From 5c9eb9b45ba7b3c0dc911328da6f0ccc703b8fff Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Wed, 26 Apr 2006 15:08:19 +0000 Subject: [PATCH] initial import of openbios--main--1.0--patch-26 git-svn-id: svn://coreboot.org/openbios/openbios-devel@1 f158a5a8-5612-0410-a976-696ce0be7e32 --- COPYING | 341 +++ Documentation/ChangeLog.arch | 1895 +++++++++++++++ Documentation/kernel/AUTHORS | 6 + Documentation/kernel/COPYING | 358 +++ Documentation/kernel/Changelog.stepan | 300 +++ Documentation/kernel/TODO | 11 + Documentation/kernel/dictformat.txt | 8 + Documentation/kernel/glossary.txt | 14 + Documentation/kernel/initializers.txt | 24 + Makefile | 59 + README | 131 ++ arch/amd64/Kconfig | 50 + arch/amd64/boot.c | 43 + arch/amd64/build.xml | 6 + arch/amd64/builtin.c | 26 + arch/amd64/console.c | 412 ++++ arch/amd64/context.c | 124 + arch/amd64/context.h | 48 + arch/amd64/defconfig | 65 + arch/amd64/elfload.c | 387 ++++ arch/amd64/init.fs | 77 + arch/amd64/ldscript | 73 + arch/amd64/lib.c | 58 + arch/amd64/linux_load.c | 647 ++++++ arch/amd64/loadfs.c | 46 + arch/amd64/loadfs.h | 7 + arch/amd64/multiboot.c | 125 + arch/amd64/multiboot.h | 96 + arch/amd64/openbios.c | 109 + arch/amd64/openbios.h | 29 + arch/amd64/plainboot.c | 22 + arch/amd64/relocate.h | 2 + arch/amd64/segment.c | 134 ++ arch/amd64/segment.h | 30 + arch/amd64/switch.S | 116 + arch/amd64/sys_info.c | 57 + arch/build.xml | 8 + arch/ia64/Kconfig | 24 + arch/ia64/build.xml | 6 + arch/ia64/defconfig | 65 + arch/ia64/init.fs | 77 + arch/ppc/Kconfig | 48 + arch/ppc/Makefile | 79 + arch/ppc/Makefile.asm | 32 + arch/ppc/briq/briq.c | 194 ++ arch/ppc/briq/briq.fs | 115 + arch/ppc/briq/briq.h | 24 + arch/ppc/briq/init.c | 129 ++ arch/ppc/briq/kernel.c | 17 + arch/ppc/briq/main.c | 145 ++ arch/ppc/briq/methods.c | 333 +++ arch/ppc/briq/tree.c | 23 + arch/ppc/briq/tree.fs | 247 ++ arch/ppc/briq/vfd.c | 42 + arch/ppc/build.xml | 217 ++ arch/ppc/defconfig | 48 + arch/ppc/kernel.c | 106 + arch/ppc/kernel.h | 41 + arch/ppc/misc.S | 76 + arch/ppc/mmutypes.h | 76 + arch/ppc/mol/console.c | 32 + arch/ppc/mol/init.c | 112 + arch/ppc/mol/kernel.c | 17 + arch/ppc/mol/main.c | 369 +++ arch/ppc/mol/methods.c | 475 ++++ arch/ppc/mol/mol.c | 166 ++ arch/ppc/mol/mol.fs | 107 + arch/ppc/mol/mol.h | 44 + arch/ppc/mol/osi-blk.c | 119 + arch/ppc/mol/osi-scsi.c | 271 +++ arch/ppc/mol/prom.c | 177 ++ arch/ppc/mol/prom.h | 47 + arch/ppc/mol/pseudodisk.c | 178 ++ arch/ppc/mol/tree.c | 165 ++ arch/ppc/mol/tree.fs | 104 + arch/ppc/ofmem.c | 705 ++++++ arch/ppc/osi.h | 170 ++ arch/ppc/osi_calls.h | 454 ++++ arch/ppc/pearpc/console.c | 47 + arch/ppc/pearpc/init.c | 137 ++ arch/ppc/pearpc/kernel.c | 17 + arch/ppc/pearpc/main.c | 145 ++ arch/ppc/pearpc/methods.c | 335 +++ arch/ppc/pearpc/pearpc.c | 206 ++ arch/ppc/pearpc/pearpc.fs | 116 + arch/ppc/pearpc/pearpc.h | 26 + arch/ppc/pearpc/tree.c | 23 + arch/ppc/pearpc/tree.fs | 247 ++ arch/ppc/pearpc/vfd.c | 42 + arch/ppc/ppc.fs | 47 + arch/ppc/start.S | 324 +++ arch/ppc/timebase.S | 35 + arch/unix/Kconfig | 18 + arch/unix/Makefile | 29 + arch/unix/blk.c | 115 + arch/unix/blk.h | 8 + arch/unix/boot.c | 80 + arch/unix/build.xml | 22 + arch/unix/gui_qt/Makefile | 42 + arch/unix/gui_qt/gui-qt.cpp | 129 ++ arch/unix/gui_qt/gui-qt.h | 44 + arch/unix/gui_qt/gui-qt.pro | 19 + arch/unix/gui_qt/logo.xpm | 132 ++ arch/unix/gui_qt/qt-main.cpp | 98 + arch/unix/plugins.c | 198 ++ arch/unix/plugins/Kconfig | 17 + arch/unix/plugins/Makefile | 13 + arch/unix/plugins/Rules.plugin | 15 + arch/unix/plugins/loader.c | 209 ++ arch/unix/plugins/plugin_pci/Makefile | 7 + arch/unix/plugins/plugin_pci/Makefile.old | 21 + arch/unix/plugins/plugin_pci/plugin_pci.c | 221 ++ arch/unix/plugins/plugin_qt/Makefile | 37 + arch/unix/plugins/plugin_qt/logo.xpm | 132 ++ arch/unix/plugins/plugin_qt/pciconfig.h | 42 + arch/unix/plugins/plugin_qt/plugin_qt.cpp | 129 ++ arch/unix/plugins/plugin_qt/plugin_qt.h | 44 + arch/unix/plugins/plugin_qt/plugin_qt.pro | 19 + arch/unix/plugins/plugin_qt/qt_main.cpp | 103 + arch/unix/plugins/plugin_qt/qt_rom.fs | 85 + arch/unix/tree.fs | 116 + arch/unix/unix.c | 517 +++++ arch/x86/Kconfig | 49 + arch/x86/boot.c | 53 + arch/x86/boot.h | 14 + arch/x86/build.xml | 99 + arch/x86/builtin.c | 25 + arch/x86/console.c | 412 ++++ arch/x86/context.c | 131 ++ arch/x86/context.h | 48 + arch/x86/defconfig | 65 + arch/x86/elfload.c | 393 ++++ arch/x86/entry.S | 300 +++ arch/x86/exception.c | 92 + arch/x86/forthload.c | 62 + arch/x86/init.fs | 78 + arch/x86/ldscript | 73 + arch/x86/lib.c | 58 + arch/x86/linux_load.c | 648 ++++++ arch/x86/loadfs.c | 46 + arch/x86/loadfs.h | 7 + arch/x86/multiboot.c | 126 + arch/x86/multiboot.h | 96 + arch/x86/openbios.c | 120 + arch/x86/openbios.h | 29 + arch/x86/plainboot.c | 22 + arch/x86/relocate.h | 2 + arch/x86/segment.c | 134 ++ arch/x86/segment.h | 30 + arch/x86/sys_info.c | 56 + arch/x86/xbox/console.c | 39 + arch/x86/xbox/methods.c | 108 + build.xml | 14 + config.xml | 1 + config/examples/amd64_config.xml | 72 + config/examples/amd64_rules.xml | 73 + config/examples/cross-ppc_config.xml | 71 + config/examples/cross-ppc_rules.xml | 97 + config/examples/x86_config.xml | 74 + config/examples/x86_rules.xml | 77 + config/scripts/archname | 16 + config/scripts/reldir | 11 + config/scripts/switch-arch | 15 + config/xml/config-c.xsl | 52 + config/xml/config-forth.xsl | 38 + config/xml/dictionary.xsl | 162 ++ config/xml/makefile.xsl | 18 + config/xml/object.xsl | 321 +++ config/xml/util.xsl | 80 + config/xml/xinclude.xsl | 43 + drivers/Kconfig | 40 + drivers/adb.c | 577 +++++ drivers/adb.fs | 33 + drivers/adb.h | 107 + drivers/build.xml | 19 + drivers/cuda.c | 297 +++ drivers/cuda.h | 20 + drivers/floppy.c | 1143 +++++++++ drivers/floppy.h | 9 + drivers/hdreg.h | 289 +++ drivers/ide.c | 1374 +++++++++++ drivers/ide.fs | 69 + drivers/ide.h | 217 ++ drivers/kbd.c | 106 + drivers/kbd.h | 104 + drivers/pci.c | 333 +++ drivers/pci.fs | 37 + drivers/pci.h | 79 + drivers/timer.c | 104 + drivers/timer.h | 60 + forth/Kconfig | 9 + forth/admin/README | 5 + forth/admin/banner.fs | 49 + forth/admin/build.xml | 25 + forth/admin/callback.fs | 10 + forth/admin/devices.fs | 356 +++ forth/admin/help.fs | 51 + forth/admin/iocontrol.fs | 139 ++ forth/admin/nvram.fs | 354 +++ forth/admin/reset.fs | 5 + forth/admin/script.fs | 17 + forth/admin/security.fs | 11 + forth/admin/selftest.fs | 50 + forth/admin/userboot.fs | 20 + forth/bootstrap/bootstrap.fs | 1500 ++++++++++++ forth/bootstrap/build.xml | 16 + forth/bootstrap/builtin.fs | 30 + forth/bootstrap/hayes.fs | 1064 +++++++++ forth/bootstrap/interpreter.fs | 174 ++ forth/bootstrap/memory.fs | 218 ++ forth/bootstrap/start.fs | 69 + forth/build.xml | 14 + forth/debugging/build.xml | 18 + forth/debugging/client.fs | 111 + forth/debugging/fcode.fs | 31 + forth/debugging/firmware.fs | 83 + forth/debugging/see.fs | 114 + forth/device/README.device | 23 + forth/device/build.xml | 31 + forth/device/builtin.fs | 32 + forth/device/device.fs | 191 ++ forth/device/display.fs | 367 +++ forth/device/extra.fs | 103 + forth/device/fcode.fs | 521 +++++ forth/device/feval.fs | 82 + forth/device/font.fs | 13 + forth/device/logo.fs | 99 + forth/device/missing | 39 + forth/device/other.fs | 179 ++ forth/device/package.fs | 256 ++ forth/device/pathres.fs | 517 +++++ forth/device/preof.fs | 50 + forth/device/property.fs | 324 +++ forth/device/romfont.bin | Bin 0 -> 4096 bytes forth/device/structures.fs | 54 + forth/device/table.fs | 428 ++++ forth/device/terminal.fs | 256 ++ forth/device/tree.fs | 72 + forth/lib/build.xml | 20 + forth/lib/creation.fs | 52 + forth/lib/lists.fs | 26 + forth/lib/preinclude.fs | 11 + forth/lib/preprocessor.fs | 75 + forth/lib/split.fs | 49 + forth/lib/string.fs | 127 + forth/lib/vocabulary.fs | 155 ++ forth/packages/Kconfig | 17 + forth/packages/README | 12 + forth/packages/build.xml | 20 + forth/packages/deblocker.fs | 64 + forth/packages/disklabel.fs | 23 + forth/packages/obp-tftp.fs | 23 + forth/packages/packages.fs | 18 + forth/packages/terminal-emulator.fs | 25 + forth/system/build.xml | 16 + forth/system/ciface.fs | 318 +++ forth/system/main.fs | 60 + forth/testsuite/README | 8 + forth/testsuite/build.xml | 16 + forth/testsuite/fract.fs | 36 + forth/testsuite/framebuffer-test.fs | 13 + forth/testsuite/memory-testsuite.fs | 106 + forth/testsuite/splitfunc-testsuite.fs | 38 + forth/util/apic.fs | 62 + forth/util/build.xml | 19 + forth/util/pci.fs | 127 + forth/util/util.fs | 95 + fs/build.xml | 13 + fs/grubfs/Kconfig | 84 + fs/grubfs/build.xml | 17 + fs/grubfs/debug.h | 3 + fs/grubfs/defs.h | 94 + fs/grubfs/dir.h | 147 ++ fs/grubfs/disk_inode.h | 110 + fs/grubfs/disk_inode_ffs.h | 101 + fs/grubfs/fat.h | 100 + fs/grubfs/filesys.h | 302 +++ fs/grubfs/fs.h | 457 ++++ fs/grubfs/fsys_affs.c | 702 ++++++ fs/grubfs/fsys_ext2fs.c | 804 +++++++ fs/grubfs/fsys_fat.c | 476 ++++ fs/grubfs/fsys_ffs.c | 310 +++ fs/grubfs/fsys_iso9660.c | 336 +++ fs/grubfs/fsys_jfs.c | 403 ++++ fs/grubfs/fsys_minix.c | 534 +++++ fs/grubfs/fsys_ntfs.c | 1254 ++++++++++ fs/grubfs/fsys_reiserfs.c | 1219 ++++++++++ fs/grubfs/fsys_ufs.c | 391 ++++ fs/grubfs/fsys_vstafs.c | 254 ++ fs/grubfs/fsys_xfs.c | 632 +++++ fs/grubfs/glue.h | 48 + fs/grubfs/grubfs_fs.c | 310 +++ fs/grubfs/iso9660.h | 168 ++ fs/grubfs/jfs.h | 604 +++++ fs/grubfs/shared.h | 3 + fs/grubfs/ufs_dinode.h | 191 ++ fs/grubfs/ufs_fs.h | 635 +++++ fs/grubfs/vstafs.h | 88 + fs/grubfs/xfs.h | 546 +++++ fs/hfs/block.c | 612 +++++ fs/hfs/btree.c | 229 ++ fs/hfs/build.xml | 15 + fs/hfs/data.c | 475 ++++ fs/hfs/file.c | 191 ++ fs/hfs/hfs.c | 737 ++++++ fs/hfs/hfs_fs.c | 324 +++ fs/hfs/include/apple.h | 272 +++ fs/hfs/include/block.h | 40 + fs/hfs/include/btree.h | 33 + fs/hfs/include/data.h | 58 + fs/hfs/include/file.h | 45 + fs/hfs/include/hfs.h | 178 ++ fs/hfs/include/libhfs.h | 226 ++ fs/hfs/include/low.h | 44 + fs/hfs/include/medium.h | 42 + fs/hfs/include/node.h | 34 + fs/hfs/include/record.h | 47 + fs/hfs/include/volume.h | 68 + fs/hfs/low.c | 157 ++ fs/hfs/medium.c | 84 + fs/hfs/node.c | 59 + fs/hfs/record.c | 552 +++++ fs/hfs/volume.c | 592 +++++ fs/hfs_mdb.h | 110 + fs/hfsplus/blockiter.c | 141 ++ fs/hfsplus/btree.c | 376 +++ fs/hfsplus/build.xml | 11 + fs/hfsplus/hfsp_fs.c | 397 ++++ fs/hfsplus/include/apple.h | 111 + fs/hfsplus/include/blockiter.h | 60 + fs/hfsplus/include/btree.h | 50 + fs/hfsplus/include/hfs.h | 32 + fs/hfsplus/include/hfsp.h | 305 +++ fs/hfsplus/include/hfstime.h | 34 + fs/hfsplus/include/libhfsp.h | 204 ++ fs/hfsplus/include/record.h | 81 + fs/hfsplus/include/swab.h | 44 + fs/hfsplus/include/unicode.h | 28 + fs/hfsplus/include/volume.h | 84 + fs/hfsplus/libhfsp.c | 28 + fs/hfsplus/record.c | 756 ++++++ fs/hfsplus/unicode.c | 508 ++++ fs/hfsplus/volume.c | 289 +++ fs/ioglue.c | 86 + fs/os.h | 50 + include/amd64/elf.h | 6 + include/amd64/io.h | 68 + include/amd64/types.h | 43 + include/elf_boot.h | 104 + include/ia64/elf.h | 5 + include/ia64/io.h | 59 + include/ia64/types.h | 44 + include/ipchecksum.h | 7 + include/libc/byteorder.h | 42 + include/libc/diskio.h | 33 + include/libc/stdlib.h | 26 + include/libc/string.h | 99 + include/libc/vsprintf.h | 24 + include/mconfig.h | 79 + include/ofmem.h | 38 + include/openbios/asm.m4 | 138 ++ include/openbios/bindings.h | 137 ++ include/openbios/config.h | 77 + include/openbios/drivers.h | 20 + include/openbios/elf.h | 227 ++ include/openbios/elfload.h | 29 + include/openbios/fs.h | 77 + include/openbios/kernel.h | 47 + include/openbios/nvram.h | 27 + include/openbios/of.h | 22 + include/openbios/stack.h | 90 + include/openbios/sysinclude.h | 20 + include/ppc/asmdefs.h | 371 +++ include/ppc/elf.h | 5 + include/ppc/io.h | 165 ++ include/ppc/pci.h | 84 + include/ppc/processor.h | 404 ++++ include/ppc/types.h | 63 + include/sys_info.h | 34 + include/unix/plugin_pci.h | 25 + include/unix/plugins.h | 31 + include/x86/elf.h | 5 + include/x86/io.h | 70 + include/x86/pci.h | 66 + include/x86/types.h | 44 + kernel/Kconfig | 89 + kernel/README | 93 + kernel/bootstrap.c | 1111 +++++++++ kernel/build.xml | 16 + kernel/cross.h | 143 ++ kernel/dict.c | 183 ++ kernel/forth.c | 917 ++++++++ kernel/include/dict.h | 48 + kernel/internal.c | 365 +++ kernel/primitives.c | 148 ++ kernel/stack.c | 42 + libc/build.xml | 12 + libc/ctype.c | 36 + libc/diskio.c | 215 ++ libc/extra.c | 26 + libc/misc.c | 77 + libc/string.c | 515 +++++ libc/vsprintf.c | 311 +++ modules/Kconfig | 97 + modules/bindings.c | 520 +++++ modules/build.xml | 27 + modules/clib.fs | 37 + modules/client.c | 114 + modules/cmdline.c | 368 +++ modules/console.c | 208 ++ modules/deblocker.c | 214 ++ modules/disk-label.c | 211 ++ modules/elfload.c | 129 ++ modules/elfnote.c | 151 ++ modules/filesystems.c | 288 +++ modules/font_8x8.c | 2573 +++++++++++++++++++++ modules/helpers.fs | 35 + modules/init.c | 42 + modules/ipchecksum.c | 55 + modules/linuxbios.c | 129 ++ modules/linuxbios.h | 181 ++ modules/mac-parts.c | 124 + modules/mac-parts.h | 72 + modules/modules.h | 27 + modules/nvram.c | 297 +++ modules/pc-parts.c | 205 ++ modules/support.fs | 124 + modules/video.c | 290 +++ rules.xml | 1 + toke/COPYING | 341 +++ toke/ChangeLog | 141 ++ toke/Makefile | 72 + toke/README | 212 ++ toke/Rules.make | 17 + toke/build.xml | 13 + toke/dictionary.c | 574 +++++ toke/dictionary.h | 104 + toke/emit.c | 306 +++ toke/emit.h | 44 + toke/examples/case.fs | 14 + toke/examples/date.fs | 9 + toke/examples/display.fs | 33 + toke/examples/fcdisp.fs | 72 + toke/examples/fract.fs | 32 + toke/examples/pciexample.fs | 10 + toke/examples/primes.fs | 68 + toke/examples/scsi-sample/README.sample | 8 + toke/examples/scsi-sample/hacom.fs | 330 +++ toke/examples/scsi-sample/overall.fs | 42 + toke/examples/scsi-sample/scsicom.fs | 72 + toke/examples/scsi-sample/scsidisk.fs | 156 ++ toke/examples/scsi-sample/scsiha.fs | 200 ++ toke/examples/scsi-sample/scsitape.fs | 296 +++ toke/examples/simple.fs | 18 + toke/examples/version1.fs | 18 + toke/examples/world.fs | 15 + toke/macros.c | 138 ++ toke/scanner.c | 1169 ++++++++++ toke/stack.c | 116 + toke/stack.h | 46 + toke/stream.c | 165 ++ toke/stream.h | 38 + toke/toke.c | 148 ++ toke/toke.h | 53 + utils/README | 52 + utils/detok/COPYING | 341 +++ utils/detok/ChangeLog | 75 + utils/detok/Makefile | 68 + utils/detok/README | 80 + utils/detok/Rules.make | 17 + utils/detok/decode.c | 332 +++ utils/detok/detok.c | 158 ++ utils/detok/detok.h | 33 + utils/detok/dictionary.c | 460 ++++ utils/detok/stream.c | 180 ++ utils/detok/stream.h | 39 + utils/devbios/COPYING | 353 +++ utils/devbios/CREDITS | 4 + utils/devbios/ChangeLog | 275 +++ utils/devbios/Makefile | 22 + utils/devbios/Makefile.24 | 81 + utils/devbios/README.bios | 237 ++ utils/devbios/ToDo | 33 + utils/devbios/bios.h | 38 + utils/devbios/bios_core.c | 198 ++ utils/devbios/comp.c | 47 + utils/devbios/filesystem.c | 300 +++ utils/devbios/flashchips.c | 313 +++ utils/devbios/flashchips.h | 81 + utils/devbios/pcisets.c | 630 +++++ utils/devbios/pcisets.h | 45 + utils/devbios/procfs.c | 162 ++ utils/devbios/programming.c | 539 +++++ utils/devbios/programming.h | 73 + utils/dist/debian/changelog | 6 + utils/dist/debian/control | 16 + utils/dist/debian/packages | 45 + utils/dist/debian/rules | 189 ++ utils/dist/openbios.spec | 61 + utils/fccc/COPYING | 280 +++ utils/fccc/include/fccc-tools.h | 12 + utils/fccc/include/fccc.h | 44 + utils/fccc/include/linklist.h | 24 + utils/fccc/include/parserfunctions.h | 10 + utils/fccc/include/symboltable.h | 24 + utils/fccc/src/Makefile | 35 + utils/fccc/src/fccc-tools.c | 88 + utils/fccc/src/fccc.lex | 203 ++ utils/fccc/src/fccc.y | 562 +++++ utils/fccc/src/linklist.c | 45 + utils/fccc/src/plain_ass.c | 41 + utils/fccc/src/symboltable.c | 105 + utils/fccc/test/test1.c | 14 + utils/ofclient/Makefile | 14 + utils/ofclient/README | 4 + utils/ofclient/endian.h | 18 + utils/ofclient/of1275.c | 451 ++++ utils/ofclient/of1275.h | 437 ++++ utils/ofclient/of1275_io.c | 51 + utils/ofclient/ofclient.c | 9 + utils/romheaders/Makefile | 40 + utils/romheaders/romheaders.c | 291 +++ 522 files changed, 83237 insertions(+) create mode 100644 COPYING create mode 100644 Documentation/ChangeLog.arch create mode 100644 Documentation/kernel/AUTHORS create mode 100644 Documentation/kernel/COPYING create mode 100644 Documentation/kernel/Changelog.stepan create mode 100644 Documentation/kernel/TODO create mode 100644 Documentation/kernel/dictformat.txt create mode 100644 Documentation/kernel/glossary.txt create mode 100644 Documentation/kernel/initializers.txt create mode 100644 Makefile create mode 100644 README create mode 100644 arch/amd64/Kconfig create mode 100644 arch/amd64/boot.c create mode 100644 arch/amd64/build.xml create mode 100644 arch/amd64/builtin.c create mode 100644 arch/amd64/console.c create mode 100644 arch/amd64/context.c create mode 100644 arch/amd64/context.h create mode 100644 arch/amd64/defconfig create mode 100644 arch/amd64/elfload.c create mode 100644 arch/amd64/init.fs create mode 100644 arch/amd64/ldscript create mode 100644 arch/amd64/lib.c create mode 100644 arch/amd64/linux_load.c create mode 100644 arch/amd64/loadfs.c create mode 100644 arch/amd64/loadfs.h create mode 100644 arch/amd64/multiboot.c create mode 100644 arch/amd64/multiboot.h create mode 100644 arch/amd64/openbios.c create mode 100644 arch/amd64/openbios.h create mode 100644 arch/amd64/plainboot.c create mode 100644 arch/amd64/relocate.h create mode 100644 arch/amd64/segment.c create mode 100644 arch/amd64/segment.h create mode 100644 arch/amd64/switch.S create mode 100644 arch/amd64/sys_info.c create mode 100644 arch/build.xml create mode 100644 arch/ia64/Kconfig create mode 100644 arch/ia64/build.xml create mode 100644 arch/ia64/defconfig create mode 100644 arch/ia64/init.fs create mode 100644 arch/ppc/Kconfig create mode 100644 arch/ppc/Makefile create mode 100644 arch/ppc/Makefile.asm create mode 100644 arch/ppc/briq/briq.c create mode 100644 arch/ppc/briq/briq.fs create mode 100644 arch/ppc/briq/briq.h create mode 100644 arch/ppc/briq/init.c create mode 100644 arch/ppc/briq/kernel.c create mode 100644 arch/ppc/briq/main.c create mode 100644 arch/ppc/briq/methods.c create mode 100644 arch/ppc/briq/tree.c create mode 100644 arch/ppc/briq/tree.fs create mode 100644 arch/ppc/briq/vfd.c create mode 100644 arch/ppc/build.xml create mode 100644 arch/ppc/defconfig create mode 100644 arch/ppc/kernel.c create mode 100644 arch/ppc/kernel.h create mode 100644 arch/ppc/misc.S create mode 100644 arch/ppc/mmutypes.h create mode 100644 arch/ppc/mol/console.c create mode 100644 arch/ppc/mol/init.c create mode 100644 arch/ppc/mol/kernel.c create mode 100644 arch/ppc/mol/main.c create mode 100644 arch/ppc/mol/methods.c create mode 100644 arch/ppc/mol/mol.c create mode 100644 arch/ppc/mol/mol.fs create mode 100644 arch/ppc/mol/mol.h create mode 100644 arch/ppc/mol/osi-blk.c create mode 100644 arch/ppc/mol/osi-scsi.c create mode 100644 arch/ppc/mol/prom.c create mode 100644 arch/ppc/mol/prom.h create mode 100644 arch/ppc/mol/pseudodisk.c create mode 100644 arch/ppc/mol/tree.c create mode 100644 arch/ppc/mol/tree.fs create mode 100644 arch/ppc/ofmem.c create mode 100644 arch/ppc/osi.h create mode 100644 arch/ppc/osi_calls.h create mode 100644 arch/ppc/pearpc/console.c create mode 100644 arch/ppc/pearpc/init.c create mode 100644 arch/ppc/pearpc/kernel.c create mode 100644 arch/ppc/pearpc/main.c create mode 100644 arch/ppc/pearpc/methods.c create mode 100644 arch/ppc/pearpc/pearpc.c create mode 100644 arch/ppc/pearpc/pearpc.fs create mode 100644 arch/ppc/pearpc/pearpc.h create mode 100644 arch/ppc/pearpc/tree.c create mode 100644 arch/ppc/pearpc/tree.fs create mode 100644 arch/ppc/pearpc/vfd.c create mode 100644 arch/ppc/ppc.fs create mode 100644 arch/ppc/start.S create mode 100644 arch/ppc/timebase.S create mode 100644 arch/unix/Kconfig create mode 100644 arch/unix/Makefile create mode 100644 arch/unix/blk.c create mode 100644 arch/unix/blk.h create mode 100644 arch/unix/boot.c create mode 100644 arch/unix/build.xml create mode 100644 arch/unix/gui_qt/Makefile create mode 100644 arch/unix/gui_qt/gui-qt.cpp create mode 100644 arch/unix/gui_qt/gui-qt.h create mode 100644 arch/unix/gui_qt/gui-qt.pro create mode 100644 arch/unix/gui_qt/logo.xpm create mode 100644 arch/unix/gui_qt/qt-main.cpp create mode 100644 arch/unix/plugins.c create mode 100644 arch/unix/plugins/Kconfig create mode 100644 arch/unix/plugins/Makefile create mode 100644 arch/unix/plugins/Rules.plugin create mode 100644 arch/unix/plugins/loader.c create mode 100644 arch/unix/plugins/plugin_pci/Makefile create mode 100644 arch/unix/plugins/plugin_pci/Makefile.old create mode 100644 arch/unix/plugins/plugin_pci/plugin_pci.c create mode 100644 arch/unix/plugins/plugin_qt/Makefile create mode 100644 arch/unix/plugins/plugin_qt/logo.xpm create mode 100644 arch/unix/plugins/plugin_qt/pciconfig.h create mode 100644 arch/unix/plugins/plugin_qt/plugin_qt.cpp create mode 100644 arch/unix/plugins/plugin_qt/plugin_qt.h create mode 100644 arch/unix/plugins/plugin_qt/plugin_qt.pro create mode 100644 arch/unix/plugins/plugin_qt/qt_main.cpp create mode 100644 arch/unix/plugins/plugin_qt/qt_rom.fs create mode 100644 arch/unix/tree.fs create mode 100644 arch/unix/unix.c create mode 100644 arch/x86/Kconfig create mode 100644 arch/x86/boot.c create mode 100644 arch/x86/boot.h create mode 100644 arch/x86/build.xml create mode 100644 arch/x86/builtin.c create mode 100644 arch/x86/console.c create mode 100644 arch/x86/context.c create mode 100644 arch/x86/context.h create mode 100644 arch/x86/defconfig create mode 100644 arch/x86/elfload.c create mode 100644 arch/x86/entry.S create mode 100644 arch/x86/exception.c create mode 100644 arch/x86/forthload.c create mode 100644 arch/x86/init.fs create mode 100644 arch/x86/ldscript create mode 100644 arch/x86/lib.c create mode 100644 arch/x86/linux_load.c create mode 100644 arch/x86/loadfs.c create mode 100644 arch/x86/loadfs.h create mode 100644 arch/x86/multiboot.c create mode 100644 arch/x86/multiboot.h create mode 100644 arch/x86/openbios.c create mode 100644 arch/x86/openbios.h create mode 100644 arch/x86/plainboot.c create mode 100644 arch/x86/relocate.h create mode 100644 arch/x86/segment.c create mode 100644 arch/x86/segment.h create mode 100644 arch/x86/sys_info.c create mode 100644 arch/x86/xbox/console.c create mode 100644 arch/x86/xbox/methods.c create mode 100644 build.xml create mode 120000 config.xml create mode 100644 config/examples/amd64_config.xml create mode 100644 config/examples/amd64_rules.xml create mode 100644 config/examples/cross-ppc_config.xml create mode 100644 config/examples/cross-ppc_rules.xml create mode 100644 config/examples/x86_config.xml create mode 100644 config/examples/x86_rules.xml create mode 100755 config/scripts/archname create mode 100755 config/scripts/reldir create mode 100755 config/scripts/switch-arch create mode 100644 config/xml/config-c.xsl create mode 100644 config/xml/config-forth.xsl create mode 100644 config/xml/dictionary.xsl create mode 100644 config/xml/makefile.xsl create mode 100644 config/xml/object.xsl create mode 100644 config/xml/util.xsl create mode 100644 config/xml/xinclude.xsl create mode 100644 drivers/Kconfig create mode 100644 drivers/adb.c create mode 100644 drivers/adb.fs create mode 100644 drivers/adb.h create mode 100644 drivers/build.xml create mode 100644 drivers/cuda.c create mode 100644 drivers/cuda.h create mode 100644 drivers/floppy.c create mode 100644 drivers/floppy.h create mode 100644 drivers/hdreg.h create mode 100644 drivers/ide.c create mode 100644 drivers/ide.fs create mode 100644 drivers/ide.h create mode 100644 drivers/kbd.c create mode 100644 drivers/kbd.h create mode 100644 drivers/pci.c create mode 100644 drivers/pci.fs create mode 100644 drivers/pci.h create mode 100644 drivers/timer.c create mode 100644 drivers/timer.h create mode 100644 forth/Kconfig create mode 100644 forth/admin/README create mode 100644 forth/admin/banner.fs create mode 100644 forth/admin/build.xml create mode 100644 forth/admin/callback.fs create mode 100644 forth/admin/devices.fs create mode 100644 forth/admin/help.fs create mode 100644 forth/admin/iocontrol.fs create mode 100644 forth/admin/nvram.fs create mode 100644 forth/admin/reset.fs create mode 100644 forth/admin/script.fs create mode 100644 forth/admin/security.fs create mode 100644 forth/admin/selftest.fs create mode 100644 forth/admin/userboot.fs create mode 100644 forth/bootstrap/bootstrap.fs create mode 100644 forth/bootstrap/build.xml create mode 100644 forth/bootstrap/builtin.fs create mode 100644 forth/bootstrap/hayes.fs create mode 100644 forth/bootstrap/interpreter.fs create mode 100644 forth/bootstrap/memory.fs create mode 100644 forth/bootstrap/start.fs create mode 100644 forth/build.xml create mode 100644 forth/debugging/build.xml create mode 100644 forth/debugging/client.fs create mode 100644 forth/debugging/fcode.fs create mode 100644 forth/debugging/firmware.fs create mode 100644 forth/debugging/see.fs create mode 100644 forth/device/README.device create mode 100644 forth/device/build.xml create mode 100644 forth/device/builtin.fs create mode 100644 forth/device/device.fs create mode 100644 forth/device/display.fs create mode 100644 forth/device/extra.fs create mode 100644 forth/device/fcode.fs create mode 100644 forth/device/feval.fs create mode 100644 forth/device/font.fs create mode 100644 forth/device/logo.fs create mode 100644 forth/device/missing create mode 100644 forth/device/other.fs create mode 100644 forth/device/package.fs create mode 100644 forth/device/pathres.fs create mode 100644 forth/device/preof.fs create mode 100644 forth/device/property.fs create mode 100644 forth/device/romfont.bin create mode 100644 forth/device/structures.fs create mode 100644 forth/device/table.fs create mode 100644 forth/device/terminal.fs create mode 100644 forth/device/tree.fs create mode 100644 forth/lib/build.xml create mode 100644 forth/lib/creation.fs create mode 100644 forth/lib/lists.fs create mode 100644 forth/lib/preinclude.fs create mode 100644 forth/lib/preprocessor.fs create mode 100644 forth/lib/split.fs create mode 100644 forth/lib/string.fs create mode 100644 forth/lib/vocabulary.fs create mode 100644 forth/packages/Kconfig create mode 100644 forth/packages/README create mode 100644 forth/packages/build.xml create mode 100644 forth/packages/deblocker.fs create mode 100644 forth/packages/disklabel.fs create mode 100644 forth/packages/obp-tftp.fs create mode 100644 forth/packages/packages.fs create mode 100644 forth/packages/terminal-emulator.fs create mode 100644 forth/system/build.xml create mode 100644 forth/system/ciface.fs create mode 100644 forth/system/main.fs create mode 100644 forth/testsuite/README create mode 100644 forth/testsuite/build.xml create mode 100644 forth/testsuite/fract.fs create mode 100644 forth/testsuite/framebuffer-test.fs create mode 100644 forth/testsuite/memory-testsuite.fs create mode 100644 forth/testsuite/splitfunc-testsuite.fs create mode 100644 forth/util/apic.fs create mode 100644 forth/util/build.xml create mode 100644 forth/util/pci.fs create mode 100644 forth/util/util.fs create mode 100644 fs/build.xml create mode 100644 fs/grubfs/Kconfig create mode 100644 fs/grubfs/build.xml create mode 100644 fs/grubfs/debug.h create mode 100644 fs/grubfs/defs.h create mode 100644 fs/grubfs/dir.h create mode 100644 fs/grubfs/disk_inode.h create mode 100644 fs/grubfs/disk_inode_ffs.h create mode 100644 fs/grubfs/fat.h create mode 100644 fs/grubfs/filesys.h create mode 100644 fs/grubfs/fs.h create mode 100644 fs/grubfs/fsys_affs.c create mode 100644 fs/grubfs/fsys_ext2fs.c create mode 100644 fs/grubfs/fsys_fat.c create mode 100644 fs/grubfs/fsys_ffs.c create mode 100644 fs/grubfs/fsys_iso9660.c create mode 100644 fs/grubfs/fsys_jfs.c create mode 100644 fs/grubfs/fsys_minix.c create mode 100644 fs/grubfs/fsys_ntfs.c create mode 100644 fs/grubfs/fsys_reiserfs.c create mode 100644 fs/grubfs/fsys_ufs.c create mode 100644 fs/grubfs/fsys_vstafs.c create mode 100644 fs/grubfs/fsys_xfs.c create mode 100644 fs/grubfs/glue.h create mode 100644 fs/grubfs/grubfs_fs.c create mode 100644 fs/grubfs/iso9660.h create mode 100644 fs/grubfs/jfs.h create mode 100644 fs/grubfs/shared.h create mode 100644 fs/grubfs/ufs_dinode.h create mode 100644 fs/grubfs/ufs_fs.h create mode 100644 fs/grubfs/vstafs.h create mode 100644 fs/grubfs/xfs.h create mode 100644 fs/hfs/block.c create mode 100644 fs/hfs/btree.c create mode 100644 fs/hfs/build.xml create mode 100644 fs/hfs/data.c create mode 100644 fs/hfs/file.c create mode 100644 fs/hfs/hfs.c create mode 100644 fs/hfs/hfs_fs.c create mode 100644 fs/hfs/include/apple.h create mode 100644 fs/hfs/include/block.h create mode 100644 fs/hfs/include/btree.h create mode 100644 fs/hfs/include/data.h create mode 100644 fs/hfs/include/file.h create mode 100644 fs/hfs/include/hfs.h create mode 100644 fs/hfs/include/libhfs.h create mode 100644 fs/hfs/include/low.h create mode 100644 fs/hfs/include/medium.h create mode 100644 fs/hfs/include/node.h create mode 100644 fs/hfs/include/record.h create mode 100644 fs/hfs/include/volume.h create mode 100644 fs/hfs/low.c create mode 100644 fs/hfs/medium.c create mode 100644 fs/hfs/node.c create mode 100644 fs/hfs/record.c create mode 100644 fs/hfs/volume.c create mode 100644 fs/hfs_mdb.h create mode 100644 fs/hfsplus/blockiter.c create mode 100644 fs/hfsplus/btree.c create mode 100644 fs/hfsplus/build.xml create mode 100644 fs/hfsplus/hfsp_fs.c create mode 100644 fs/hfsplus/include/apple.h create mode 100644 fs/hfsplus/include/blockiter.h create mode 100644 fs/hfsplus/include/btree.h create mode 100644 fs/hfsplus/include/hfs.h create mode 100644 fs/hfsplus/include/hfsp.h create mode 100644 fs/hfsplus/include/hfstime.h create mode 100644 fs/hfsplus/include/libhfsp.h create mode 100644 fs/hfsplus/include/record.h create mode 100644 fs/hfsplus/include/swab.h create mode 100644 fs/hfsplus/include/unicode.h create mode 100644 fs/hfsplus/include/volume.h create mode 100644 fs/hfsplus/libhfsp.c create mode 100644 fs/hfsplus/record.c create mode 100644 fs/hfsplus/unicode.c create mode 100644 fs/hfsplus/volume.c create mode 100644 fs/ioglue.c create mode 100644 fs/os.h create mode 100644 include/amd64/elf.h create mode 100644 include/amd64/io.h create mode 100644 include/amd64/types.h create mode 100644 include/elf_boot.h create mode 100644 include/ia64/elf.h create mode 100644 include/ia64/io.h create mode 100644 include/ia64/types.h create mode 100644 include/ipchecksum.h create mode 100644 include/libc/byteorder.h create mode 100644 include/libc/diskio.h create mode 100644 include/libc/stdlib.h create mode 100644 include/libc/string.h create mode 100644 include/libc/vsprintf.h create mode 100644 include/mconfig.h create mode 100644 include/ofmem.h create mode 100644 include/openbios/asm.m4 create mode 100644 include/openbios/bindings.h create mode 100644 include/openbios/config.h create mode 100644 include/openbios/drivers.h create mode 100644 include/openbios/elf.h create mode 100644 include/openbios/elfload.h create mode 100644 include/openbios/fs.h create mode 100644 include/openbios/kernel.h create mode 100644 include/openbios/nvram.h create mode 100644 include/openbios/of.h create mode 100644 include/openbios/stack.h create mode 100644 include/openbios/sysinclude.h create mode 100644 include/ppc/asmdefs.h create mode 100644 include/ppc/elf.h create mode 100644 include/ppc/io.h create mode 100644 include/ppc/pci.h create mode 100644 include/ppc/processor.h create mode 100644 include/ppc/types.h create mode 100644 include/sys_info.h create mode 100644 include/unix/plugin_pci.h create mode 100644 include/unix/plugins.h create mode 100644 include/x86/elf.h create mode 100644 include/x86/io.h create mode 100644 include/x86/pci.h create mode 100644 include/x86/types.h create mode 100644 kernel/Kconfig create mode 100644 kernel/README create mode 100644 kernel/bootstrap.c create mode 100644 kernel/build.xml create mode 100644 kernel/cross.h create mode 100644 kernel/dict.c create mode 100644 kernel/forth.c create mode 100644 kernel/include/dict.h create mode 100644 kernel/internal.c create mode 100644 kernel/primitives.c create mode 100644 kernel/stack.c create mode 100644 libc/build.xml create mode 100644 libc/ctype.c create mode 100644 libc/diskio.c create mode 100644 libc/extra.c create mode 100644 libc/misc.c create mode 100644 libc/string.c create mode 100644 libc/vsprintf.c create mode 100644 modules/Kconfig create mode 100644 modules/bindings.c create mode 100644 modules/build.xml create mode 100644 modules/clib.fs create mode 100644 modules/client.c create mode 100644 modules/cmdline.c create mode 100644 modules/console.c create mode 100644 modules/deblocker.c create mode 100644 modules/disk-label.c create mode 100644 modules/elfload.c create mode 100644 modules/elfnote.c create mode 100644 modules/filesystems.c create mode 100644 modules/font_8x8.c create mode 100644 modules/helpers.fs create mode 100644 modules/init.c create mode 100644 modules/ipchecksum.c create mode 100644 modules/linuxbios.c create mode 100644 modules/linuxbios.h create mode 100644 modules/mac-parts.c create mode 100644 modules/mac-parts.h create mode 100644 modules/modules.h create mode 100644 modules/nvram.c create mode 100644 modules/pc-parts.c create mode 100644 modules/support.fs create mode 100644 modules/video.c create mode 120000 rules.xml create mode 100644 toke/COPYING create mode 100644 toke/ChangeLog create mode 100644 toke/Makefile create mode 100644 toke/README create mode 100644 toke/Rules.make create mode 100644 toke/build.xml create mode 100644 toke/dictionary.c create mode 100644 toke/dictionary.h create mode 100644 toke/emit.c create mode 100644 toke/emit.h create mode 100644 toke/examples/case.fs create mode 100644 toke/examples/date.fs create mode 100644 toke/examples/display.fs create mode 100644 toke/examples/fcdisp.fs create mode 100644 toke/examples/fract.fs create mode 100644 toke/examples/pciexample.fs create mode 100644 toke/examples/primes.fs create mode 100644 toke/examples/scsi-sample/README.sample create mode 100644 toke/examples/scsi-sample/hacom.fs create mode 100644 toke/examples/scsi-sample/overall.fs create mode 100644 toke/examples/scsi-sample/scsicom.fs create mode 100644 toke/examples/scsi-sample/scsidisk.fs create mode 100644 toke/examples/scsi-sample/scsiha.fs create mode 100644 toke/examples/scsi-sample/scsitape.fs create mode 100644 toke/examples/simple.fs create mode 100644 toke/examples/version1.fs create mode 100644 toke/examples/world.fs create mode 100644 toke/macros.c create mode 100644 toke/scanner.c create mode 100644 toke/stack.c create mode 100644 toke/stack.h create mode 100644 toke/stream.c create mode 100644 toke/stream.h create mode 100644 toke/toke.c create mode 100644 toke/toke.h create mode 100644 utils/README create mode 100644 utils/detok/COPYING create mode 100644 utils/detok/ChangeLog create mode 100644 utils/detok/Makefile create mode 100644 utils/detok/README create mode 100644 utils/detok/Rules.make create mode 100644 utils/detok/decode.c create mode 100644 utils/detok/detok.c create mode 100644 utils/detok/detok.h create mode 100644 utils/detok/dictionary.c create mode 100644 utils/detok/stream.c create mode 100644 utils/detok/stream.h create mode 100644 utils/devbios/COPYING create mode 100644 utils/devbios/CREDITS create mode 100644 utils/devbios/ChangeLog create mode 100644 utils/devbios/Makefile create mode 100644 utils/devbios/Makefile.24 create mode 100644 utils/devbios/README.bios create mode 100644 utils/devbios/ToDo create mode 100644 utils/devbios/bios.h create mode 100644 utils/devbios/bios_core.c create mode 100644 utils/devbios/comp.c create mode 100644 utils/devbios/filesystem.c create mode 100644 utils/devbios/flashchips.c create mode 100644 utils/devbios/flashchips.h create mode 100644 utils/devbios/pcisets.c create mode 100644 utils/devbios/pcisets.h create mode 100644 utils/devbios/procfs.c create mode 100644 utils/devbios/programming.c create mode 100644 utils/devbios/programming.h create mode 100644 utils/dist/debian/changelog create mode 100644 utils/dist/debian/control create mode 100644 utils/dist/debian/packages create mode 100755 utils/dist/debian/rules create mode 100644 utils/dist/openbios.spec create mode 100644 utils/fccc/COPYING create mode 100644 utils/fccc/include/fccc-tools.h create mode 100644 utils/fccc/include/fccc.h create mode 100644 utils/fccc/include/linklist.h create mode 100644 utils/fccc/include/parserfunctions.h create mode 100644 utils/fccc/include/symboltable.h create mode 100644 utils/fccc/src/Makefile create mode 100644 utils/fccc/src/fccc-tools.c create mode 100644 utils/fccc/src/fccc.lex create mode 100644 utils/fccc/src/fccc.y create mode 100644 utils/fccc/src/linklist.c create mode 100644 utils/fccc/src/plain_ass.c create mode 100644 utils/fccc/src/symboltable.c create mode 100644 utils/fccc/test/test1.c create mode 100644 utils/ofclient/Makefile create mode 100644 utils/ofclient/README create mode 100644 utils/ofclient/endian.h create mode 100644 utils/ofclient/of1275.c create mode 100644 utils/ofclient/of1275.h create mode 100644 utils/ofclient/of1275_io.c create mode 100644 utils/ofclient/ofclient.c create mode 100644 utils/romheaders/Makefile create mode 100644 utils/romheaders/romheaders.c diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..8a6932a --- /dev/null +++ b/COPYING @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Documentation/ChangeLog.arch b/Documentation/ChangeLog.arch new file mode 100644 index 0000000..8213b28 --- /dev/null +++ b/Documentation/ChangeLog.arch @@ -0,0 +1,1895 @@ +# do not edit -- automatically generated by arch changelog +# arch-tag: automatic-ChangeLog--stepan@openbios.org--devel/openbios--main--1.0 +# + +2006-04-26 11:52:05 GMT Stefan Reinauer patch-26 + + Summary: + small gcc4 changes + Revision: + openbios--main--1.0--patch-26 + + lvalue stuff + + + modified files: + Documentation/ChangeLog.arch config/examples/x86_config.xml + kernel/bootstrap.c kernel/dict.c + + +2006-02-22 17:01:41 GMT Stefan Reinauer patch-25 + + Summary: + make romheaders work on non linux systems + Revision: + openbios--main--1.0--patch-25 + + removes endian dependency and some signed/unsigned comparisons + + + + modified files: + Documentation/ChangeLog.arch utils/romheaders/Makefile + utils/romheaders/romheaders.c + + +2005-10-15 16:01:47 GMT Stefan Reinauer patch-24 + + Summary: + toke fix: hex string handling + Revision: + openbios--main--1.0--patch-24 + + This revision fixes a bug in toke when creating hex definitions within strings. + It also contains a little documentation update. + + + removed files: + toke/.arch-ids/TODO.id toke/TODO + + modified files: + Documentation/ChangeLog.arch toke/ChangeLog toke/README + toke/scanner.c toke/toke.c + + +2005-10-05 18:26:56 GMT Stefan Reinauer patch-23 + + Summary: + address change, second attempt + Revision: + openbios--main--1.0--patch-23 + + The correct address of FSF is: + + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + + modified files: + COPYING Documentation/ChangeLog.arch + Documentation/kernel/COPYING drivers/adb.c drivers/adb.h + drivers/kbd.c drivers/kbd.h fs/grubfs/jfs.h fs/grubfs/xfs.h + toke/COPYING toke/Makefile toke/dictionary.c toke/dictionary.h + toke/emit.c toke/emit.h toke/macros.c toke/scanner.c + toke/stack.c toke/stack.h toke/stream.c toke/stream.h + toke/toke.c toke/toke.h utils/detok/COPYING + utils/detok/Makefile utils/detok/decode.c utils/detok/detok.c + utils/detok/detok.h utils/detok/dictionary.c + utils/detok/stream.c utils/detok/stream.h + utils/devbios/COPYING utils/devbios/bios.h + utils/devbios/bios_core.c utils/devbios/filesystem.c + utils/devbios/flashchips.c utils/devbios/flashchips.h + utils/devbios/pcisets.c utils/devbios/pcisets.h + utils/devbios/procfs.c utils/devbios/programming.c + utils/devbios/programming.h utils/fccc/COPYING + utils/romheaders/Makefile + + +2005-10-05 17:44:01 GMT Stefan Reinauer patch-22 + + Summary: + Update FSF address all over the tree + Revision: + openbios--main--1.0--patch-22 + + The FSF moved to a new address this April already. The old address was + still in place in many files in the tree. Now we're up to date again ;) + + + modified files: + COPYING Documentation/ChangeLog.arch + Documentation/kernel/COPYING drivers/adb.c drivers/adb.h + drivers/kbd.c drivers/kbd.h utils/detok/COPYING + utils/detok/Makefile utils/detok/decode.c utils/detok/detok.c + utils/detok/detok.h utils/detok/dictionary.c + utils/detok/stream.c utils/detok/stream.h + utils/devbios/COPYING utils/devbios/bios.h + utils/devbios/bios_core.c utils/devbios/filesystem.c + utils/devbios/flashchips.c utils/devbios/flashchips.h + utils/devbios/pcisets.c utils/devbios/pcisets.h + utils/devbios/procfs.c utils/devbios/programming.c + utils/devbios/programming.h utils/fccc/COPYING + utils/romheaders/Makefile + + +2005-10-05 17:40:18 GMT Stefan Reinauer patch-21 + + Summary: + fix two bugs in toke, update FSF address + Revision: + openbios--main--1.0--patch-21 + + * toke: fix signed/unsigned bug + * toke: error if maximum word count is exceeded + * toke: change FSF address to 51 Franklin St, Fifth Floor, Boston, MA, 02111-1301 USA + + + modified files: + Documentation/ChangeLog.arch toke/COPYING toke/ChangeLog + toke/Makefile toke/dictionary.c toke/dictionary.h toke/emit.c + toke/emit.h toke/macros.c toke/scanner.c toke/stack.c + toke/stack.h toke/stream.c toke/stream.h toke/toke.c + toke/toke.h + + +2005-10-02 12:18:38 GMT Stefan Reinauer patch-20 + + Summary: + add preliminary floppy driver + Revision: + openbios--main--1.0--patch-20 + + This is a simple floppy driver, borrowed from linuxbios v1 + + + new files: + drivers/.arch-ids/floppy.c.id drivers/.arch-ids/floppy.h.id + drivers/floppy.c drivers/floppy.h + + modified files: + Documentation/ChangeLog.arch arch/x86/openbios.c + config/examples/x86_config.xml drivers/build.xml + + +2005-09-17 15:29:08 GMT Stefan Reinauer patch-19 + + Summary: + merge openbios--xml--1.0--patch-48 back into openbios--main + Revision: + openbios--main--1.0--patch-19 + + finally merging the xml tree back to the main tree. Some things are missing + like a decent config tool (Kconfig?) But well.. + + Patches applied: + + * oxygene@openbios.org--2005/openbios--xml--1.0--base-0 + tag of stepan@openbios.org--devel/openbios--xml--1.0--patch-29 + + * oxygene@openbios.org--2005/openbios--xml--1.0--patch-1 + update openbios--xml with openbios--main + + * oxygene@openbios.org--2005/openbios--xml--1.0--patch-2 + change to word "dev" + + * stepan@openbios.org--devel/openbios--xml--1.0--base-0 + tag of stepan@openbios.org--devel/openbios--main--1.0--patch-14 + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-1 + initial checkin + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-2 + get briq building + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-3 + latest changes. clean ppc building up, etc pp + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-4 + checksum support + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-5 + first merge of cross platform abstraction + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-6 + more cross api changes + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-7 + more cross api merges + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-8 + + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-9 + toke fixes + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-10 + fix detok, v0.6.1 + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-11 + release ready version + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-12 + 2 flash chips supported + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-13 + devbios: fix filesystem.c + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-14 + fix devbios for 2.6.10. + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-15 + small fixes for ppc and filesystems + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-16 + cross api and other cleanups + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-17 + activate central trampoline for bootstrapping + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-18 + getting build process more into shape + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-19 + cross api: 64->32bit cross compilation + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-20 + only use cross.h during bootstrap. + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-21 + cross api swapped endian support. + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-22 + smaller fixes + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-23 + fill in cylinders on non chs disks as well + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-24 + fix NULL phandle problem + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-25 + fix ppc dictionary cross compiling + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-26 + small ppc pci update + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-27 + first merge of pearpc target + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-28 + fix pearpc nvram access + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-29 + pearpc update + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-30 + remove some gnuisms + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-31 + merge from patrick, some smaller updates + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-32 + add freebsd UFS driver (patch from Ed Schouten) + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-33 + two more missing files for UFS support.. + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-34 + fix gnuish leftovers (&>) + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-35 + small fix and ufs config file update + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-36 + another one: fix build.xml for UFS + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-37 + fix warnings in ufs driver + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-38 + get strcpy right + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-39 + start unifying video console code + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-40 + first try for xbox console output + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-41 + small preprocessor fix + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-42 + fix -ldl issue for non-linux systems. + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-43 + next try xbox console.. + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-44 + remove xml namespace from base tag + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-45 + drop video.c from ppc platform specific code + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-46 + add load address masking to boot fbsd kernels + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-47 + add openfirmware client interface example. + + * stepan@openbios.org--devel/openbios--xml--1.0--patch-48 + lots of endian fixes + + + new files: + .arch-ids/build.xml.id .arch-ids/config.xml.id + .arch-ids/rules.xml.id arch/.arch-ids/build.xml.id + arch/amd64/.arch-ids/build.xml.id arch/amd64/build.xml + arch/build.xml arch/ia64/.arch-ids/build.xml.id + arch/ia64/build.xml arch/ppc/.arch-ids/build.xml.id + arch/ppc/build.xml arch/ppc/pearpc/.arch-ids/=id + arch/ppc/pearpc/.arch-ids/console.c.id + arch/ppc/pearpc/.arch-ids/init.c.id + arch/ppc/pearpc/.arch-ids/kernel.c.id + arch/ppc/pearpc/.arch-ids/main.c.id + arch/ppc/pearpc/.arch-ids/methods.c.id + arch/ppc/pearpc/.arch-ids/pearpc.c.id + arch/ppc/pearpc/.arch-ids/pearpc.fs.id + arch/ppc/pearpc/.arch-ids/pearpc.h.id + arch/ppc/pearpc/.arch-ids/tree.c.id + arch/ppc/pearpc/.arch-ids/tree.fs.id + arch/ppc/pearpc/.arch-ids/vfd.c.id arch/ppc/pearpc/console.c + arch/ppc/pearpc/init.c arch/ppc/pearpc/kernel.c + arch/ppc/pearpc/main.c arch/ppc/pearpc/methods.c + arch/ppc/pearpc/pearpc.c arch/ppc/pearpc/pearpc.fs + arch/ppc/pearpc/pearpc.h arch/ppc/pearpc/tree.c + arch/ppc/pearpc/tree.fs arch/ppc/pearpc/vfd.c + arch/unix/.arch-ids/build.xml.id arch/unix/build.xml + arch/x86/.arch-ids/build.xml.id arch/x86/build.xml + arch/x86/xbox/.arch-ids/=id + arch/x86/xbox/.arch-ids/console.c.id + arch/x86/xbox/.arch-ids/methods.c.id arch/x86/xbox/console.c + arch/x86/xbox/methods.c build.xml config.xml + config/.arch-ids/=id config/examples/.arch-ids/=id + config/examples/.arch-ids/amd64_config.xml.id + config/examples/.arch-ids/amd64_rules.xml.id + config/examples/.arch-ids/cross-ppc_config.xml.id + config/examples/.arch-ids/cross-ppc_rules.xml.id + config/examples/.arch-ids/x86_config.xml.id + config/examples/.arch-ids/x86_rules.xml.id + config/examples/amd64_config.xml + config/examples/amd64_rules.xml + config/examples/cross-ppc_config.xml + config/examples/cross-ppc_rules.xml + config/examples/x86_config.xml config/examples/x86_rules.xml + config/scripts/.arch-ids/switch-arch.id + config/scripts/switch-arch config/xml/.arch-ids/=id + config/xml/.arch-ids/config-c.xsl.id + config/xml/.arch-ids/config-forth.xsl.id + config/xml/.arch-ids/dictionary.xsl.id + config/xml/.arch-ids/makefile.xsl.id + config/xml/.arch-ids/object.xsl.id + config/xml/.arch-ids/util.xsl.id + config/xml/.arch-ids/xinclude.xsl.id config/xml/config-c.xsl + config/xml/config-forth.xsl config/xml/dictionary.xsl + config/xml/makefile.xsl config/xml/object.xsl + config/xml/util.xsl config/xml/xinclude.xsl + drivers/.arch-ids/adb.c.id drivers/.arch-ids/adb.fs.id + drivers/.arch-ids/adb.h.id drivers/.arch-ids/build.xml.id + drivers/.arch-ids/cuda.c.id drivers/.arch-ids/cuda.h.id + drivers/.arch-ids/kbd.c.id drivers/.arch-ids/kbd.h.id + drivers/adb.c drivers/adb.fs drivers/adb.h drivers/build.xml + drivers/cuda.c drivers/cuda.h drivers/kbd.c drivers/kbd.h + forth/.arch-ids/build.xml.id + forth/admin/.arch-ids/build.xml.id forth/admin/build.xml + forth/bootstrap/.arch-ids/build.xml.id + forth/bootstrap/build.xml forth/build.xml + forth/debugging/.arch-ids/build.xml.id + forth/debugging/build.xml forth/device/.arch-ids/build.xml.id + forth/device/build.xml forth/lib/.arch-ids/build.xml.id + forth/lib/.arch-ids/preinclude.fs.id forth/lib/build.xml + forth/lib/preinclude.fs forth/packages/.arch-ids/build.xml.id + forth/packages/build.xml forth/system/.arch-ids/build.xml.id + forth/system/build.xml forth/testsuite/.arch-ids/build.xml.id + forth/testsuite/build.xml forth/util/.arch-ids/build.xml.id + forth/util/build.xml fs/.arch-ids/build.xml.id fs/build.xml + fs/grubfs/.arch-ids/build.xml.id + fs/grubfs/.arch-ids/fsys_ufs.c.id + fs/grubfs/.arch-ids/ufs_dinode.h.id + fs/grubfs/.arch-ids/ufs_fs.h.id fs/grubfs/build.xml + fs/grubfs/fsys_ufs.c fs/grubfs/ufs_dinode.h fs/grubfs/ufs_fs.h + fs/hfs/.arch-ids/build.xml.id fs/hfs/build.xml + fs/hfsplus/.arch-ids/build.xml.id fs/hfsplus/build.xml + include/.arch-ids/mconfig.h.id include/mconfig.h + include/ppc/.arch-ids/pci.h.id include/ppc/pci.h + kernel/.arch-ids/build.xml.id kernel/.arch-ids/cross.h.id + kernel/build.xml kernel/cross.h libc/.arch-ids/build.xml.id + libc/build.xml modules/.arch-ids/build.xml.id + modules/.arch-ids/console.c.id modules/.arch-ids/video.c.id + modules/build.xml modules/console.c modules/video.c rules.xml + toke/.arch-ids/Makefile.id toke/.arch-ids/build.xml.id + toke/Makefile toke/build.xml utils/ofclient/.arch-ids/=id + utils/ofclient/.arch-ids/Makefile.id + utils/ofclient/.arch-ids/README.id + utils/ofclient/.arch-ids/endian.h.id + utils/ofclient/.arch-ids/of1275.c.id + utils/ofclient/.arch-ids/of1275.h.id + utils/ofclient/.arch-ids/of1275_io.c.id + utils/ofclient/.arch-ids/ofclient.c.id utils/ofclient/Makefile + utils/ofclient/README utils/ofclient/endian.h + utils/ofclient/of1275.c utils/ofclient/of1275.h + utils/ofclient/of1275_io.c utils/ofclient/ofclient.c + + removed files: + .arch-ids/autogen.sh.id .arch-ids/configure.id + .arch-ids/setup_links.id arch/amd64/.arch-ids/Makefile.asm.id + arch/amd64/.arch-ids/Makefile.id arch/amd64/Makefile + arch/amd64/Makefile.asm arch/ia64/.arch-ids/Makefile.asm.id + arch/ia64/.arch-ids/Makefile.id arch/ia64/Makefile + arch/ia64/Makefile.asm arch/ppc/mol/.arch-ids/video.c.id + arch/ppc/mol/video.c arch/x86/.arch-ids/Makefile.asm.id + arch/x86/.arch-ids/Makefile.id arch/x86/Makefile + arch/x86/Makefile.asm autogen.sh config/.arch-ids/=id + config/.arch-ids/Makefile.defs.in.id + config/.arch-ids/Makefile.id + config/.arch-ids/Makefile.master.id + config/.arch-ids/Makefile.top.id + config/.arch-ids/Rules.forth.id config/.arch-ids/Rules.make.id + config/.arch-ids/configure.in.id config/Makefile + config/Makefile.defs.in config/Makefile.master + config/Makefile.top config/Rules.forth config/Rules.make + config/configure.in config/kconfig/.arch-ids/=id + config/kconfig/.arch-ids/Makefile.id + config/kconfig/.arch-ids/conf.c.id + config/kconfig/.arch-ids/confdata.c.id + config/kconfig/.arch-ids/expr.c.id + config/kconfig/.arch-ids/expr.h.id + config/kconfig/.arch-ids/lkc.h.id + config/kconfig/.arch-ids/lkc_proto.h.id + config/kconfig/.arch-ids/mconf.c.id + config/kconfig/.arch-ids/menu.c.id + config/kconfig/.arch-ids/symbol.c.id + config/kconfig/.arch-ids/zconf-l.l.id + config/kconfig/.arch-ids/zconf-y.y.id config/kconfig/Makefile + config/kconfig/conf.c config/kconfig/confdata.c + config/kconfig/expr.c config/kconfig/expr.h + config/kconfig/lkc.h config/kconfig/lkc_proto.h + config/kconfig/mconf.c config/kconfig/menu.c + config/kconfig/symbol.c config/kconfig/zconf-l.l + config/kconfig/zconf-y.y config/lxdialog/.arch-ids/=id + config/lxdialog/.arch-ids/Makefile.id + config/lxdialog/.arch-ids/checklist.c.id + config/lxdialog/.arch-ids/colors.h.id + config/lxdialog/.arch-ids/dialog.h.id + config/lxdialog/.arch-ids/inputbox.c.id + config/lxdialog/.arch-ids/lxdialog.c.id + config/lxdialog/.arch-ids/menubox.c.id + config/lxdialog/.arch-ids/msgbox.c.id + config/lxdialog/.arch-ids/textbox.c.id + config/lxdialog/.arch-ids/util.c.id + config/lxdialog/.arch-ids/yesno.c.id config/lxdialog/Makefile + config/lxdialog/checklist.c config/lxdialog/colors.h + config/lxdialog/dialog.h config/lxdialog/inputbox.c + config/lxdialog/lxdialog.c config/lxdialog/menubox.c + config/lxdialog/msgbox.c config/lxdialog/textbox.c + config/lxdialog/util.c config/lxdialog/yesno.c configure + drivers/.arch-ids/Makefile.id drivers/Makefile + forth/.arch-ids/Makefile.id forth/Makefile + forth/admin/.arch-ids/Makefile.id forth/admin/Makefile + forth/debugging/.arch-ids/Makefile.id forth/debugging/Makefile + forth/device/.arch-ids/Makefile.id forth/device/Makefile + forth/lib/.arch-ids/Makefile.id forth/lib/Makefile + forth/packages/.arch-ids/Makefile.id forth/packages/Makefile + forth/system/.arch-ids/Makefile.id forth/system/Makefile + forth/testsuite/.arch-ids/Makefile.id forth/testsuite/Makefile + forth/util/.arch-ids/Makefile.id forth/util/Makefile + fs/.arch-ids/Makefile.id fs/Makefile + fs/grubfs/.arch-ids/Makefile.id fs/grubfs/Makefile + fs/hfs/.arch-ids/Makefile.id fs/hfs/Makefile + fs/hfsplus/.arch-ids/Makefile.id fs/hfsplus/Makefile + kernel/.arch-ids/Makefile.id kernel/Makefile + libc/.arch-ids/Makefile.id libc/.arch-ids/byteorder.c.id + libc/Makefile libc/byteorder.c modules/.arch-ids/Makefile.id + modules/Makefile setup_links toke/.arch-ids/Makefile.id + toke/Makefile + + modified files: + Documentation/ChangeLog.arch Makefile README + arch/ppc/briq/briq.c arch/ppc/briq/init.c + arch/ppc/briq/kernel.c arch/ppc/mol/console.c arch/ppc/ofmem.c + arch/unix/Makefile arch/unix/plugins/Makefile arch/unix/unix.c + arch/x86/elfload.c arch/x86/multiboot.c arch/x86/openbios.c + arch/x86/sys_info.c drivers/ide.c drivers/pci.c drivers/pci.fs + forth/admin/banner.fs forth/admin/devices.fs + forth/bootstrap/bootstrap.fs forth/device/font.fs + fs/grubfs/Kconfig fs/grubfs/filesys.h fs/grubfs/fsys_ext2fs.c + fs/grubfs/fsys_reiserfs.c fs/grubfs/fsys_xfs.c + fs/grubfs/grubfs_fs.c include/amd64/io.h + include/libc/byteorder.h include/libc/stdlib.h + include/openbios/stack.h include/ppc/io.h include/ppc/types.h + include/x86/io.h include/x86/pci.h include/x86/types.h + kernel/bootstrap.c kernel/dict.c kernel/forth.c + kernel/include/dict.h kernel/internal.c kernel/primitives.c + modules/bindings.c modules/pc-parts.c toke/ChangeLog + toke/dictionary.c toke/dictionary.h toke/emit.c toke/emit.h + toke/macros.c toke/scanner.c toke/stack.c toke/stack.h + toke/stream.c toke/stream.h toke/toke.c toke/toke.h + utils/README utils/devbios/filesystem.c + utils/devbios/flashchips.c utils/devbios/pcisets.c + + renamed files: + arch/ppc/mol/.arch-ids/font_8x8.c.id + ==> modules/.arch-ids/font_8x8.c.id + arch/ppc/mol/font_8x8.c + ==> modules/font_8x8.c + dist/.arch-ids/=id + ==> utils/dist/.arch-ids/=id + dist/.arch-ids/openbios.spec.id + ==> utils/dist/.arch-ids/openbios.spec.id + dist/debian/.arch-ids/=id + ==> utils/dist/debian/.arch-ids/=id + dist/debian/.arch-ids/changelog.id + ==> utils/dist/debian/.arch-ids/changelog.id + dist/debian/.arch-ids/control.id + ==> utils/dist/debian/.arch-ids/control.id + dist/debian/.arch-ids/packages.id + ==> utils/dist/debian/.arch-ids/packages.id + dist/debian/.arch-ids/rules.id + ==> utils/dist/debian/.arch-ids/rules.id + + new directories: + arch/ppc/pearpc arch/ppc/pearpc/.arch-ids arch/x86/xbox + arch/x86/xbox/.arch-ids config config/examples + config/examples/.arch-ids config/xml config/xml/.arch-ids + utils/dist/.arch-ids utils/dist/debian/.arch-ids + utils/ofclient utils/ofclient/.arch-ids + + removed directories: + config config/kconfig config/kconfig/.arch-ids config/lxdialog + config/lxdialog/.arch-ids dist/.arch-ids dist/debian/.arch-ids + + modified directories: + config/.arch-ids + + renamed directories: + config/.arch-ids + ==> config/.arch-ids + config/scripts + ==> config/scripts + dist + ==> utils/dist + + new patches: + oxygene@openbios.org--2005/openbios--xml--1.0--base-0 + oxygene@openbios.org--2005/openbios--xml--1.0--patch-1 + oxygene@openbios.org--2005/openbios--xml--1.0--patch-2 + stepan@openbios.org--devel/openbios--xml--1.0--base-0 + stepan@openbios.org--devel/openbios--xml--1.0--patch-1 + stepan@openbios.org--devel/openbios--xml--1.0--patch-2 + stepan@openbios.org--devel/openbios--xml--1.0--patch-3 + stepan@openbios.org--devel/openbios--xml--1.0--patch-4 + stepan@openbios.org--devel/openbios--xml--1.0--patch-5 + stepan@openbios.org--devel/openbios--xml--1.0--patch-6 + stepan@openbios.org--devel/openbios--xml--1.0--patch-7 + stepan@openbios.org--devel/openbios--xml--1.0--patch-8 + stepan@openbios.org--devel/openbios--xml--1.0--patch-9 + stepan@openbios.org--devel/openbios--xml--1.0--patch-10 + stepan@openbios.org--devel/openbios--xml--1.0--patch-11 + stepan@openbios.org--devel/openbios--xml--1.0--patch-12 + stepan@openbios.org--devel/openbios--xml--1.0--patch-13 + stepan@openbios.org--devel/openbios--xml--1.0--patch-14 + stepan@openbios.org--devel/openbios--xml--1.0--patch-15 + stepan@openbios.org--devel/openbios--xml--1.0--patch-16 + stepan@openbios.org--devel/openbios--xml--1.0--patch-17 + stepan@openbios.org--devel/openbios--xml--1.0--patch-18 + stepan@openbios.org--devel/openbios--xml--1.0--patch-19 + stepan@openbios.org--devel/openbios--xml--1.0--patch-20 + stepan@openbios.org--devel/openbios--xml--1.0--patch-21 + stepan@openbios.org--devel/openbios--xml--1.0--patch-22 + stepan@openbios.org--devel/openbios--xml--1.0--patch-23 + stepan@openbios.org--devel/openbios--xml--1.0--patch-24 + stepan@openbios.org--devel/openbios--xml--1.0--patch-25 + stepan@openbios.org--devel/openbios--xml--1.0--patch-26 + stepan@openbios.org--devel/openbios--xml--1.0--patch-27 + stepan@openbios.org--devel/openbios--xml--1.0--patch-28 + stepan@openbios.org--devel/openbios--xml--1.0--patch-29 + stepan@openbios.org--devel/openbios--xml--1.0--patch-30 + stepan@openbios.org--devel/openbios--xml--1.0--patch-31 + stepan@openbios.org--devel/openbios--xml--1.0--patch-32 + stepan@openbios.org--devel/openbios--xml--1.0--patch-33 + stepan@openbios.org--devel/openbios--xml--1.0--patch-34 + stepan@openbios.org--devel/openbios--xml--1.0--patch-35 + stepan@openbios.org--devel/openbios--xml--1.0--patch-36 + stepan@openbios.org--devel/openbios--xml--1.0--patch-37 + stepan@openbios.org--devel/openbios--xml--1.0--patch-38 + stepan@openbios.org--devel/openbios--xml--1.0--patch-39 + stepan@openbios.org--devel/openbios--xml--1.0--patch-40 + stepan@openbios.org--devel/openbios--xml--1.0--patch-41 + stepan@openbios.org--devel/openbios--xml--1.0--patch-42 + stepan@openbios.org--devel/openbios--xml--1.0--patch-43 + stepan@openbios.org--devel/openbios--xml--1.0--patch-44 + stepan@openbios.org--devel/openbios--xml--1.0--patch-45 + stepan@openbios.org--devel/openbios--xml--1.0--patch-46 + stepan@openbios.org--devel/openbios--xml--1.0--patch-47 + stepan@openbios.org--devel/openbios--xml--1.0--patch-48 + + +2005-03-10 14:46:23 GMT Stefan Reinauer patch-18 + + Summary: + detok update: 0.6.1 + Revision: + openbios--main--1.0--patch-18 + + * fix bug in output of strings. Strings were cut off when 0 bytes + occured, in a C manner. Now detok prints correct forth strings. + Thanks to Arti Itra for reporting this. + + * free string after printing it. + + + modified files: + Documentation/ChangeLog.arch utils/detok/ChangeLog + utils/detok/Makefile utils/detok/README utils/detok/decode.c + utils/detok/detok.c utils/detok/detok.h + utils/detok/dictionary.c utils/detok/stream.c + utils/detok/stream.h + + +2005-03-10 12:52:08 GMT Stefan Reinauer patch-17 + + Summary: + toke update + Revision: + openbios--main--1.0--patch-17 + + * fix fload. Problem reported by David L. Paktor + * remove debug enforcement in scanner.c + + + modified files: + Documentation/ChangeLog.arch toke/scanner.c toke/stream.c + + +2005-02-22 21:54:06 GMT Stefan Reinauer patch-16 + + Summary: + fix uninitialized variable + Revision: + openbios--main--1.0--patch-16 + + step towards fixing devbios + + + modified files: + Documentation/ChangeLog.arch utils/devbios/pcisets.c + + +2005-01-27 10:12:20 GMT Stefan Reinauer patch-15 + + Summary: + update documentation + Revision: + openbios--main--1.0--patch-15 + + Documentation update (thanks to Brian Sammon) + + + modified files: + Documentation/ChangeLog.arch README + + +2004-11-01 20:33:55 GMT Stefan Reinauer patch-14 + + Summary: + add exception handling for x86 + Revision: + openbios--main--1.0--patch-14 + + simple exception handling for x86. Safe return does not seem to work yet. + + + new files: + arch/x86/.arch-ids/exception.c.id arch/x86/exception.c + + modified files: + Documentation/ChangeLog.arch arch/unix/unix.c + arch/x86/Makefile arch/x86/context.c arch/x86/entry.S + + renamed files: + arch/x86/.arch-ids/switch.S.id + ==> arch/x86/.arch-ids/entry.S.id + arch/x86/switch.S + ==> arch/x86/entry.S + + +2004-09-19 20:24:46 GMT Stefan Reinauer patch-13 + + Summary: + type cleanups + Revision: + openbios--main--1.0--patch-13 + + applying first patch of issue 38 + + + + modified files: + Documentation/ChangeLog.arch kernel/bootstrap.c kernel/forth.c + + +2004-09-19 15:34:22 GMT Stefan Reinauer patch-12 + + Summary: + use ranlib instead of "ar s" + Revision: + openbios--main--1.0--patch-12 + + "ar s" is GNU specific and the documenation says it is equal to ranlib. So we + rather use ranlib and stay portable (ie. to Solaris9) + + fixes issue 36 + + + modified files: + Documentation/ChangeLog.arch config/Rules.make + + +2004-09-19 13:38:37 GMT Stefan Reinauer patch-11 + + Summary: + initialize ofmem structure properly + Revision: + openbios--main--1.0--patch-11 + + initialize ofmem structure with zero. The correct fix + would be to obtain all information from either linuxbios, + uboot, the hardware or a defined per-board function + + + modified files: + Documentation/ChangeLog.arch arch/ppc/ofmem.c + + +2004-09-12 15:02:04 GMT Stefan Reinauer patch-10 + + Summary: + initialize nvram structure completely + Revision: + openbios--main--1.0--patch-10 + + fixes issue 17. nvram structure did not get initialized completely + + + modified files: + Documentation/ChangeLog.arch modules/nvram.c + + +2004-09-12 14:43:23 GMT Stefan Reinauer patch-9 + + Summary: + fix little endian/big endian handling + Revision: + openbios--main--1.0--patch-9 + + this should fix issue 20. Switch all endianess handling to use + CONFIG_LITTLE_ENDIAN/CONFIG_BIG_ENDIAN + + + + modified files: + Documentation/ChangeLog.arch fs/hfsplus/btree.c + include/amd64/types.h include/ia64/types.h include/ppc/types.h + include/x86/types.h kernel/bootstrap.c kernel/forth.c + + +2004-09-12 12:29:55 GMT Stefan Reinauer patch-8 + + Summary: + + Revision: + openbios--main--1.0--patch-8 + + + + + modified files: + Documentation/ChangeLog.arch arch/amd64/boot.c + arch/amd64/context.c arch/amd64/elfload.c arch/amd64/lib.c + arch/amd64/linux_load.c arch/amd64/multiboot.c + arch/amd64/segment.c arch/amd64/sys_info.c + arch/ppc/briq/briq.c arch/ppc/briq/init.c arch/ppc/briq/main.c + arch/ppc/briq/methods.c arch/ppc/kernel.c arch/ppc/mol/init.c + arch/ppc/mol/main.c arch/ppc/mol/methods.c arch/ppc/mol/mol.c + arch/ppc/mol/osi-blk.c arch/ppc/mol/osi-scsi.c + arch/ppc/mol/prom.c arch/ppc/mol/pseudodisk.c + arch/ppc/mol/tree.c arch/ppc/mol/video.c arch/ppc/ofmem.c + arch/unix/blk.c arch/unix/boot.c arch/unix/unix.c + arch/x86/boot.c arch/x86/context.c arch/x86/elfload.c + arch/x86/forthload.c arch/x86/lib.c arch/x86/linux_load.c + arch/x86/multiboot.c arch/x86/segment.c arch/x86/sys_info.c + drivers/ide.c drivers/pci.c fs/grubfs/grubfs_fs.c + fs/hfs/hfs_fs.c fs/hfsplus/hfsp_fs.c fs/ioglue.c + include/openbios/sysinclude.h kernel/internal.c + modules/bindings.c modules/client.c modules/deblocker.c + modules/disk-label.c modules/elfload.c modules/elfnote.c + modules/filesystems.c modules/linuxbios.c modules/mac-parts.c + modules/nvram.c modules/pc-parts.c + + +2004-09-11 23:18:56 GMT Stefan Reinauer patch-7 + + Summary: + get tla silent on commit + Revision: + openbios--main--1.0--patch-7 + + get tla silent on commit. add some files to precious + + + modified files: + Documentation/ChangeLog.arch {arch}/=tagging-method + + +2004-09-11 22:21:05 GMT Stefan Reinauer patch-6 + + Summary: + elimination of variables tramp_semis and trampoline + Revision: + openbios--main--1.0--patch-6 + + This fixes https://openbios.org/roundup/openbios/issue22 + + + modified files: + Documentation/ChangeLog.arch kernel/internal.c + + +2004-09-11 21:55:42 GMT Stefan Reinauer patch-5 + + Summary: + initialize cache_xt and catch_xt to 0 + Revision: + openbios--main--1.0--patch-5 + + this fixes openbios to work with compilers that do not null out uninitialized + variables. (fixes issues 13 and 18) + + + modified files: + Documentation/ChangeLog.arch include/openbios/bindings.h + modules/bindings.c + + +2004-09-11 21:33:13 GMT Stefan Reinauer patch-4 + + Summary: + IDE fix + Revision: + openbios--main--1.0--patch-4 + + shame, shame, shame, shame.. + shame on me.. + + + modified files: + Documentation/ChangeLog.arch drivers/ide.c + + +2004-09-05 17:41:18 GMT Stefan Reinauer patch-3 + + Summary: + fix briq build + Revision: + openbios--main--1.0--patch-3 + + fix build for Total Impact Briq systems. This is mostly fixing typos that I + introduced in Gregs recent changes. + + + modified files: + Documentation/ChangeLog.arch arch/ppc/Makefile + arch/ppc/briq/briq.h arch/ppc/briq/kernel.c drivers/Kconfig + drivers/ide.c drivers/ide.h drivers/timer.c drivers/timer.h + + +2004-09-03 19:40:52 GMT Stefan Reinauer patch-2 + + Summary: + oxygene fixed the file permissions + Revision: + openbios--main--1.0--patch-2 + + merged from Patricks tree + + Patches applied: + + * oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-4 + make all files writable, we're not using bitkeeper + + + modified files: + .arch-ids/COPYING.id .arch-ids/Makefile.id .arch-ids/README.id + .arch-ids/autogen.sh.id .arch-ids/configure.id + .arch-ids/setup_links.id COPYING Documentation/.arch-ids/=id + Documentation/ChangeLog.arch + Documentation/kernel/.arch-ids/=id + Documentation/kernel/.arch-ids/AUTHORS.id + Documentation/kernel/.arch-ids/COPYING.id + Documentation/kernel/.arch-ids/Changelog.stepan.id + Documentation/kernel/.arch-ids/TODO.id + Documentation/kernel/.arch-ids/dictformat.txt.id + Documentation/kernel/.arch-ids/glossary.txt.id + Documentation/kernel/.arch-ids/initializers.txt.id + Documentation/kernel/AUTHORS Documentation/kernel/COPYING + Documentation/kernel/Changelog.stepan + Documentation/kernel/TODO Documentation/kernel/dictformat.txt + Documentation/kernel/glossary.txt + Documentation/kernel/initializers.txt Makefile README + arch/.arch-ids/=id arch/amd64/.arch-ids/=id + arch/amd64/.arch-ids/Kconfig.id + arch/amd64/.arch-ids/Makefile.asm.id + arch/amd64/.arch-ids/Makefile.id + arch/amd64/.arch-ids/boot.c.id + arch/amd64/.arch-ids/builtin.c.id + arch/amd64/.arch-ids/console.c.id + arch/amd64/.arch-ids/context.c.id + arch/amd64/.arch-ids/context.h.id + arch/amd64/.arch-ids/defconfig.id + arch/amd64/.arch-ids/elfload.c.id + arch/amd64/.arch-ids/init.fs.id + arch/amd64/.arch-ids/ldscript.id arch/amd64/.arch-ids/lib.c.id + arch/amd64/.arch-ids/linux_load.c.id + arch/amd64/.arch-ids/loadfs.c.id + arch/amd64/.arch-ids/loadfs.h.id + arch/amd64/.arch-ids/multiboot.c.id + arch/amd64/.arch-ids/multiboot.h.id + arch/amd64/.arch-ids/openbios.c.id + arch/amd64/.arch-ids/openbios.h.id + arch/amd64/.arch-ids/plainboot.c.id + arch/amd64/.arch-ids/relocate.h.id + arch/amd64/.arch-ids/segment.c.id + arch/amd64/.arch-ids/segment.h.id + arch/amd64/.arch-ids/switch.S.id + arch/amd64/.arch-ids/sys_info.c.id arch/amd64/Kconfig + arch/amd64/Makefile arch/amd64/Makefile.asm arch/amd64/boot.c + arch/amd64/builtin.c arch/amd64/console.c arch/amd64/context.c + arch/amd64/context.h arch/amd64/defconfig arch/amd64/elfload.c + arch/amd64/init.fs arch/amd64/ldscript arch/amd64/lib.c + arch/amd64/linux_load.c arch/amd64/loadfs.c + arch/amd64/loadfs.h arch/amd64/multiboot.c + arch/amd64/multiboot.h arch/amd64/openbios.c + arch/amd64/openbios.h arch/amd64/plainboot.c + arch/amd64/relocate.h arch/amd64/segment.c + arch/amd64/segment.h arch/amd64/switch.S arch/amd64/sys_info.c + arch/ia64/.arch-ids/=id arch/ia64/.arch-ids/Kconfig.id + arch/ia64/.arch-ids/Makefile.asm.id + arch/ia64/.arch-ids/Makefile.id + arch/ia64/.arch-ids/defconfig.id + arch/ia64/.arch-ids/init.fs.id arch/ia64/Kconfig + arch/ia64/Makefile arch/ia64/Makefile.asm arch/ia64/defconfig + arch/ia64/init.fs arch/ppc/.arch-ids/=id + arch/ppc/.arch-ids/Kconfig.id + arch/ppc/.arch-ids/Makefile.asm.id + arch/ppc/.arch-ids/Makefile.id arch/ppc/.arch-ids/defconfig.id + arch/ppc/.arch-ids/kernel.c.id arch/ppc/.arch-ids/kernel.h.id + arch/ppc/.arch-ids/misc.S.id arch/ppc/.arch-ids/mmutypes.h.id + arch/ppc/.arch-ids/ofmem.c.id arch/ppc/.arch-ids/osi.h.id + arch/ppc/.arch-ids/osi_calls.h.id arch/ppc/.arch-ids/ppc.fs.id + arch/ppc/.arch-ids/start.S.id arch/ppc/.arch-ids/timebase.S.id + arch/ppc/Kconfig arch/ppc/Makefile arch/ppc/Makefile.asm + arch/ppc/briq/.arch-ids/=id arch/ppc/briq/.arch-ids/briq.c.id + arch/ppc/briq/.arch-ids/briq.fs.id + arch/ppc/briq/.arch-ids/briq.h.id + arch/ppc/briq/.arch-ids/init.c.id + arch/ppc/briq/.arch-ids/kernel.c.id + arch/ppc/briq/.arch-ids/main.c.id + arch/ppc/briq/.arch-ids/methods.c.id + arch/ppc/briq/.arch-ids/tree.c.id + arch/ppc/briq/.arch-ids/tree.fs.id + arch/ppc/briq/.arch-ids/vfd.c.id arch/ppc/briq/briq.c + arch/ppc/briq/briq.fs arch/ppc/briq/briq.h + arch/ppc/briq/init.c arch/ppc/briq/kernel.c + arch/ppc/briq/main.c arch/ppc/briq/methods.c + arch/ppc/briq/tree.c arch/ppc/briq/tree.fs arch/ppc/briq/vfd.c + arch/ppc/defconfig arch/ppc/kernel.c arch/ppc/kernel.h + arch/ppc/misc.S arch/ppc/mmutypes.h arch/ppc/mol/.arch-ids/=id + arch/ppc/mol/.arch-ids/console.c.id + arch/ppc/mol/.arch-ids/font_8x8.c.id + arch/ppc/mol/.arch-ids/init.c.id + arch/ppc/mol/.arch-ids/kernel.c.id + arch/ppc/mol/.arch-ids/main.c.id + arch/ppc/mol/.arch-ids/methods.c.id + arch/ppc/mol/.arch-ids/mol.c.id + arch/ppc/mol/.arch-ids/mol.fs.id + arch/ppc/mol/.arch-ids/mol.h.id + arch/ppc/mol/.arch-ids/osi-blk.c.id + arch/ppc/mol/.arch-ids/osi-scsi.c.id + arch/ppc/mol/.arch-ids/prom.c.id + arch/ppc/mol/.arch-ids/prom.h.id + arch/ppc/mol/.arch-ids/pseudodisk.c.id + arch/ppc/mol/.arch-ids/tree.c.id + arch/ppc/mol/.arch-ids/tree.fs.id + arch/ppc/mol/.arch-ids/video.c.id arch/ppc/mol/console.c + arch/ppc/mol/font_8x8.c arch/ppc/mol/init.c + arch/ppc/mol/kernel.c arch/ppc/mol/main.c + arch/ppc/mol/methods.c arch/ppc/mol/mol.c arch/ppc/mol/mol.fs + arch/ppc/mol/mol.h arch/ppc/mol/osi-blk.c + arch/ppc/mol/osi-scsi.c arch/ppc/mol/prom.c + arch/ppc/mol/prom.h arch/ppc/mol/pseudodisk.c + arch/ppc/mol/tree.c arch/ppc/mol/tree.fs arch/ppc/mol/video.c + arch/ppc/ofmem.c arch/ppc/osi.h arch/ppc/osi_calls.h + arch/ppc/ppc.fs arch/ppc/start.S arch/ppc/timebase.S + arch/unix/.arch-ids/=id arch/unix/.arch-ids/Kconfig.id + arch/unix/.arch-ids/Makefile.id arch/unix/.arch-ids/blk.c.id + arch/unix/.arch-ids/blk.h.id arch/unix/.arch-ids/boot.c.id + arch/unix/.arch-ids/plugins.c.id + arch/unix/.arch-ids/tree.fs.id arch/unix/.arch-ids/unix.c.id + arch/unix/Kconfig arch/unix/Makefile arch/unix/blk.c + arch/unix/blk.h arch/unix/boot.c + arch/unix/gui_qt/.arch-ids/=id + arch/unix/gui_qt/.arch-ids/Makefile.id + arch/unix/gui_qt/.arch-ids/gui-qt.cpp.id + arch/unix/gui_qt/.arch-ids/gui-qt.h.id + arch/unix/gui_qt/.arch-ids/gui-qt.pro.id + arch/unix/gui_qt/.arch-ids/logo.xpm.id + arch/unix/gui_qt/.arch-ids/qt-main.cpp.id + arch/unix/gui_qt/Makefile arch/unix/gui_qt/gui-qt.cpp + arch/unix/gui_qt/gui-qt.h arch/unix/gui_qt/gui-qt.pro + arch/unix/gui_qt/logo.xpm arch/unix/gui_qt/qt-main.cpp + arch/unix/plugins.c arch/unix/plugins/.arch-ids/=id + arch/unix/plugins/.arch-ids/Kconfig.id + arch/unix/plugins/.arch-ids/Makefile.id + arch/unix/plugins/.arch-ids/Rules.plugin.id + arch/unix/plugins/.arch-ids/loader.c.id + arch/unix/plugins/Kconfig arch/unix/plugins/Makefile + arch/unix/plugins/Rules.plugin arch/unix/plugins/loader.c + arch/unix/plugins/plugin_pci/.arch-ids/=id + arch/unix/plugins/plugin_pci/.arch-ids/Makefile.id + arch/unix/plugins/plugin_pci/.arch-ids/Makefile.old.id + arch/unix/plugins/plugin_pci/.arch-ids/plugin_pci.c.id + arch/unix/plugins/plugin_pci/Makefile + arch/unix/plugins/plugin_pci/Makefile.old + arch/unix/plugins/plugin_pci/plugin_pci.c + arch/unix/plugins/plugin_qt/.arch-ids/=id + arch/unix/plugins/plugin_qt/.arch-ids/Makefile.id + arch/unix/plugins/plugin_qt/.arch-ids/logo.xpm.id + arch/unix/plugins/plugin_qt/.arch-ids/pciconfig.h.id + arch/unix/plugins/plugin_qt/.arch-ids/plugin_qt.cpp.id + arch/unix/plugins/plugin_qt/.arch-ids/plugin_qt.h.id + arch/unix/plugins/plugin_qt/.arch-ids/plugin_qt.pro.id + arch/unix/plugins/plugin_qt/.arch-ids/qt_main.cpp.id + arch/unix/plugins/plugin_qt/.arch-ids/qt_rom.fs.id + arch/unix/plugins/plugin_qt/Makefile + arch/unix/plugins/plugin_qt/logo.xpm + arch/unix/plugins/plugin_qt/pciconfig.h + arch/unix/plugins/plugin_qt/plugin_qt.cpp + arch/unix/plugins/plugin_qt/plugin_qt.h + arch/unix/plugins/plugin_qt/plugin_qt.pro + arch/unix/plugins/plugin_qt/qt_main.cpp + arch/unix/plugins/plugin_qt/qt_rom.fs arch/unix/tree.fs + arch/unix/unix.c arch/x86/.arch-ids/=id + arch/x86/.arch-ids/Kconfig.id + arch/x86/.arch-ids/Makefile.asm.id + arch/x86/.arch-ids/Makefile.id arch/x86/.arch-ids/boot.c.id + arch/x86/.arch-ids/boot.h.id arch/x86/.arch-ids/builtin.c.id + arch/x86/.arch-ids/console.c.id + arch/x86/.arch-ids/context.c.id + arch/x86/.arch-ids/context.h.id + arch/x86/.arch-ids/defconfig.id + arch/x86/.arch-ids/elfload.c.id + arch/x86/.arch-ids/forthload.c.id + arch/x86/.arch-ids/init.fs.id arch/x86/.arch-ids/ldscript.id + arch/x86/.arch-ids/lib.c.id arch/x86/.arch-ids/linux_load.c.id + arch/x86/.arch-ids/loadfs.c.id arch/x86/.arch-ids/loadfs.h.id + arch/x86/.arch-ids/multiboot.c.id + arch/x86/.arch-ids/multiboot.h.id + arch/x86/.arch-ids/openbios.c.id + arch/x86/.arch-ids/openbios.h.id + arch/x86/.arch-ids/plainboot.c.id + arch/x86/.arch-ids/relocate.h.id + arch/x86/.arch-ids/segment.c.id + arch/x86/.arch-ids/segment.h.id arch/x86/.arch-ids/switch.S.id + arch/x86/.arch-ids/sys_info.c.id arch/x86/Kconfig + arch/x86/Makefile arch/x86/Makefile.asm arch/x86/boot.c + arch/x86/boot.h arch/x86/builtin.c arch/x86/console.c + arch/x86/context.c arch/x86/context.h arch/x86/defconfig + arch/x86/elfload.c arch/x86/forthload.c arch/x86/init.fs + arch/x86/ldscript arch/x86/lib.c arch/x86/linux_load.c + arch/x86/loadfs.c arch/x86/loadfs.h arch/x86/multiboot.c + arch/x86/multiboot.h arch/x86/openbios.c arch/x86/openbios.h + arch/x86/plainboot.c arch/x86/relocate.h arch/x86/segment.c + arch/x86/segment.h arch/x86/switch.S arch/x86/sys_info.c + autogen.sh config/.arch-ids/=id + config/.arch-ids/Makefile.defs.in.id + config/.arch-ids/Makefile.id + config/.arch-ids/Makefile.master.id + config/.arch-ids/Makefile.top.id + config/.arch-ids/Rules.forth.id config/.arch-ids/Rules.make.id + config/.arch-ids/configure.in.id config/Makefile + config/Makefile.defs.in config/Makefile.master + config/Makefile.top config/Rules.forth config/Rules.make + config/configure.in config/kconfig/.arch-ids/=id + config/kconfig/.arch-ids/Makefile.id + config/kconfig/.arch-ids/conf.c.id + config/kconfig/.arch-ids/confdata.c.id + config/kconfig/.arch-ids/expr.c.id + config/kconfig/.arch-ids/expr.h.id + config/kconfig/.arch-ids/lkc.h.id + config/kconfig/.arch-ids/lkc_proto.h.id + config/kconfig/.arch-ids/mconf.c.id + config/kconfig/.arch-ids/menu.c.id + config/kconfig/.arch-ids/symbol.c.id + config/kconfig/.arch-ids/zconf-l.l.id + config/kconfig/.arch-ids/zconf-y.y.id config/kconfig/Makefile + config/kconfig/conf.c config/kconfig/confdata.c + config/kconfig/expr.c config/kconfig/expr.h + config/kconfig/lkc.h config/kconfig/lkc_proto.h + config/kconfig/mconf.c config/kconfig/menu.c + config/kconfig/symbol.c config/kconfig/zconf-l.l + config/kconfig/zconf-y.y config/lxdialog/.arch-ids/=id + config/lxdialog/.arch-ids/Makefile.id + config/lxdialog/.arch-ids/checklist.c.id + config/lxdialog/.arch-ids/colors.h.id + config/lxdialog/.arch-ids/dialog.h.id + config/lxdialog/.arch-ids/inputbox.c.id + config/lxdialog/.arch-ids/lxdialog.c.id + config/lxdialog/.arch-ids/menubox.c.id + config/lxdialog/.arch-ids/msgbox.c.id + config/lxdialog/.arch-ids/textbox.c.id + config/lxdialog/.arch-ids/util.c.id + config/lxdialog/.arch-ids/yesno.c.id config/lxdialog/Makefile + config/lxdialog/checklist.c config/lxdialog/colors.h + config/lxdialog/dialog.h config/lxdialog/inputbox.c + config/lxdialog/lxdialog.c config/lxdialog/menubox.c + config/lxdialog/msgbox.c config/lxdialog/textbox.c + config/lxdialog/util.c config/lxdialog/yesno.c + config/scripts/.arch-ids/=id + config/scripts/.arch-ids/archname.id + config/scripts/.arch-ids/reldir.id config/scripts/archname + config/scripts/reldir configure dist/.arch-ids/=id + dist/.arch-ids/openbios.spec.id dist/debian/.arch-ids/=id + dist/debian/.arch-ids/changelog.id + dist/debian/.arch-ids/control.id + dist/debian/.arch-ids/packages.id + dist/debian/.arch-ids/rules.id dist/debian/changelog + dist/debian/control dist/debian/packages dist/debian/rules + dist/openbios.spec drivers/.arch-ids/=id + drivers/.arch-ids/Kconfig.id drivers/.arch-ids/Makefile.id + drivers/.arch-ids/hdreg.h.id drivers/.arch-ids/ide.c.id + drivers/.arch-ids/ide.fs.id drivers/.arch-ids/ide.h.id + drivers/.arch-ids/pci.c.id drivers/.arch-ids/pci.fs.id + drivers/.arch-ids/pci.h.id drivers/.arch-ids/timer.c.id + drivers/.arch-ids/timer.h.id drivers/Kconfig drivers/Makefile + drivers/hdreg.h drivers/ide.c drivers/ide.fs drivers/ide.h + drivers/pci.c drivers/pci.fs drivers/pci.h drivers/timer.c + drivers/timer.h forth/.arch-ids/=id forth/.arch-ids/Kconfig.id + forth/.arch-ids/Makefile.id forth/Kconfig forth/Makefile + forth/admin/.arch-ids/=id forth/admin/.arch-ids/Makefile.id + forth/admin/.arch-ids/README.id + forth/admin/.arch-ids/banner.fs.id + forth/admin/.arch-ids/callback.fs.id + forth/admin/.arch-ids/devices.fs.id + forth/admin/.arch-ids/help.fs.id + forth/admin/.arch-ids/iocontrol.fs.id + forth/admin/.arch-ids/nvram.fs.id + forth/admin/.arch-ids/reset.fs.id + forth/admin/.arch-ids/script.fs.id + forth/admin/.arch-ids/security.fs.id + forth/admin/.arch-ids/selftest.fs.id + forth/admin/.arch-ids/userboot.fs.id forth/admin/Makefile + forth/admin/README forth/admin/banner.fs + forth/admin/callback.fs forth/admin/devices.fs + forth/admin/help.fs forth/admin/iocontrol.fs + forth/admin/nvram.fs forth/admin/reset.fs + forth/admin/script.fs forth/admin/security.fs + forth/admin/selftest.fs forth/admin/userboot.fs + forth/bootstrap/.arch-ids/=id + forth/bootstrap/.arch-ids/bootstrap.fs.id + forth/bootstrap/.arch-ids/builtin.fs.id + forth/bootstrap/.arch-ids/hayes.fs.id + forth/bootstrap/.arch-ids/interpreter.fs.id + forth/bootstrap/.arch-ids/memory.fs.id + forth/bootstrap/.arch-ids/start.fs.id + forth/bootstrap/bootstrap.fs forth/bootstrap/builtin.fs + forth/bootstrap/hayes.fs forth/bootstrap/interpreter.fs + forth/bootstrap/memory.fs forth/bootstrap/start.fs + forth/debugging/.arch-ids/=id + forth/debugging/.arch-ids/Makefile.id + forth/debugging/.arch-ids/client.fs.id + forth/debugging/.arch-ids/fcode.fs.id + forth/debugging/.arch-ids/firmware.fs.id + forth/debugging/.arch-ids/see.fs.id forth/debugging/Makefile + forth/debugging/client.fs forth/debugging/fcode.fs + forth/debugging/firmware.fs forth/debugging/see.fs + forth/device/.arch-ids/=id forth/device/.arch-ids/Makefile.id + forth/device/.arch-ids/README.device.id + forth/device/.arch-ids/builtin.fs.id + forth/device/.arch-ids/device.fs.id + forth/device/.arch-ids/display.fs.id + forth/device/.arch-ids/extra.fs.id + forth/device/.arch-ids/fcode.fs.id + forth/device/.arch-ids/feval.fs.id + forth/device/.arch-ids/font.fs.id + forth/device/.arch-ids/logo.fs.id + forth/device/.arch-ids/missing.id + forth/device/.arch-ids/other.fs.id + forth/device/.arch-ids/package.fs.id + forth/device/.arch-ids/pathres.fs.id + forth/device/.arch-ids/preof.fs.id + forth/device/.arch-ids/property.fs.id + forth/device/.arch-ids/romfont.bin.id + forth/device/.arch-ids/structures.fs.id + forth/device/.arch-ids/table.fs.id + forth/device/.arch-ids/terminal.fs.id + forth/device/.arch-ids/tree.fs.id forth/device/Makefile + forth/device/README.device forth/device/builtin.fs + forth/device/device.fs forth/device/display.fs + forth/device/extra.fs forth/device/fcode.fs + forth/device/feval.fs forth/device/font.fs + forth/device/logo.fs forth/device/missing + forth/device/other.fs forth/device/package.fs + forth/device/pathres.fs forth/device/preof.fs + forth/device/property.fs forth/device/romfont.bin + forth/device/structures.fs forth/device/table.fs + forth/device/terminal.fs forth/device/tree.fs + forth/lib/.arch-ids/=id forth/lib/.arch-ids/Makefile.id + forth/lib/.arch-ids/creation.fs.id + forth/lib/.arch-ids/lists.fs.id + forth/lib/.arch-ids/preprocessor.fs.id + forth/lib/.arch-ids/split.fs.id + forth/lib/.arch-ids/string.fs.id + forth/lib/.arch-ids/vocabulary.fs.id forth/lib/Makefile + forth/lib/creation.fs forth/lib/lists.fs + forth/lib/preprocessor.fs forth/lib/split.fs + forth/lib/string.fs forth/lib/vocabulary.fs + forth/packages/.arch-ids/=id + forth/packages/.arch-ids/Kconfig.id + forth/packages/.arch-ids/Makefile.id + forth/packages/.arch-ids/README.id + forth/packages/.arch-ids/deblocker.fs.id + forth/packages/.arch-ids/disklabel.fs.id + forth/packages/.arch-ids/obp-tftp.fs.id + forth/packages/.arch-ids/packages.fs.id + forth/packages/.arch-ids/terminal-emulator.fs.id + forth/packages/Kconfig forth/packages/Makefile + forth/packages/README forth/packages/deblocker.fs + forth/packages/disklabel.fs forth/packages/obp-tftp.fs + forth/packages/packages.fs forth/packages/terminal-emulator.fs + forth/system/.arch-ids/=id forth/system/.arch-ids/Makefile.id + forth/system/.arch-ids/ciface.fs.id + forth/system/.arch-ids/main.fs.id forth/system/Makefile + forth/system/ciface.fs forth/system/main.fs + forth/testsuite/.arch-ids/=id + forth/testsuite/.arch-ids/Makefile.id + forth/testsuite/.arch-ids/README.id + forth/testsuite/.arch-ids/fract.fs.id + forth/testsuite/.arch-ids/framebuffer-test.fs.id + forth/testsuite/.arch-ids/memory-testsuite.fs.id + forth/testsuite/.arch-ids/splitfunc-testsuite.fs.id + forth/testsuite/Makefile forth/testsuite/README + forth/testsuite/fract.fs forth/testsuite/framebuffer-test.fs + forth/testsuite/memory-testsuite.fs + forth/testsuite/splitfunc-testsuite.fs + forth/util/.arch-ids/=id forth/util/.arch-ids/Makefile.id + forth/util/.arch-ids/apic.fs.id forth/util/.arch-ids/pci.fs.id + forth/util/.arch-ids/util.fs.id forth/util/Makefile + forth/util/apic.fs forth/util/pci.fs forth/util/util.fs + fs/.arch-ids/=id fs/.arch-ids/Makefile.id + fs/.arch-ids/hfs_mdb.h.id fs/.arch-ids/ioglue.c.id + fs/.arch-ids/os.h.id fs/Makefile fs/grubfs/.arch-ids/=id + fs/grubfs/.arch-ids/Kconfig.id fs/grubfs/.arch-ids/Makefile.id + fs/grubfs/.arch-ids/debug.h.id fs/grubfs/.arch-ids/defs.h.id + fs/grubfs/.arch-ids/dir.h.id + fs/grubfs/.arch-ids/disk_inode.h.id + fs/grubfs/.arch-ids/disk_inode_ffs.h.id + fs/grubfs/.arch-ids/fat.h.id fs/grubfs/.arch-ids/filesys.h.id + fs/grubfs/.arch-ids/fs.h.id fs/grubfs/.arch-ids/fsys_affs.c.id + fs/grubfs/.arch-ids/fsys_ext2fs.c.id + fs/grubfs/.arch-ids/fsys_fat.c.id + fs/grubfs/.arch-ids/fsys_ffs.c.id + fs/grubfs/.arch-ids/fsys_iso9660.c.id + fs/grubfs/.arch-ids/fsys_jfs.c.id + fs/grubfs/.arch-ids/fsys_minix.c.id + fs/grubfs/.arch-ids/fsys_ntfs.c.id + fs/grubfs/.arch-ids/fsys_reiserfs.c.id + fs/grubfs/.arch-ids/fsys_vstafs.c.id + fs/grubfs/.arch-ids/fsys_xfs.c.id + fs/grubfs/.arch-ids/glue.h.id + fs/grubfs/.arch-ids/grubfs_fs.c.id + fs/grubfs/.arch-ids/iso9660.h.id fs/grubfs/.arch-ids/jfs.h.id + fs/grubfs/.arch-ids/shared.h.id + fs/grubfs/.arch-ids/vstafs.h.id fs/grubfs/.arch-ids/xfs.h.id + fs/grubfs/Kconfig fs/grubfs/Makefile fs/grubfs/debug.h + fs/grubfs/defs.h fs/grubfs/dir.h fs/grubfs/disk_inode.h + fs/grubfs/disk_inode_ffs.h fs/grubfs/fat.h fs/grubfs/filesys.h + fs/grubfs/fs.h fs/grubfs/fsys_affs.c fs/grubfs/fsys_ext2fs.c + fs/grubfs/fsys_fat.c fs/grubfs/fsys_ffs.c + fs/grubfs/fsys_iso9660.c fs/grubfs/fsys_jfs.c + fs/grubfs/fsys_minix.c fs/grubfs/fsys_ntfs.c + fs/grubfs/fsys_reiserfs.c fs/grubfs/fsys_vstafs.c + fs/grubfs/fsys_xfs.c fs/grubfs/glue.h fs/grubfs/grubfs_fs.c + fs/grubfs/iso9660.h fs/grubfs/jfs.h fs/grubfs/shared.h + fs/grubfs/vstafs.h fs/grubfs/xfs.h fs/hfs/.arch-ids/=id + fs/hfs/.arch-ids/Makefile.id fs/hfs/.arch-ids/block.c.id + fs/hfs/.arch-ids/btree.c.id fs/hfs/.arch-ids/data.c.id + fs/hfs/.arch-ids/file.c.id fs/hfs/.arch-ids/hfs.c.id + fs/hfs/.arch-ids/hfs_fs.c.id fs/hfs/.arch-ids/low.c.id + fs/hfs/.arch-ids/medium.c.id fs/hfs/.arch-ids/node.c.id + fs/hfs/.arch-ids/record.c.id fs/hfs/.arch-ids/volume.c.id + fs/hfs/Makefile fs/hfs/block.c fs/hfs/btree.c fs/hfs/data.c + fs/hfs/file.c fs/hfs/hfs.c fs/hfs/hfs_fs.c + fs/hfs/include/.arch-ids/=id + fs/hfs/include/.arch-ids/apple.h.id + fs/hfs/include/.arch-ids/block.h.id + fs/hfs/include/.arch-ids/btree.h.id + fs/hfs/include/.arch-ids/data.h.id + fs/hfs/include/.arch-ids/file.h.id + fs/hfs/include/.arch-ids/hfs.h.id + fs/hfs/include/.arch-ids/libhfs.h.id + fs/hfs/include/.arch-ids/low.h.id + fs/hfs/include/.arch-ids/medium.h.id + fs/hfs/include/.arch-ids/node.h.id + fs/hfs/include/.arch-ids/record.h.id + fs/hfs/include/.arch-ids/volume.h.id fs/hfs/include/apple.h + fs/hfs/include/block.h fs/hfs/include/btree.h + fs/hfs/include/data.h fs/hfs/include/file.h + fs/hfs/include/hfs.h fs/hfs/include/libhfs.h + fs/hfs/include/low.h fs/hfs/include/medium.h + fs/hfs/include/node.h fs/hfs/include/record.h + fs/hfs/include/volume.h fs/hfs/low.c fs/hfs/medium.c + fs/hfs/node.c fs/hfs/record.c fs/hfs/volume.c fs/hfs_mdb.h + fs/hfsplus/.arch-ids/=id fs/hfsplus/.arch-ids/Makefile.id + fs/hfsplus/.arch-ids/blockiter.c.id + fs/hfsplus/.arch-ids/btree.c.id + fs/hfsplus/.arch-ids/hfsp_fs.c.id + fs/hfsplus/.arch-ids/libhfsp.c.id + fs/hfsplus/.arch-ids/record.c.id + fs/hfsplus/.arch-ids/unicode.c.id + fs/hfsplus/.arch-ids/volume.c.id fs/hfsplus/Makefile + fs/hfsplus/blockiter.c fs/hfsplus/btree.c fs/hfsplus/hfsp_fs.c + fs/hfsplus/include/.arch-ids/=id + fs/hfsplus/include/.arch-ids/apple.h.id + fs/hfsplus/include/.arch-ids/blockiter.h.id + fs/hfsplus/include/.arch-ids/btree.h.id + fs/hfsplus/include/.arch-ids/hfs.h.id + fs/hfsplus/include/.arch-ids/hfsp.h.id + fs/hfsplus/include/.arch-ids/hfstime.h.id + fs/hfsplus/include/.arch-ids/libhfsp.h.id + fs/hfsplus/include/.arch-ids/record.h.id + fs/hfsplus/include/.arch-ids/swab.h.id + fs/hfsplus/include/.arch-ids/unicode.h.id + fs/hfsplus/include/.arch-ids/volume.h.id + fs/hfsplus/include/apple.h fs/hfsplus/include/blockiter.h + fs/hfsplus/include/btree.h fs/hfsplus/include/hfs.h + fs/hfsplus/include/hfsp.h fs/hfsplus/include/hfstime.h + fs/hfsplus/include/libhfsp.h fs/hfsplus/include/record.h + fs/hfsplus/include/swab.h fs/hfsplus/include/unicode.h + fs/hfsplus/include/volume.h fs/hfsplus/libhfsp.c + fs/hfsplus/record.c fs/hfsplus/unicode.c fs/hfsplus/volume.c + fs/ioglue.c fs/os.h include/.arch-ids/=id + include/.arch-ids/elf_boot.h.id + include/.arch-ids/ipchecksum.h.id include/.arch-ids/ofmem.h.id + include/.arch-ids/sys_info.h.id include/amd64/.arch-ids/=id + include/amd64/.arch-ids/elf.h.id + include/amd64/.arch-ids/io.h.id + include/amd64/.arch-ids/types.h.id include/amd64/elf.h + include/amd64/io.h include/amd64/types.h include/elf_boot.h + include/ia64/.arch-ids/=id include/ia64/.arch-ids/elf.h.id + include/ia64/.arch-ids/io.h.id + include/ia64/.arch-ids/types.h.id include/ia64/elf.h + include/ia64/io.h include/ia64/types.h include/ipchecksum.h + include/libc/.arch-ids/=id + include/libc/.arch-ids/byteorder.h.id + include/libc/.arch-ids/diskio.h.id + include/libc/.arch-ids/stdlib.h.id + include/libc/.arch-ids/string.h.id + include/libc/.arch-ids/vsprintf.h.id include/libc/byteorder.h + include/libc/diskio.h include/libc/stdlib.h + include/libc/string.h include/libc/vsprintf.h include/ofmem.h + include/openbios/.arch-ids/=id + include/openbios/.arch-ids/asm.m4.id + include/openbios/.arch-ids/bindings.h.id + include/openbios/.arch-ids/config.h.id + include/openbios/.arch-ids/drivers.h.id + include/openbios/.arch-ids/elf.h.id + include/openbios/.arch-ids/elfload.h.id + include/openbios/.arch-ids/fs.h.id + include/openbios/.arch-ids/kernel.h.id + include/openbios/.arch-ids/nvram.h.id + include/openbios/.arch-ids/of.h.id + include/openbios/.arch-ids/stack.h.id + include/openbios/.arch-ids/sysinclude.h.id + include/openbios/asm.m4 include/openbios/bindings.h + include/openbios/config.h include/openbios/drivers.h + include/openbios/elf.h include/openbios/elfload.h + include/openbios/fs.h include/openbios/kernel.h + include/openbios/nvram.h include/openbios/of.h + include/openbios/stack.h include/openbios/sysinclude.h + include/ppc/.arch-ids/=id include/ppc/.arch-ids/asmdefs.h.id + include/ppc/.arch-ids/elf.h.id include/ppc/.arch-ids/io.h.id + include/ppc/.arch-ids/processor.h.id + include/ppc/.arch-ids/types.h.id include/ppc/asmdefs.h + include/ppc/elf.h include/ppc/io.h include/ppc/processor.h + include/ppc/types.h include/sys_info.h + include/unix/.arch-ids/=id + include/unix/.arch-ids/plugin_pci.h.id + include/unix/.arch-ids/plugins.h.id include/unix/plugin_pci.h + include/unix/plugins.h include/x86/.arch-ids/=id + include/x86/.arch-ids/elf.h.id include/x86/.arch-ids/io.h.id + include/x86/.arch-ids/pci.h.id + include/x86/.arch-ids/types.h.id include/x86/elf.h + include/x86/io.h include/x86/pci.h include/x86/types.h + kernel/.arch-ids/=id kernel/.arch-ids/Kconfig.id + kernel/.arch-ids/Makefile.id kernel/.arch-ids/README.id + kernel/.arch-ids/bootstrap.c.id kernel/.arch-ids/dict.c.id + kernel/.arch-ids/forth.c.id kernel/.arch-ids/internal.c.id + kernel/.arch-ids/primitives.c.id kernel/.arch-ids/stack.c.id + kernel/Kconfig kernel/Makefile kernel/README + kernel/bootstrap.c kernel/dict.c kernel/forth.c + kernel/include/.arch-ids/=id + kernel/include/.arch-ids/dict.h.id kernel/include/dict.h + kernel/internal.c kernel/primitives.c kernel/stack.c + libc/.arch-ids/=id libc/.arch-ids/Makefile.id + libc/.arch-ids/byteorder.c.id libc/.arch-ids/ctype.c.id + libc/.arch-ids/diskio.c.id libc/.arch-ids/extra.c.id + libc/.arch-ids/misc.c.id libc/.arch-ids/string.c.id + libc/.arch-ids/vsprintf.c.id libc/Makefile libc/byteorder.c + libc/ctype.c libc/diskio.c libc/extra.c libc/misc.c + libc/string.c libc/vsprintf.c modules/.arch-ids/=id + modules/.arch-ids/Kconfig.id modules/.arch-ids/Makefile.id + modules/.arch-ids/bindings.c.id modules/.arch-ids/clib.fs.id + modules/.arch-ids/client.c.id modules/.arch-ids/cmdline.c.id + modules/.arch-ids/deblocker.c.id + modules/.arch-ids/disk-label.c.id + modules/.arch-ids/elfload.c.id modules/.arch-ids/elfnote.c.id + modules/.arch-ids/filesystems.c.id + modules/.arch-ids/helpers.fs.id modules/.arch-ids/init.c.id + modules/.arch-ids/ipchecksum.c.id + modules/.arch-ids/linuxbios.c.id + modules/.arch-ids/linuxbios.h.id + modules/.arch-ids/mac-parts.c.id + modules/.arch-ids/mac-parts.h.id + modules/.arch-ids/modules.h.id modules/.arch-ids/nvram.c.id + modules/.arch-ids/pc-parts.c.id + modules/.arch-ids/support.fs.id modules/Kconfig + modules/Makefile modules/bindings.c modules/clib.fs + modules/client.c modules/cmdline.c modules/deblocker.c + modules/disk-label.c modules/elfload.c modules/elfnote.c + modules/filesystems.c modules/helpers.fs modules/init.c + modules/ipchecksum.c modules/linuxbios.c modules/linuxbios.h + modules/mac-parts.c modules/mac-parts.h modules/modules.h + modules/nvram.c modules/pc-parts.c modules/support.fs + setup_links toke/.arch-ids/=id toke/.arch-ids/COPYING.id + toke/.arch-ids/ChangeLog.id toke/.arch-ids/Makefile.id + toke/.arch-ids/README.id toke/.arch-ids/Rules.make.id + toke/.arch-ids/TODO.id toke/.arch-ids/dictionary.c.id + toke/.arch-ids/dictionary.h.id toke/.arch-ids/emit.c.id + toke/.arch-ids/emit.h.id toke/.arch-ids/macros.c.id + toke/.arch-ids/scanner.c.id toke/.arch-ids/stack.c.id + toke/.arch-ids/stack.h.id toke/.arch-ids/stream.c.id + toke/.arch-ids/stream.h.id toke/.arch-ids/toke.c.id + toke/.arch-ids/toke.h.id toke/COPYING toke/ChangeLog + toke/Makefile toke/README toke/Rules.make toke/TODO + toke/dictionary.c toke/dictionary.h toke/emit.c toke/emit.h + toke/examples/.arch-ids/=id toke/examples/.arch-ids/case.fs.id + toke/examples/.arch-ids/date.fs.id + toke/examples/.arch-ids/display.fs.id + toke/examples/.arch-ids/fcdisp.fs.id + toke/examples/.arch-ids/fract.fs.id + toke/examples/.arch-ids/pciexample.fs.id + toke/examples/.arch-ids/primes.fs.id + toke/examples/.arch-ids/simple.fs.id + toke/examples/.arch-ids/version1.fs.id + toke/examples/.arch-ids/world.fs.id toke/examples/case.fs + toke/examples/date.fs toke/examples/display.fs + toke/examples/fcdisp.fs toke/examples/fract.fs + toke/examples/pciexample.fs toke/examples/primes.fs + toke/examples/scsi-sample/.arch-ids/=id + toke/examples/scsi-sample/.arch-ids/README.sample.id + toke/examples/scsi-sample/.arch-ids/hacom.fs.id + toke/examples/scsi-sample/.arch-ids/overall.fs.id + toke/examples/scsi-sample/.arch-ids/scsicom.fs.id + toke/examples/scsi-sample/.arch-ids/scsidisk.fs.id + toke/examples/scsi-sample/.arch-ids/scsiha.fs.id + toke/examples/scsi-sample/.arch-ids/scsitape.fs.id + toke/examples/scsi-sample/README.sample + toke/examples/scsi-sample/hacom.fs + toke/examples/scsi-sample/overall.fs + toke/examples/scsi-sample/scsicom.fs + toke/examples/scsi-sample/scsidisk.fs + toke/examples/scsi-sample/scsiha.fs + toke/examples/scsi-sample/scsitape.fs toke/examples/simple.fs + toke/examples/version1.fs toke/examples/world.fs toke/macros.c + toke/scanner.c toke/stack.c toke/stack.h toke/stream.c + toke/stream.h toke/toke.c toke/toke.h utils/.arch-ids/=id + utils/.arch-ids/README.id utils/README + utils/detok/.arch-ids/=id utils/detok/.arch-ids/COPYING.id + utils/detok/.arch-ids/ChangeLog.id + utils/detok/.arch-ids/Makefile.id + utils/detok/.arch-ids/README.id + utils/detok/.arch-ids/Rules.make.id + utils/detok/.arch-ids/decode.c.id + utils/detok/.arch-ids/detok.c.id + utils/detok/.arch-ids/detok.h.id + utils/detok/.arch-ids/dictionary.c.id + utils/detok/.arch-ids/stream.c.id + utils/detok/.arch-ids/stream.h.id utils/detok/COPYING + utils/detok/ChangeLog utils/detok/Makefile utils/detok/README + utils/detok/Rules.make utils/detok/decode.c + utils/detok/detok.c utils/detok/detok.h + utils/detok/dictionary.c utils/detok/stream.c + utils/detok/stream.h utils/devbios/.arch-ids/=id + utils/devbios/.arch-ids/COPYING.id + utils/devbios/.arch-ids/CREDITS.id + utils/devbios/.arch-ids/ChangeLog.id + utils/devbios/.arch-ids/Makefile.24.id + utils/devbios/.arch-ids/Makefile.id + utils/devbios/.arch-ids/README.bios.id + utils/devbios/.arch-ids/ToDo.id + utils/devbios/.arch-ids/bios.h.id + utils/devbios/.arch-ids/bios_core.c.id + utils/devbios/.arch-ids/comp.c.id + utils/devbios/.arch-ids/filesystem.c.id + utils/devbios/.arch-ids/flashchips.c.id + utils/devbios/.arch-ids/flashchips.h.id + utils/devbios/.arch-ids/pcisets.c.id + utils/devbios/.arch-ids/pcisets.h.id + utils/devbios/.arch-ids/procfs.c.id + utils/devbios/.arch-ids/programming.c.id + utils/devbios/.arch-ids/programming.h.id utils/devbios/COPYING + utils/devbios/CREDITS utils/devbios/ChangeLog + utils/devbios/Makefile utils/devbios/Makefile.24 + utils/devbios/README.bios utils/devbios/ToDo + utils/devbios/bios.h utils/devbios/bios_core.c + utils/devbios/comp.c utils/devbios/filesystem.c + utils/devbios/flashchips.c utils/devbios/flashchips.h + utils/devbios/pcisets.c utils/devbios/pcisets.h + utils/devbios/procfs.c utils/devbios/programming.c + utils/devbios/programming.h utils/fccc/.arch-ids/=id + utils/fccc/.arch-ids/COPYING.id utils/fccc/COPYING + utils/fccc/include/.arch-ids/=id + utils/fccc/include/.arch-ids/fccc-tools.h.id + utils/fccc/include/.arch-ids/fccc.h.id + utils/fccc/include/.arch-ids/linklist.h.id + utils/fccc/include/.arch-ids/parserfunctions.h.id + utils/fccc/include/.arch-ids/symboltable.h.id + utils/fccc/include/fccc-tools.h utils/fccc/include/fccc.h + utils/fccc/include/linklist.h + utils/fccc/include/parserfunctions.h + utils/fccc/include/symboltable.h utils/fccc/src/.arch-ids/=id + utils/fccc/src/.arch-ids/Makefile.id + utils/fccc/src/.arch-ids/fccc-tools.c.id + utils/fccc/src/.arch-ids/fccc.lex.id + utils/fccc/src/.arch-ids/fccc.y.id + utils/fccc/src/.arch-ids/linklist.c.id + utils/fccc/src/.arch-ids/plain_ass.c.id + utils/fccc/src/.arch-ids/symboltable.c.id + utils/fccc/src/Makefile utils/fccc/src/fccc-tools.c + utils/fccc/src/fccc.lex utils/fccc/src/fccc.y + utils/fccc/src/linklist.c utils/fccc/src/plain_ass.c + utils/fccc/src/symboltable.c utils/fccc/test/.arch-ids/=id + utils/fccc/test/.arch-ids/test1.c.id utils/fccc/test/test1.c + utils/romheaders/.arch-ids/=id + utils/romheaders/.arch-ids/Makefile.id + utils/romheaders/.arch-ids/romheaders.c.id + utils/romheaders/Makefile utils/romheaders/romheaders.c + {arch}/.arch-project-tree {arch}/=tagging-method + {arch}/openbios/openbios--main/openbios--main--1.0/stepan@openbios.org--devel/patch-log/base-0 + {arch}/openbios/openbios--porting/openbios--porting--0/oxygene@studentenbude.ath.cx--2004/patch-log/base-0 + {arch}/openbios/openbios--porting/openbios--porting--0/oxygene@studentenbude.ath.cx--2004/patch-log/patch-1 + {arch}/openbios/openbios--porting/openbios--porting--0/oxygene@studentenbude.ath.cx--2004/patch-log/patch-2 + {arch}/openbios/openbios--porting/openbios--porting--0/oxygene@studentenbude.ath.cx--2004/patch-log/patch-3 + + modified directories: + .arch-ids Documentation/.arch-ids + Documentation/kernel/.arch-ids arch/.arch-ids + arch/amd64/.arch-ids arch/ia64/.arch-ids arch/ppc/.arch-ids + arch/ppc/briq/.arch-ids arch/ppc/mol/.arch-ids + arch/unix/.arch-ids arch/unix/gui_qt/.arch-ids + arch/unix/plugins/.arch-ids + arch/unix/plugins/plugin_pci/.arch-ids + arch/unix/plugins/plugin_qt/.arch-ids arch/x86/.arch-ids + config/.arch-ids config/kconfig/.arch-ids + config/lxdialog/.arch-ids config/scripts/.arch-ids + dist/.arch-ids dist/debian/.arch-ids drivers/.arch-ids + forth/.arch-ids forth/admin/.arch-ids + forth/bootstrap/.arch-ids forth/debugging/.arch-ids + forth/device/.arch-ids forth/lib/.arch-ids + forth/packages/.arch-ids forth/system/.arch-ids + forth/testsuite/.arch-ids forth/util/.arch-ids fs/.arch-ids + fs/grubfs/.arch-ids fs/hfs/.arch-ids fs/hfs/include/.arch-ids + fs/hfsplus/.arch-ids fs/hfsplus/include/.arch-ids + include/.arch-ids include/amd64/.arch-ids + include/ia64/.arch-ids include/libc/.arch-ids + include/openbios/.arch-ids include/ppc/.arch-ids + include/unix/.arch-ids include/x86/.arch-ids kernel/.arch-ids + kernel/include/.arch-ids libc/.arch-ids modules/.arch-ids + toke/.arch-ids toke/examples/.arch-ids + toke/examples/scsi-sample/.arch-ids utils/.arch-ids + utils/detok/.arch-ids utils/devbios/.arch-ids + utils/fccc/.arch-ids utils/fccc/include/.arch-ids + utils/fccc/src/.arch-ids utils/fccc/test/.arch-ids + utils/romheaders/.arch-ids {arch} {arch}/openbios + {arch}/openbios/openbios--main + {arch}/openbios/openbios--main/openbios--main--1.0 + {arch}/openbios/openbios--main/openbios--main--1.0/stepan@openbios.org--devel + {arch}/openbios/openbios--main/openbios--main--1.0/stepan@openbios.org--devel/patch-log + {arch}/openbios/openbios--porting + {arch}/openbios/openbios--porting/openbios--porting--0 + {arch}/openbios/openbios--porting/openbios--porting--0/oxygene@studentenbude.ath.cx--2004 + {arch}/openbios/openbios--porting/openbios--porting--0/oxygene@studentenbude.ath.cx--2004/patch-log + + new patches: + oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-4 + + +2004-09-01 19:03:41 GMT Stefan Reinauer patch-1 + + Summary: + + Revision: + openbios--main--1.0--patch-1 + + + + Patches applied: + + * oxygene@studentenbude.ath.cx--2004/openbios--porting--0--base-0 + tag of stepan@openbios.org--devel/openbios--main--1.0--base-0 + + * oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-1 + changes to make it build on dragonflybsd + + * oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-2 + no need for the uue hack anymore + + * oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-3 + check for stack protector for gcc and disable if present + + + new files: + forth/device/.arch-ids/romfont.bin.id forth/device/romfont.bin + + removed files: + forth/device/.arch-ids/romfont.uue.id forth/device/romfont.uue + + modified files: + Documentation/ChangeLog.arch arch/unix/unix.c + arch/x86/builtin.c config/configure.in drivers/ide.h + forth/device/Makefile include/openbios/kernel.h + include/x86/types.h {arch}/=tagging-method + + new patches: + oxygene@studentenbude.ath.cx--2004/openbios--porting--0--base-0 + oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-1 + oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-2 + oxygene@studentenbude.ath.cx--2004/openbios--porting--0--patch-3 + + +2004-08-29 13:29:22 GMT Stefan Reinauer base-0 + + Summary: + initial import + Revision: + openbios--main--1.0--base-0 + + + (automatically generated log message) + + new files: + COPYING Documentation/ChangeLog.arch + Documentation/kernel/AUTHORS Documentation/kernel/COPYING + Documentation/kernel/Changelog.stepan + Documentation/kernel/TODO Documentation/kernel/dictformat.txt + Documentation/kernel/glossary.txt + Documentation/kernel/initializers.txt Makefile README + arch/amd64/Kconfig arch/amd64/Makefile arch/amd64/Makefile.asm + arch/amd64/boot.c arch/amd64/builtin.c arch/amd64/console.c + arch/amd64/context.c arch/amd64/context.h arch/amd64/defconfig + arch/amd64/elfload.c arch/amd64/init.fs arch/amd64/ldscript + arch/amd64/lib.c arch/amd64/linux_load.c arch/amd64/loadfs.c + arch/amd64/loadfs.h arch/amd64/multiboot.c + arch/amd64/multiboot.h arch/amd64/openbios.c + arch/amd64/openbios.h arch/amd64/plainboot.c + arch/amd64/relocate.h arch/amd64/segment.c + arch/amd64/segment.h arch/amd64/switch.S arch/amd64/sys_info.c + arch/ia64/Kconfig arch/ia64/Makefile arch/ia64/Makefile.asm + arch/ia64/defconfig arch/ia64/init.fs arch/ppc/Kconfig + arch/ppc/Makefile arch/ppc/Makefile.asm arch/ppc/briq/briq.c + arch/ppc/briq/briq.fs arch/ppc/briq/briq.h + arch/ppc/briq/init.c arch/ppc/briq/kernel.c + arch/ppc/briq/main.c arch/ppc/briq/methods.c + arch/ppc/briq/tree.c arch/ppc/briq/tree.fs arch/ppc/briq/vfd.c + arch/ppc/defconfig arch/ppc/kernel.c arch/ppc/kernel.h + arch/ppc/misc.S arch/ppc/mmutypes.h arch/ppc/mol/console.c + arch/ppc/mol/font_8x8.c arch/ppc/mol/init.c + arch/ppc/mol/kernel.c arch/ppc/mol/main.c + arch/ppc/mol/methods.c arch/ppc/mol/mol.c arch/ppc/mol/mol.fs + arch/ppc/mol/mol.h arch/ppc/mol/osi-blk.c + arch/ppc/mol/osi-scsi.c arch/ppc/mol/prom.c + arch/ppc/mol/prom.h arch/ppc/mol/pseudodisk.c + arch/ppc/mol/tree.c arch/ppc/mol/tree.fs arch/ppc/mol/video.c + arch/ppc/ofmem.c arch/ppc/osi.h arch/ppc/osi_calls.h + arch/ppc/ppc.fs arch/ppc/start.S arch/ppc/timebase.S + arch/unix/Kconfig arch/unix/Makefile arch/unix/blk.c + arch/unix/blk.h arch/unix/boot.c arch/unix/gui_qt/Makefile + arch/unix/gui_qt/gui-qt.cpp arch/unix/gui_qt/gui-qt.h + arch/unix/gui_qt/gui-qt.pro arch/unix/gui_qt/logo.xpm + arch/unix/gui_qt/qt-main.cpp arch/unix/plugins.c + arch/unix/plugins/Kconfig arch/unix/plugins/Makefile + arch/unix/plugins/Rules.plugin arch/unix/plugins/loader.c + arch/unix/plugins/plugin_pci/Makefile + arch/unix/plugins/plugin_pci/Makefile.old + arch/unix/plugins/plugin_pci/plugin_pci.c + arch/unix/plugins/plugin_qt/Makefile + arch/unix/plugins/plugin_qt/logo.xpm + arch/unix/plugins/plugin_qt/pciconfig.h + arch/unix/plugins/plugin_qt/plugin_qt.cpp + arch/unix/plugins/plugin_qt/plugin_qt.h + arch/unix/plugins/plugin_qt/plugin_qt.pro + arch/unix/plugins/plugin_qt/qt_main.cpp + arch/unix/plugins/plugin_qt/qt_rom.fs arch/unix/tree.fs + arch/unix/unix.c arch/x86/Kconfig arch/x86/Makefile + arch/x86/Makefile.asm arch/x86/boot.c arch/x86/boot.h + arch/x86/builtin.c arch/x86/console.c arch/x86/context.c + arch/x86/context.h arch/x86/defconfig arch/x86/elfload.c + arch/x86/forthload.c arch/x86/init.fs arch/x86/ldscript + arch/x86/lib.c arch/x86/linux_load.c arch/x86/loadfs.c + arch/x86/loadfs.h arch/x86/multiboot.c arch/x86/multiboot.h + arch/x86/openbios.c arch/x86/openbios.h arch/x86/plainboot.c + arch/x86/relocate.h arch/x86/segment.c arch/x86/segment.h + arch/x86/switch.S arch/x86/sys_info.c autogen.sh + config/Makefile config/Makefile.defs.in config/Makefile.master + config/Makefile.top config/Rules.forth config/Rules.make + config/configure.in config/kconfig/Makefile + config/kconfig/conf.c config/kconfig/confdata.c + config/kconfig/expr.c config/kconfig/expr.h + config/kconfig/lkc.h config/kconfig/lkc_proto.h + config/kconfig/mconf.c config/kconfig/menu.c + config/kconfig/symbol.c config/kconfig/zconf-l.l + config/kconfig/zconf-y.y config/lxdialog/Makefile + config/lxdialog/checklist.c config/lxdialog/colors.h + config/lxdialog/dialog.h config/lxdialog/inputbox.c + config/lxdialog/lxdialog.c config/lxdialog/menubox.c + config/lxdialog/msgbox.c config/lxdialog/textbox.c + config/lxdialog/util.c config/lxdialog/yesno.c + config/scripts/archname config/scripts/reldir configure + dist/debian/changelog dist/debian/control dist/debian/packages + dist/debian/rules dist/openbios.spec drivers/Kconfig + drivers/Makefile drivers/hdreg.h drivers/ide.c drivers/ide.fs + drivers/ide.h drivers/pci.c drivers/pci.fs drivers/pci.h + drivers/timer.c drivers/timer.h forth/Kconfig forth/Makefile + forth/admin/Makefile forth/admin/README forth/admin/banner.fs + forth/admin/callback.fs forth/admin/devices.fs + forth/admin/help.fs forth/admin/iocontrol.fs + forth/admin/nvram.fs forth/admin/reset.fs + forth/admin/script.fs forth/admin/security.fs + forth/admin/selftest.fs forth/admin/userboot.fs + forth/bootstrap/bootstrap.fs forth/bootstrap/builtin.fs + forth/bootstrap/hayes.fs forth/bootstrap/interpreter.fs + forth/bootstrap/memory.fs forth/bootstrap/start.fs + forth/debugging/Makefile forth/debugging/client.fs + forth/debugging/fcode.fs forth/debugging/firmware.fs + forth/debugging/see.fs forth/device/Makefile + forth/device/README.device forth/device/builtin.fs + forth/device/device.fs forth/device/display.fs + forth/device/extra.fs forth/device/fcode.fs + forth/device/feval.fs forth/device/font.fs + forth/device/logo.fs forth/device/missing + forth/device/other.fs forth/device/package.fs + forth/device/pathres.fs forth/device/preof.fs + forth/device/property.fs forth/device/romfont.uue + forth/device/structures.fs forth/device/table.fs + forth/device/terminal.fs forth/device/tree.fs + forth/lib/Makefile forth/lib/creation.fs forth/lib/lists.fs + forth/lib/preprocessor.fs forth/lib/split.fs + forth/lib/string.fs forth/lib/vocabulary.fs + forth/packages/Kconfig forth/packages/Makefile + forth/packages/README forth/packages/deblocker.fs + forth/packages/disklabel.fs forth/packages/obp-tftp.fs + forth/packages/packages.fs forth/packages/terminal-emulator.fs + forth/system/Makefile forth/system/ciface.fs + forth/system/main.fs forth/testsuite/Makefile + forth/testsuite/README forth/testsuite/fract.fs + forth/testsuite/framebuffer-test.fs + forth/testsuite/memory-testsuite.fs + forth/testsuite/splitfunc-testsuite.fs forth/util/Makefile + forth/util/apic.fs forth/util/pci.fs forth/util/util.fs + fs/Makefile fs/grubfs/Kconfig fs/grubfs/Makefile + fs/grubfs/debug.h fs/grubfs/defs.h fs/grubfs/dir.h + fs/grubfs/disk_inode.h fs/grubfs/disk_inode_ffs.h + fs/grubfs/fat.h fs/grubfs/filesys.h fs/grubfs/fs.h + fs/grubfs/fsys_affs.c fs/grubfs/fsys_ext2fs.c + fs/grubfs/fsys_fat.c fs/grubfs/fsys_ffs.c + fs/grubfs/fsys_iso9660.c fs/grubfs/fsys_jfs.c + fs/grubfs/fsys_minix.c fs/grubfs/fsys_ntfs.c + fs/grubfs/fsys_reiserfs.c fs/grubfs/fsys_vstafs.c + fs/grubfs/fsys_xfs.c fs/grubfs/glue.h fs/grubfs/grubfs_fs.c + fs/grubfs/iso9660.h fs/grubfs/jfs.h fs/grubfs/shared.h + fs/grubfs/vstafs.h fs/grubfs/xfs.h fs/hfs/Makefile + fs/hfs/block.c fs/hfs/btree.c fs/hfs/data.c fs/hfs/file.c + fs/hfs/hfs.c fs/hfs/hfs_fs.c fs/hfs/include/apple.h + fs/hfs/include/block.h fs/hfs/include/btree.h + fs/hfs/include/data.h fs/hfs/include/file.h + fs/hfs/include/hfs.h fs/hfs/include/libhfs.h + fs/hfs/include/low.h fs/hfs/include/medium.h + fs/hfs/include/node.h fs/hfs/include/record.h + fs/hfs/include/volume.h fs/hfs/low.c fs/hfs/medium.c + fs/hfs/node.c fs/hfs/record.c fs/hfs/volume.c fs/hfs_mdb.h + fs/hfsplus/Makefile fs/hfsplus/blockiter.c fs/hfsplus/btree.c + fs/hfsplus/hfsp_fs.c fs/hfsplus/include/apple.h + fs/hfsplus/include/blockiter.h fs/hfsplus/include/btree.h + fs/hfsplus/include/hfs.h fs/hfsplus/include/hfsp.h + fs/hfsplus/include/hfstime.h fs/hfsplus/include/libhfsp.h + fs/hfsplus/include/record.h fs/hfsplus/include/swab.h + fs/hfsplus/include/unicode.h fs/hfsplus/include/volume.h + fs/hfsplus/libhfsp.c fs/hfsplus/record.c fs/hfsplus/unicode.c + fs/hfsplus/volume.c fs/ioglue.c fs/os.h include/amd64/elf.h + include/amd64/io.h include/amd64/types.h include/elf_boot.h + include/ia64/elf.h include/ia64/io.h include/ia64/types.h + include/ipchecksum.h include/libc/byteorder.h + include/libc/diskio.h include/libc/stdlib.h + include/libc/string.h include/libc/vsprintf.h include/ofmem.h + include/openbios/asm.m4 include/openbios/bindings.h + include/openbios/config.h include/openbios/drivers.h + include/openbios/elf.h include/openbios/elfload.h + include/openbios/fs.h include/openbios/kernel.h + include/openbios/nvram.h include/openbios/of.h + include/openbios/stack.h include/openbios/sysinclude.h + include/ppc/asmdefs.h include/ppc/elf.h include/ppc/io.h + include/ppc/processor.h include/ppc/types.h include/sys_info.h + include/unix/plugin_pci.h include/unix/plugins.h + include/x86/elf.h include/x86/io.h include/x86/pci.h + include/x86/types.h kernel/Kconfig kernel/Makefile + kernel/README kernel/bootstrap.c kernel/dict.c kernel/forth.c + kernel/include/dict.h kernel/internal.c kernel/primitives.c + kernel/stack.c libc/Makefile libc/byteorder.c libc/ctype.c + libc/diskio.c libc/extra.c libc/misc.c libc/string.c + libc/vsprintf.c modules/Kconfig modules/Makefile + modules/bindings.c modules/clib.fs modules/client.c + modules/cmdline.c modules/deblocker.c modules/disk-label.c + modules/elfload.c modules/elfnote.c modules/filesystems.c + modules/helpers.fs modules/init.c modules/ipchecksum.c + modules/linuxbios.c modules/linuxbios.h modules/mac-parts.c + modules/mac-parts.h modules/modules.h modules/nvram.c + modules/pc-parts.c modules/support.fs setup_links toke/COPYING + toke/ChangeLog toke/Makefile toke/README toke/Rules.make + toke/TODO toke/dictionary.c toke/dictionary.h toke/emit.c + toke/emit.h toke/examples/case.fs toke/examples/date.fs + toke/examples/display.fs toke/examples/fcdisp.fs + toke/examples/fract.fs toke/examples/pciexample.fs + toke/examples/primes.fs + toke/examples/scsi-sample/README.sample + toke/examples/scsi-sample/hacom.fs + toke/examples/scsi-sample/overall.fs + toke/examples/scsi-sample/scsicom.fs + toke/examples/scsi-sample/scsidisk.fs + toke/examples/scsi-sample/scsiha.fs + toke/examples/scsi-sample/scsitape.fs toke/examples/simple.fs + toke/examples/version1.fs toke/examples/world.fs toke/macros.c + toke/scanner.c toke/stack.c toke/stack.h toke/stream.c + toke/stream.h toke/toke.c toke/toke.h utils/README + utils/detok/COPYING utils/detok/ChangeLog utils/detok/Makefile + utils/detok/README utils/detok/Rules.make utils/detok/decode.c + utils/detok/detok.c utils/detok/detok.h + utils/detok/dictionary.c utils/detok/stream.c + utils/detok/stream.h utils/devbios/COPYING + utils/devbios/CREDITS utils/devbios/ChangeLog + utils/devbios/Makefile utils/devbios/Makefile.24 + utils/devbios/README.bios utils/devbios/ToDo + utils/devbios/bios.h utils/devbios/bios_core.c + utils/devbios/comp.c utils/devbios/filesystem.c + utils/devbios/flashchips.c utils/devbios/flashchips.h + utils/devbios/pcisets.c utils/devbios/pcisets.h + utils/devbios/procfs.c utils/devbios/programming.c + utils/devbios/programming.h utils/fccc/COPYING + utils/fccc/include/fccc-tools.h utils/fccc/include/fccc.h + utils/fccc/include/linklist.h + utils/fccc/include/parserfunctions.h + utils/fccc/include/symboltable.h utils/fccc/src/Makefile + utils/fccc/src/fccc-tools.c utils/fccc/src/fccc.lex + utils/fccc/src/fccc.y utils/fccc/src/linklist.c + utils/fccc/src/plain_ass.c utils/fccc/src/symboltable.c + utils/fccc/test/test1.c utils/romheaders/Makefile + utils/romheaders/romheaders.c + + diff --git a/Documentation/kernel/AUTHORS b/Documentation/kernel/AUTHORS new file mode 100644 index 0000000..365e098 --- /dev/null +++ b/Documentation/kernel/AUTHORS @@ -0,0 +1,6 @@ +The OpenBIOS forth engine was written by + + Patrick Mauritz + Stefan Reinauer + +# tag: list of authors diff --git a/Documentation/kernel/COPYING b/Documentation/kernel/COPYING new file mode 100644 index 0000000..91f234f --- /dev/null +++ b/Documentation/kernel/COPYING @@ -0,0 +1,358 @@ +All or most of the source files in this distribution refer to this +file for copyright and warranty information. This file should be +included whenever those files are redistributed. + +This software is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License, version 2, as +published by the Free Software Foundation. This license is reproduced +below. + +Please note that we explicitely do not allow applying any newer version +of the GPL to this work. Once the FSF releases such a revision we will +reconsider to allow it as well. + +----------------- verbatim license text below --------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +# tag: General Public License text +# diff --git a/Documentation/kernel/Changelog.stepan b/Documentation/kernel/Changelog.stepan new file mode 100644 index 0000000..1b4d534 --- /dev/null +++ b/Documentation/kernel/Changelog.stepan @@ -0,0 +1,300 @@ +# tag: stepan's changelog for CVS + +Mon Jul 14 02:16:49 CEST 2003 + - fix segv overrun while dumping dictionary in unix.c + - implement first version of >number and $number + - add stack diagram to digit + - no newline after accept + - new version of the interpreter + - fix make run target + +Mon Jul 14 20:15:40 CEST 2003 + - negate true value in prims + - get rid of primitive word bounds. + - get rid of some obsolete code. + - implement io[cwl][@!] + - reorganize [in|out][bwl] + - start adding stack diagrams to primitives. + +Mon Jul 14 23:57:46 CEST 2003 + - added some more stack diagrams in forth.h + - move parse, parse-word, word to bootstrap.fs + - include memory.fs from bootstrap.fs for above. + +Wed Jul 16 22:57:31 CEST 2003 + - add include guards + - add banner + - fix primitives' dependencies + +Sun Jul 20 03:27:40 CEST 2003 + - remove unneeded readcell + - rename ' to ['] to meet specs + +Sun Jul 20 14:08:43 CEST 2003 + - add rest of stack diagrams in forth.h + - move here and here! to forth.h (from internal.h) + - indent includes + - merge system.h into forth.h + - Change tag of forth.h (!) because the old one + did not meet the meaning of the code. + - update comments in primitives.c + +Sun Jul 27 01:53:18 CEST 2003 + - include great new do/?do/loop/+loop + implementation from Patrick. + - include testsuite enhancement from Patrick + - include trampoline from Patrick (fixes execute) + +Sun Jul 27 21:11:50 CEST 2003 + - update x86 console code to become when using + multiboot (vga/keyboard). + - fix exit properly + - revert to old case..endcase code + - fix >number and $number + - add number parsing to interpreter + - add simple stack checking to interpreter + - add 2 testcases (exit and case2) + +Mon Jul 28 14:49:31 CEST 2003 + - move 7.3.7 Flag constants up in bootstrap.fs + - move 7.3.9.2.4 Miscellaneous dictionary down. + - add reveal, recursive, recurse, environment? to 7.3.9.2.4 + - move (to) to bootstrap.fs + +Mon Jul 28 17:08:58 CEST 2003 + - add stack overflow check to interpreter + - check parse-word result in interpreter. + - add ascii and char, add helper handle-lit + +Tue Jul 29 09:20:18 CEST 2003 + - add s" and ." + - add [char] and control + - heavily move around words in bootstrap.fs + to get dependencies resolved. + - fix skipws crash + - rename query to refill + - interpreter reads several words in a line now + - interpreter stops now if error encountered in + currently parsed line. + - add forth definitions of ( and \ + - change c parser/interpreter to handle comments + correctly. + - indent, clean up unix.c + +Tue Jul 29 18:13:27 CEST 2003 + - add .( (chapter 7.3.4.4) + - add pack, -trailing (chapter 7.3.4.8) + - add d#, h#, o# (chapter 7.3.5.2) + - let first stack element start at 1 instead of 0 + to have a 1 cell guard band. + - set SA_NODEFER flag to signal handler to ensure + that it is entered recursively. + +Tue Jul 29 19:06:18 CEST 2003 + - more simplification for unix.c + - add ', ['], find + - fix pack, count + - add literal, compile, [compile], compile, + - fix [ + +Wed Jul 30 01:24:24 CEST 2003 + - add >body, body> + - add helpers: flags?, immediate?, compile-only?, header + - add :, ;, constant, value, variable, buffer: + - parse word's flags in interpreter to make colon + definitions work + - add "compiled" acknowledge when interpreter is in compile mode + +Wed Jul 30 07:27:58 CEST 2003 + - fix flags handling in interpreter + - fix handle-text compile mode behaviour + - add defer, struct, field + - add behaviour, to + - add $create, create, does> (missing c code DODOES) + - add abort + +Thu Jul 31 07:58:35 CEST 2003 + - fix DODOES cfa code + - make 2@ and 2! colon definitions instead of primitives. + - add word "cell" + - add warning message as described in 7.3.9.1 if an already + existing word is created + +Fri Aug 1 23:32:57 CEST 2003 + - fix s" in C interpreter (compare case insensitive) + - fix forth source dependencies + - fix forth word sm/rem + +Sat Aug 2 13:34:43 CEST 2003 + - add band guard around input buffer + - make sure that "header" pads null bytes + - define -1,0,1,2,3 early to safe dictionary space + +Sat Aug 2 16:58:31 CEST 2003 + - use getopt/getopt_long for option parsing + - add include path option -I to unix + - don't create obsolete symlink in forth/Makefile + - fix recurse + - fix prim word / + - implement postpone + - fix 2!, ['] and ' + - implement evaluate/eval + +Sun Aug 3 11:48:18 CEST 2003 + - implement "bye" to leave the engine + - change initial word to "initialize" and + make quit restart the forth engine. + - fix missing ; in u. + - fix return value of find when handling an immediate + - getting rid of primitives mod, /mod and /, replacing + them by floored variants as IEEE 1275-1994 says. + - clean up primitives. + +Sun Aug 3 23:06:39 CEST 2003 + - fix >body, body> + - make not a synonym for invert as described in IEEE 1275 + - todigit can now switch between capital and small letters via + value capital-hex? + +Mon Aug 4 21:57:06 CEST 2003 + - indent unix.c + - reimplement do, ?do, loop, +loop with prim helpers. It now + passes hayes' ans forth test suite. + - adopt unix.c and bootstrap.fs to new (?)do..(+)loop + - remove unneeded if around ?do..loop in ", + - interpreter: clear input buffer before refilling it + - serialize PC changes in dobranch and do?branch + +Thu Aug 7 19:00:43 CEST 2003 + - add/change missing/incomplete copyright notices + - implement " + +Sun Aug 10 19:52:20 CEST 2003 + - reimplement catch, through + - implement abort" + - rephrase endcase + - change interpreter to use exception words + - implement forget + - add dummy "forth" + +Sun Aug 10 22:12:28 CEST 2003 + - fix "spaces" + - create subdir util for types.sh and new bin2hex + - enable forth.html again, running hayes test suite. + - include dictionary in char array instead of elf section + when building an x86 "full" image + - don't newline in accept. + - fix " compile mode behavior. + - move throw/catch and use it with ' and ['] + - add :noname + +Thu Aug 14 23:02:15 CEST 2003 + - fix "field" + - implement second stage bootstrapping + NOTE: changes dictionary format! + - drop initxt from dictionary, since we know "last" now. + - output dictionary can be named on command line. + - make segfault handler optional + +Mon Sep 1 19:41:23 CEST 2003 + - move findword() et al to dict.c (needed by openbios.c due + to last dictionary change) + - fix findword() return values and optimize it slightly. + - indented some files. + +Mon Sep 8 22:43:55 CEST 2003 + - add initial AMD64 support (cloned x86 target) + - get vocabulary implementation working. maybe buggy, but operable + - enable vocabulary support by default (vocabularies? set to true) + - drop duplicate "forth" + - fix some comments in forth files. + +Sun Sep 28 14:26:41 CEST 2003 + - some documentation and comment fixes + - fix parameter passing for io words. + +Thu Oct 2 08:21:06 CEST 2003 + - clean up lit + - inline some functions from internal.h (reduces size and execution + time) + +Fri Oct 3 15:20:44 CEST 2003 + - make i and j primitives. This safes a lot of time in loops. + i.e. the following dummy loop executes 300% faster: + : fbar 1000 0 do 1000 0 do j drop i drop loop loop ; + +Sat Oct 11 20:18:22 CEST 2003 + - include plugin interface for unix hosted version. + - add plugin_pci and plugin_qt as examples. + - add simple set of pci functions for testing the pci plugin + - add state variable "runforth" to be changed by the qt plugin + on exit. + +Sun Oct 12 14:57:54 CEST 2003 + - move internal.h and forth.h to kernel/ + - replace make by $(MAKE) in some places. + +Tue Oct 14 01:06:39 CEST 2003 + - add (immediate) and (compile-only) + +Wed Oct 15 00:52:49 CEST 2003 + - check whether dlopen() needs libdl. + - include BSD compile fixes from oxygene + - fix abort" + +Tue Oct 21 22:08:00 CEST 2003 + - fix forth.html dependencies + - yet another indent orgy + +Thu Oct 30 16:10:01 CET 2003 + - add "call" to execute native code functions + - plugin_qt: fix framebuffer address on 64bit systems + - plugin_pci: create position independent code. + +Wed Nov 5 08:38:18 CET 2003 + - fix "comp" (from Samuel Rydh) + - include instance support (from Samuel Rydh) + +Sun Nov 9 15:53:33 CET 2003 + - some changes for "see" + - apply more patches from Samuel. + - smaller, better implementation of handle-text + +Mon Nov 10 22:06:32 CET 2003 + - increase max dictionary size from 64k to 128k + - add simple fcode to qt plugin + - fix handle-text (move null-align up) + +Tue Nov 11 22:53:27 CET 2003 + - rename ?key to key?. + - clean up .s + - add (cr + +Tue Nov 17 22:42:54 CET 2003 + - enterforth rstack fix (from Samuel) + - include latest version of qt interface + fcode driver + - fix "header" (from Samuel) + +Wed Nov 26 15:12:07 CET 2003 + - merge patches from Samuel: + - add $buffer: + - fill all of "ib", not only 80 characters + - interpreted conditionals support + - late initializers + +Sun Nov 30 23:04:28 CET 2003 + - fix bug in enterforth (non-colon words would destroy PC) + +Sat Dec 13 00:57:01 CET 2003 + - add initial ppc infrastructure + - only search current wordlist in "header" + - seperate unix host binary and bootstrap interpreter. + +Sun Dec 14 18:13:29 CET 2003 + - add sys-debug word and use it to stop forth interpreter + during bootstrap if an error occurs. + +Sat Mar 13 16:30:30 CET 2004 + - fix digit problem + diff --git a/Documentation/kernel/TODO b/Documentation/kernel/TODO new file mode 100644 index 0000000..82ebf7b --- /dev/null +++ b/Documentation/kernel/TODO @@ -0,0 +1,11 @@ +TODO + +booting + * support more arches than x86+amd64 + * compressed + rommable dictionary + +forth bootstrap + * make prompt configurable + * check state-variable when defining a new word. + +tag: TODO for the forth system diff --git a/Documentation/kernel/dictformat.txt b/Documentation/kernel/dictformat.txt new file mode 100644 index 0000000..431e2cd --- /dev/null +++ b/Documentation/kernel/dictformat.txt @@ -0,0 +1,8 @@ +# tag: contains a description of the dictionary format + +name | length of name in bytes + 0x80 | align with 0's | flags (bit 7 set) | LFA | CFA | PFA + +LFA == link field address (backlink) +CFA == code field address ("word type") +PFA == program field address (definitions) + diff --git a/Documentation/kernel/glossary.txt b/Documentation/kernel/glossary.txt new file mode 100644 index 0000000..74785f1 --- /dev/null +++ b/Documentation/kernel/glossary.txt @@ -0,0 +1,14 @@ +# tag: glossary of openbios forth + +# dictionary +LFA == link field address (backlink) +CFA == code field address ("word type") +PFA == program field address (definitions) + +# forth engine +TIB == text input buffer + +inner interpreter: interprets dictionary, does threading +outer interpreter: "user" interpreter, reads forth words from user. + + diff --git a/Documentation/kernel/initializers.txt b/Documentation/kernel/initializers.txt new file mode 100644 index 0000000..18a8e23 --- /dev/null +++ b/Documentation/kernel/initializers.txt @@ -0,0 +1,24 @@ + +Initializers are called when the forth kernel is started, to do some +initialization stuff. +Pro: If code needs initialization you can keep this in place with the code +and don't need to patch the kernel itself to do so. + +There are 2 types of initializers. "Normal" and "Late" initializers. + +Since initializers are only called during startup, they don't need a name. + +Definition: + initializer ( xt -- ) + late-initializer ( xt -- ) + +Examples: + :noname ; initializer + + :noname + some-base initializations + ; late-initializer + +Late initializers are run after all ordinary initializers have +been executed. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..37b93f2 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +ARCH= $(shell cat rules.xml |grep ^ARCH|cut -d\= -f2|tr -d \ ) +HOSTARCH=$(shell config/scripts/archname) +ODIR=obj-$(ARCH) + +all: info build + +info: + @echo "Building OpenBIOS on $(HOSTARCH) for $(ARCH)" + +clean: + @echo -n "Cleaning up..." + @rm -rf $(ODIR) forth.dict.core + @echo " ok" + +directories: clean + @echo -n "Initializing build tree..." + @mkdir $(ODIR) + @mkdir -p $(ODIR)/target/include + @mkdir -p $(ODIR)/target/arch/unix + @mkdir -p $(ODIR)/target/arch/$(ARCH) + @mkdir -p $(ODIR)/target/arch/ppc/briq # no autodetection of those.. + @mkdir -p $(ODIR)/target/arch/ppc/pearpc + @mkdir -p $(ODIR)/target/arch/ppc/mol + @mkdir -p $(ODIR)/target/arch/x86/xbox + @mkdir -p $(ODIR)/target/kernel + @mkdir -p $(ODIR)/target/modules + @mkdir -p $(ODIR)/target/fs/grubfs + @mkdir -p $(ODIR)/target/fs/hfs + @mkdir -p $(ODIR)/target/fs/hfsplus + @mkdir -p $(ODIR)/target/drivers + @mkdir -p $(ODIR)/target/libc + @mkdir -p $(ODIR)/host/include + @mkdir -p $(ODIR)/host/kernel + @mkdir -p $(ODIR)/host/toke + @mkdir -p $(ODIR)/forth + @ln -s $(PWD)/include/$(ARCH) $(ODIR)/target/include/asm + @#compile the host binary with target settings instead + @#ln -s $(PWD)/include/$(HOSTARCH) $(ODIR)/host/include/asm + @echo "ok." + +xml: directories + @echo -n "Creating target Makefile..." + @xsltproc config/xml/xinclude.xsl build.xml > $(ODIR)/build-full.xml + @xsltproc config/xml/makefile.xsl $(ODIR)/build-full.xml > $(ODIR)/Makefile + @echo "ok." + @echo -n "Creating config files..." + @xsltproc config/xml/config-c.xsl config.xml > $(ODIR)/host/include/autoconf.h + @xsltproc config/xml/config-c.xsl config.xml > $(ODIR)/target/include/autoconf.h + @xsltproc config/xml/config-forth.xsl config.xml > $(ODIR)/forth/config.fs + @echo "ok." + +build: xml + @echo -n "Building..." + @( $(MAKE) -f $(ODIR)/Makefile > $(ODIR)/build.log 2>&1 && echo "ok." ) || \ + ( echo "error:"; tail -15 $(ODIR)/build.log ) + +run: + @echo "Running..." + @$(ODIR)/openbios-unix $(ODIR)/openbios-unix.dict diff --git a/README b/README new file mode 100644 index 0000000..e8a7685 --- /dev/null +++ b/README @@ -0,0 +1,131 @@ +Welcome to OpenBIOS +------------------- + +OpenBIOS is a free, portable implementation of IEEE 1275-1994 +(Open Firmware). Find detailed information about OpenBIOS at +http://www.openbios.org/ + +What is OpenBIOS? +----------------- + +OpenBIOS can replace your system firmware (BIOS) partly or completely. It +can also be used as a bootloader to create an Open Firmware compatible +interface between legacy firmware and an operating system. + +This is achieved by a modular concept that consists of a portable Forth +kernel and three interfaces for user interaction, device initialization +and client (operating system) control. + +While far not all possible applications of OpenBIOS are implemented yet, +a lot of functionality is already there. OpenBIOS can be used to enhance +LinuxBIOS (http://www.linuxbios.org), or be booted from any multiboot +capable bootloader to bring Open Firmware to your machine. OpenBIOS can +also be used when an operating system is already running. It provides +the needed OpenFirmware functionality to MOL (MacOnLinux) to boot MacOS +9 and X on PPC machines, as well as Linux (all supported platforms) + +OpenBIOS build options +--------------------- + + config/scripts/switch-arch - build for specified platform + Look in config/example for + platforms. + + make - build all configured binaries + + make run - run unix example. + + +How OpenBIOS works +------------------ + + The OpenBIOS forth core is split into a forth kernel written in portable + C and a forth dictionary which operated on by the kernel. + + When building the forth core, you get different versions of + the forth kernel: + + * a unix executable program + + - to execute a forth dictionary from a file. This can be used for + easily testing and developing OpenBIOS on a unix host. + + - to create a dictionary file. Such a dictionary file sets up + all of the forth language. Primitives are indexed to save relocations. + + The default is to create a forth dictionary forth.dict from + forth/start.fs. This file includes all of the basic forth language + constructs from forth/bootstrap.fs and starts the interpreter. + + To achieve this, the hosted unix version contains a basic set of + forth words coded in C that allow creating a full dictionary. + + * a varying number of target specific binaries. On x86 you can start + openbios for example from GRUB or LinuxBIOS. They are all based on + the same forth engine consisting of a dictionary scheduler, primitive + words needed to build the forth environment, 2 stacks and a simple + set of console functions. These binaries can not be started directly + in the unix host environment. + +Requirements +------------ + * gcc + * gnu make + * grub or any other multiboot loader to run the multiboot + binary "openbios.multiboot" with it's module "openbios-.dict" + * xsltproc + +Building & Usage +---------------- + + * make + + this builds "openbios.multiboot", the standalone image and "openbios-unix", + the hosted image. Additionally it creates a forth dictionary + file from forth/start.fs. All generated files are written to + the absolute directory held by the variable BUILDDIR, which defaults + to obj-[platform]. Some compile time parameters can be tweaked in + include/config.h + + * use "openbios-unix" to create a forth dictionary on your own: + $ obj-x86/openbios-unix -Iforth start.fs + creates the file forth.dict from forth source forth/start.fs. + + * use "openbios-unix" to run a created dictionary: + $ obj-x86/openbios-unix obj-x86/openbios-unix.dict + This is useful for testing + + * booting openbios + You can boot openbios i.e. in grub. Add the following lines to + your menu.lst: + + title openbios + kernel (hd0,2)/boot/openbios.multiboot + module (hd0,2)/boot/openbios-x86.dict + + Note: change (hd0,2) to the partition you copied the openbios image and + openbios-x86.dict to. + + To boot OpenBIOS from LinuxBIOS/etherboot, you can either use + "openbios-plain.elf" or "openbios-builtin.elf": + + - openbios-plain.elf is the pure kernel that loads the dictionary from a + hardcoded address in flash memory (0xfffe0000) + + - openbios-builtin.elf also includes the dictionary directly so that it + can be easily used from etherboot or the LinuxBIOS builtin ELF + loader without taking care of the dictionary + +CREDITS +------- +OpenBIOS was developed by Stefan Reinauer, Samuel Rydh and Patrick Mauritz. +The OpenBIOS IDE driver was written by Jens Axboe. +For license details on this piece of software, see Documentation/COPYING. + + +If you have patches, questions, comments, feel free to contact the OpenBIOS +mailinglist. + +Regards, + the OpenBIOS team + diff --git a/arch/amd64/Kconfig b/arch/amd64/Kconfig new file mode 100644 index 0000000..d26f575 --- /dev/null +++ b/arch/amd64/Kconfig @@ -0,0 +1,50 @@ +mainmenu "OpenBIOS Configuration" + +config AMD64 + bool + default y + help + Building for AMD64 hardware. + +config LITTLE_ENDIAN + bool + default y + help + AMD64 is little endian. + + +menu "Kernel binaries (AMD64)" + +config IMAGE_ELF + bool "ELF image (for LinuxBIOS)" + default y + help + Build a simple elf image that can be used with LinuxBIOS + This image will be called openbios.elf + +config IMAGE_ELF_EMBEDDED + bool "ELF image with embedded dictionary" + default y + help + Build an elf image with embedded dictionary. This image + can easily be used with etherboot. + The image filename is openbios.full + +config IMAGE_ELF_MULTIBOOT + bool "Multiboot image" + default y + help + Build a multiboot image for booting with grub + +endmenu + +menu "Build hosted UNIX Binary" +source "arch/unix/Kconfig" +endmenu + +source "kernel/Kconfig" +source "forth/Kconfig" +source "modules/Kconfig" +source "drivers/Kconfig" + + diff --git a/arch/amd64/boot.c b/arch/amd64/boot.c new file mode 100644 index 0000000..8948041 --- /dev/null +++ b/arch/amd64/boot.c @@ -0,0 +1,43 @@ +/* + * + */ +#undef BOOTSTRAP +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/elfload.h" +#include "openbios/nvram.h" +#include "libc/diskio.h" +#include "sys_info.h" + +int elf_load(struct sys_info *, const char *filename, const char *cmdline); +int linux_load(struct sys_info *, const char *filename, const char *cmdline); + +void boot(void); + +struct sys_info sys_info; + +void boot(void) +{ + char *path=pop_fstr_copy(), *param; + + // char *param="root=/dev/hda2 console=ttyS0,115200n8 console=tty0"; + + if(!path) { + printk("[x86] Booting default not supported.\n"); + return; + } + + param = strchr(path, ' '); + if(param) { + *param = '\0'; + param++; + } + + printk("[x86] Booting file '%s' with parameters '%s'\n",path, param); + + if (elf_load(&sys_info, path, param) == LOADER_NOT_SUPPORT) + if (linux_load(&sys_info, path, param) == LOADER_NOT_SUPPORT) + printk("Unsupported image format\n"); + + free(path); +} diff --git a/arch/amd64/build.xml b/arch/amd64/build.xml new file mode 100644 index 0000000..e693080 --- /dev/null +++ b/arch/amd64/build.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/arch/amd64/builtin.c b/arch/amd64/builtin.c new file mode 100644 index 0000000..b351c70 --- /dev/null +++ b/arch/amd64/builtin.c @@ -0,0 +1,26 @@ +/* tag: openbios forth starter for builtin dictionary for amd64 + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include +#include "sys_info.h" + +/* + * wrap an array around the hex'ed dictionary file + */ + +#include "static-dict.h" + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ + info->dict_start=(unsigned long *)forth_dictionary; + info->dict_end=(unsigned long *)((ucell)forth_dictionary + + sizeof(forth_dictionary)); +} + diff --git a/arch/amd64/console.c b/arch/amd64/console.c new file mode 100644 index 0000000..346e659 --- /dev/null +++ b/arch/amd64/console.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2003, 2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios.h" + +#ifdef CONFIG_DEBUG_CONSOLE + +/* ****************************************************************** + * serial console functions + * ****************************************************************** */ + +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + +#define RBR(x) x==2?0x2f8:0x3f8 +#define THR(x) x==2?0x2f8:0x3f8 +#define IER(x) x==2?0x2f9:0x3f9 +#define IIR(x) x==2?0x2fa:0x3fa +#define LCR(x) x==2?0x2fb:0x3fb +#define MCR(x) x==2?0x2fc:0x3fc +#define LSR(x) x==2?0x2fd:0x3fd +#define MSR(x) x==2?0x2fe:0x3fe +#define SCR(x) x==2?0x2ff:0x3ff +#define DLL(x) x==2?0x2f8:0x3f8 +#define DLM(x) x==2?0x2f9:0x3f9 + +static int uart_charav(int port) +{ + if (!port) + return -1; + return ((inb(LSR(port)) & 1) != 0); +} + +static char uart_getchar(int port) +{ + if (!port) + return -1; + while (!uart_charav(port)); + return ((char) inb(RBR(port)) & 0177); +} + +static void uart_putchar(int port, unsigned char c) +{ + if (!port) + return; + if (c == '\n') + uart_putchar(port, '\r'); + while (!(inb(LSR(port)) & 0x20)); + outb(c, THR(port)); +} + +static void uart_init_line(int port, unsigned long baud) +{ + int i, baudconst; + + if (!port) + return; + + switch (baud) { + case 115200: + baudconst = 1; + break; + case 57600: + baudconst = 2; + break; + case 38400: + baudconst = 3; + break; + case 19200: + baudconst = 6; + break; + case 9600: + default: + baudconst = 12; + break; + } + + outb(0x87, LCR(port)); + outb(0x00, DLM(port)); + outb(baudconst, DLL(port)); + outb(0x07, LCR(port)); + outb(0x0f, MCR(port)); + + for (i = 10; i > 0; i--) { + if (inb(LSR(port)) == (unsigned int) 0) + break; + inb(RBR(port)); + } +} + +int uart_init(int port, unsigned long speed) +{ + if (port) + uart_init_line(port, speed); + return -1; +} + +static void serial_putchar(int c) +{ + uart_putchar(CONFIG_SERIAL_PORT, (unsigned char) (c & 0xff)); +} + +static void serial_cls(void) +{ + serial_putchar(27); + serial_putchar('['); + serial_putchar('H'); + serial_putchar(27); + serial_putchar('['); + serial_putchar('J'); +} + +#endif + +/* ****************************************************************** + * simple polling video/keyboard console functions + * ****************************************************************** */ + +#ifdef CONFIG_DEBUG_CONSOLE_VGA + +/* raw vga text mode */ +#define COLUMNS 80 /* The number of columns. */ +#define LINES 25 /* The number of lines. */ +#define ATTRIBUTE 7 /* The attribute of an character. */ + +#define VGA_BASE 0xB8000 /* The video memory address. */ + +/* VGA Index and Data Registers */ +#define VGA_REG_INDEX 0x03D4 /* VGA index register */ +#define VGA_REG_DATA 0x03D5 /* VGA data register */ + +#define VGA_IDX_CURMSL 0x09 /* cursor maximum scan line */ +#define VGA_IDX_CURSTART 0x0A /* cursor start */ +#define VGA_IDX_CUREND 0x0B /* cursor end */ +#define VGA_IDX_CURLO 0x0F /* cursor position (low 8 bits) */ +#define VGA_IDX_CURHI 0x0E /* cursor position (high 8 bits) */ + +/* Save the X and Y position. */ +static int xpos, ypos; +/* Point to the video memory. */ +static volatile unsigned char *video = (unsigned char *) VGA_BASE; + +static void video_initcursor(void) +{ + u8 val; + outb(VGA_IDX_CURMSL, VGA_REG_INDEX); + val = inb(VGA_REG_DATA) & 0x1f; /* maximum scan line -1 */ + + outb(VGA_IDX_CURSTART, VGA_REG_INDEX); + outb(0, VGA_REG_DATA); + + outb(VGA_IDX_CUREND, VGA_REG_INDEX); + outb(val, VGA_REG_DATA); +} + + + +static void video_poscursor(unsigned int x, unsigned int y) +{ + unsigned short pos; + + /* Calculate new cursor position as a function of x and y */ + pos = (y * COLUMNS) + x; + + /* Output the new position to VGA card */ + outb(VGA_IDX_CURLO, VGA_REG_INDEX); /* output low 8 bits */ + outb((u8) (pos), VGA_REG_DATA); + outb(VGA_IDX_CURHI, VGA_REG_INDEX); /* output high 8 bits */ + outb((u8) (pos >> 8), VGA_REG_DATA); + +}; + + +static void video_newline(void) +{ + xpos = 0; + + if (ypos < LINES - 1) { + ypos++; + } else { + int i; + memmove((void *) video, (void *) (video + 2 * COLUMNS), + (LINES - 1) * COLUMNS * 2); + + for (i = ((LINES - 1) * 2 * COLUMNS); + i < 2 * COLUMNS * LINES;) { + video[i++] = 0; + video[i++] = ATTRIBUTE; + } + } + +} + +/* Put the character C on the screen. */ +static void video_putchar(int c) +{ + int p=1; + + if (c == '\n' || c == '\r') { + video_newline(); + return; + } + + if (c == '\b') { + if (xpos) xpos--; + c=' '; + p=0; + } + + + if (xpos >= COLUMNS) + video_newline(); + + *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF; + *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE; + + if (p) + xpos++; + + video_poscursor(xpos, ypos); +} + +static void video_cls(void) +{ + int i; + + for (i = 0; i < 2 * COLUMNS * LINES;) { + video[i++] = 0; + video[i++] = ATTRIBUTE; + } + + + xpos = 0; + ypos = 0; + + video_initcursor(); + video_poscursor(xpos, ypos); +} + +void video_init(void) +{ + video=phys_to_virt((unsigned char*)VGA_BASE); +} + +/* + * keyboard driver + */ + +static char normal[] = { + 0x0, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', + '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', + 'p', '[', ']', 0xa, 0x0, 'a', 's', 'd', 'f', 'g', 'h', 'j', + 'k', 'l', ';', 0x27, 0x60, 0x0, 0x5c, 'z', 'x', 'c', 'v', 'b', + 'n', 'm', ',', '.', '/', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '0', 0x7f +}; + +static char shifted[] = { + 0x0, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', + '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', + 'P', '{', '}', 0xa, 0x0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', + 'K', 'L', ':', 0x22, '~', 0x0, '|', 'Z', 'X', 'C', 'V', 'B', + 'N', 'M', '<', '>', '?', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '7', '8', + '9', 0x0, '4', '5', '6', 0x0, '1', '2', '3', '0', 0x7f +}; + +static int key_ext; +static int key_lshift = 0, key_rshift = 0, key_caps = 0; + +static char last_key; + +static void keyboard_cmd(unsigned char cmd, unsigned char val) +{ + outb(cmd, 0x60); + /* wait until keyboard controller accepts cmds: */ + while (inb(0x64) & 2); + outb(val, 0x60); + while (inb(0x64) & 2); +} + +static char keyboard_poll(void) +{ + unsigned int c; + if (inb(0x64) & 1) { + c = inb(0x60); + switch (c) { + case 0xe0: + key_ext = 1; + return 0; + case 0x2a: + key_lshift = 1; + return 0; + case 0x36: + key_rshift = 1; + return 0; + case 0xaa: + key_lshift = 0; + return 0; + case 0xb6: + key_rshift = 0; + return 0; + case 0x3a: + if (key_caps) { + key_caps = 0; + keyboard_cmd(0xed, 0); + } else { + key_caps = 1; + keyboard_cmd(0xed, 4); /* set caps led */ + } + return 0; + } + + if (key_ext) { + // void printk(const char *format, ...); + printk("extended keycode: %x\n", c); + + key_ext = 0; + return 0; + } + + if (c & 0x80) /* unhandled key release */ + return 0; + + if (key_lshift || key_rshift) + return key_caps ? normal[c] : shifted[c]; + else + return key_caps ? shifted[c] : normal[c]; + } + return 0; +} + +static int keyboard_dataready(void) +{ + if (last_key) + return 1; + + last_key = keyboard_poll(); + + return (last_key != 0); +} + +static unsigned char keyboard_readdata(void) +{ + char tmp; + while (!keyboard_dataready()); + tmp = last_key; + last_key = 0; + return tmp; +} +#endif + + +/* ****************************************************************** + * common functions, implementing simple concurrent console + * ****************************************************************** */ + +int putchar(int c) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + serial_putchar(c); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + video_putchar(c); +#endif + return c; +} + +int availchar(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + if (uart_charav(CONFIG_SERIAL_PORT)) + return 1; +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + if (keyboard_dataready()) + return 1; +#endif + return 0; +} + +int getchar(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + if (uart_charav(CONFIG_SERIAL_PORT)) + return (uart_getchar(CONFIG_SERIAL_PORT)); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + if (keyboard_dataready()) + return (keyboard_readdata()); +#endif + return 0; +} + +void cls(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + serial_cls(); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + video_cls(); +#endif +} + + +#endif // CONFIG_DEBUG_CONSOLE diff --git a/arch/amd64/context.c b/arch/amd64/context.c new file mode 100644 index 0000000..4131c1f --- /dev/null +++ b/arch/amd64/context.c @@ -0,0 +1,124 @@ +/* + * context switching + * 2003-10 by SONE Takeshi + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "segment.h" +#include "context.h" + +#define MAIN_STACK_SIZE 16384 +#define IMAGE_STACK_SIZE 4096 + +#define debug printk + +static void start_main(void); /* forward decl. */ +void __exit_context(void); /* assembly routine */ + +/* + * Main context structure + * It is placed at the bottom of our stack, and loaded by assembly routine + * to start us up. + */ +struct context main_ctx __attribute__((section (".initctx"))) = { + .gdt_base = (uint64_t) gdt, + .gdt_limit = GDT_LIMIT, + .cs = FLAT_CS, + .ds = FLAT_DS, + .es = FLAT_DS, + .fs = FLAT_DS, + .gs = FLAT_DS, + .ss = FLAT_DS, + .esp = (uint32_t) ESP_LOC(&main_ctx), + .eip = (uint32_t) start_main, + .return_addr = (uint32_t) __exit_context, +}; + +/* This is used by assembly routine to load/store the context which + * it is to switch/switched. */ +struct context *__context = &main_ctx; + +/* Stack for loaded ELF image */ +static uint8_t image_stack[IMAGE_STACK_SIZE]; + +/* Pointer to startup context (physical address) */ +unsigned long __boot_ctx; + +/* + * Main starter + * This is the C function that runs first. + */ +static void start_main(void) +{ + int retval; + extern int openbios(void); + + /* Save startup context, so we can refer to it later. + * We have to keep it in physical address since we will relocate. */ + __boot_ctx = virt_to_phys(__context); + + /* Start the real fun */ + retval = openbios(); + + /* Pass return value to startup context. Bootloader may see it. */ + boot_ctx->eax = retval; + + /* Returning from here should jump to __exit_context */ + __context = boot_ctx; +} + +/* Setup a new context using the given stack. + */ +struct context * +init_context(uint8_t *stack, uint32_t stack_size, int num_params) +{ + struct context *ctx; + + ctx = (struct context *) + (stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t))); + memset(ctx, 0, sizeof(*ctx)); + + /* Fill in reasonable default for flat memory model */ + ctx->gdt_base = virt_to_phys(gdt); + ctx->gdt_limit = GDT_LIMIT; + ctx->cs = FLAT_CS; + ctx->ds = FLAT_DS; + ctx->es = FLAT_DS; + ctx->fs = FLAT_DS; + ctx->gs = FLAT_DS; + ctx->ss = FLAT_DS; + ctx->esp = virt_to_phys(ESP_LOC(ctx)); + ctx->return_addr = virt_to_phys(__exit_context); + + return ctx; +} + +/* Switch to another context. */ +struct context *switch_to(struct context *ctx) +{ + struct context *save, *ret; + + debug("switching to new context:\n"); + save = __context; + __context = ctx; + asm ("pushl %cs; call __switch_context"); + ret = __context; + __context = save; + return ret; +} + +/* Start ELF Boot image */ +uint32_t start_elf(uint32_t entry_point, uint32_t param) +{ + struct context *ctx; + + ctx = init_context(image_stack, sizeof image_stack, 1); + ctx->eip = entry_point; + ctx->param[0] = param; + ctx->eax = 0xe1fb007; + ctx->ebx = param; + + ctx = switch_to(ctx); + return ctx->eax; +} diff --git a/arch/amd64/context.h b/arch/amd64/context.h new file mode 100644 index 0000000..4c3832e --- /dev/null +++ b/arch/amd64/context.h @@ -0,0 +1,48 @@ +#ifndef AMD64_CONTEXT_H +#define AMD64_CONTEXT_H + +struct context { + /* Stack Segment, placed here because of the alignment issue... */ + uint16_t ss; + /* Used with sgdt/lgdt */ + uint16_t gdt_limit; + uint64_t gdt_base; + /* General registers, accessed with pushal/popal */ + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; /* points just below eax */ + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; +#define ESP_LOC(ctx) (&(ctx)->gs) + /* Segment registers */ + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + /* Flags */ + uint32_t eflags; + /* Code segment:offset */ + uint32_t eip; + uint32_t cs; + /* Optional stack contents */ + uint32_t return_addr; + uint32_t param[0]; +}; + +/* Create a new context in the given stack */ +struct context * +init_context(uint8_t *stack, uint32_t stack_size, int num_param); + +/* Switch context */ +struct context *switch_to(struct context *); + +/* Holds physical address of boot context */ +extern unsigned long __boot_ctx; + +/* This can always be safely used to refer to the boot context */ +#define boot_ctx ((struct context *) phys_to_virt(__boot_ctx)) + +#endif /* AMD64_CONTEXT_H */ diff --git a/arch/amd64/defconfig b/arch/amd64/defconfig new file mode 100644 index 0000000..570a6c8 --- /dev/null +++ b/arch/amd64/defconfig @@ -0,0 +1,65 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_AMD64=y +CONFIG_LITTLE_ENDIAN=y + +# +# Kernel binaries (AMD64) +# +# CONFIG_IMAGE_ELF is not set +# CONFIG_IMAGE_ELF_EMBEDDED is not set +# CONFIG_IMAGE_ELF_MULTIBOOT is not set + +# +# Build hosted UNIX Binary +# +CONFIG_HOST_UNIX=y +# CONFIG_PLUGIN_PCI is not set + +# +# Kernel Debugging +# +# CONFIG_DEBUG is not set +CONFIG_DEBUG_CONSOLE=y +CONFIG_DEBUG_CONSOLE_SERIAL=y +CONFIG_SERIAL_PORT=1 +CONFIG_SERIAL_SPEED=115200 +CONFIG_DEBUG_CONSOLE_VGA=y + +# +# Module Configuration +# +CONFIG_CMDLINE=y +CONFIG_DEBLOCKER=y + +# +# Filesystem Configuration +# +CONFIG_DISK_LABEL=y +CONFIG_PART_SUPPORT=y +CONFIG_PC_PARTS=y +CONFIG_FS=y +CONFIG_GRUBFS=y +CONFIG_FSYS_EXT2FS=y +CONFIG_FSYS_FAT=y +CONFIG_FSYS_JFS=y +# CONFIG_FSYS_MINIX is not set +CONFIG_FSYS_REISERFS=y +CONFIG_FSYS_XFS=y +CONFIG_FSYS_ISO9660=y +# CONFIG_FSYS_FFS is not set +# CONFIG_FSYS_VSTAFS is not set +# CONFIG_DEBUG_FS is not set + +# +# Miscellaneous +# +CONFIG_LINUXBIOS=y + +# +# Drivers +# +CONFIG_DRIVER_PCI=y +CONFIG_DRIVER_IDE=y +# CONFIG_DEBUG_IDE is not set diff --git a/arch/amd64/elfload.c b/arch/amd64/elfload.c new file mode 100644 index 0000000..946c7e2 --- /dev/null +++ b/arch/amd64/elfload.c @@ -0,0 +1,387 @@ +/* ELF Boot loader + * As we have seek, this implementation can be straightforward. + * 2003-07 by SONE Takeshi + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/elf.h" +#include "asm/elf.h" +#include "elf_boot.h" +#include "sys_info.h" +#include "ipchecksum.h" +#include "loadfs.h" +#define printf printk +#define debug printk + +extern unsigned int start_elf(unsigned long entry_point, unsigned long param); +extern char _start, _end; + +static char *image_name, *image_version; + +static void *calloc(size_t nmemb, size_t size) +{ + size_t alloc_size = nmemb * size; + void *mem; + + if (alloc_size < nmemb || alloc_size < size) { + printf("calloc overflow: %u, %u\n", nmemb, size); + return 0; + } + + mem = malloc(alloc_size); + memset(mem, 0, alloc_size); + + return mem; +} + + +static int check_mem_ranges(struct sys_info *info, + Elf_phdr *phdr, int phnum) +{ + int i, j; + unsigned long start, end; + unsigned long prog_start, prog_end; + struct memrange *mem; + + prog_start = virt_to_phys(&_start); + prog_end = virt_to_phys(&_end); + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + start = phdr[i].p_paddr; + end = start + phdr[i].p_memsz; + if (start < prog_start && end > prog_start) + goto conflict; + if (start < prog_end && end > prog_end) + goto conflict; + mem=info->memrange; + for (j = 0; j < info->n_memranges; j++) { + if (mem[j].base <= start && mem[j].base + mem[j].size >= end) + break; + } + if (j >= info->n_memranges) + goto badseg; + } + return 1; + +conflict: + printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end); + +badseg: + printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1); + return 0; +} + +static unsigned long process_image_notes(Elf_phdr *phdr, int phnum, + unsigned short *sum_ptr) +{ + int i; + char *buf = NULL; + int retval = 0; + unsigned long addr, end; + Elf_Nhdr *nhdr; + const char *name; + void *desc; + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_NOTE) + continue; + buf = malloc(phdr[i].p_filesz); + file_seek(phdr[i].p_offset); + if (lfile_read(buf, phdr[i].p_filesz) != phdr[i].p_filesz) { + printf("Can't read note segment\n"); + goto out; + } + addr = (unsigned long) buf; + end = addr + phdr[i].p_filesz; + while (addr < end) { + nhdr = (Elf_Nhdr *) addr; + addr += sizeof(Elf_Nhdr); + name = (const char *) addr; + addr += (nhdr->n_namesz+3) & ~3; + desc = (void *) addr; + addr += (nhdr->n_descsz+3) & ~3; + + if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT) + && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) { + if (nhdr->n_type == EIN_PROGRAM_NAME) { + image_name = calloc(1, nhdr->n_descsz + 1); + memcpy(image_name, desc, nhdr->n_descsz); + } + if (nhdr->n_type == EIN_PROGRAM_VERSION) { + image_version = calloc(1, nhdr->n_descsz + 1); + memcpy(image_version, desc, nhdr->n_descsz); + } + if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) { + *sum_ptr = *(unsigned short *) desc; + debug("Image checksum: %#04x\n", *sum_ptr); + /* Where in the file */ + retval = phdr[i].p_offset + + (unsigned long) desc - (unsigned long) buf; + } + } + } + } +out: + if (buf) + free(buf); + return retval; +} + +static int load_segments(Elf_phdr *phdr, int phnum, + unsigned long checksum_offset) +{ + unsigned long bytes; + //unsigned int start_time, time; + int i; + + bytes = 0; + // start_time = currticks(); + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + debug("segment %d addr:%#x file:%#x mem:%#x ", + i, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz); + file_seek(phdr[i].p_offset); + debug("loading... "); + if (lfile_read(phys_to_virt(phdr[i].p_paddr), phdr[i].p_filesz) + != phdr[i].p_filesz) { + printf("Can't read program segment %d\n", i); + return 0; + } + bytes += phdr[i].p_filesz; + debug("clearing... "); + memset(phys_to_virt(phdr[i].p_paddr + phdr[i].p_filesz), 0, + phdr[i].p_memsz - phdr[i].p_filesz); + if (phdr[i].p_offset <= checksum_offset + && phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) { + debug("clearing checksum... "); + memset(phys_to_virt(phdr[i].p_paddr + checksum_offset + - phdr[i].p_offset), 0, 2); + } + debug("ok\n"); + + } + // time = currticks() - start_time; + //debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time, + // time? bytes/time : 0); + debug("Loaded %lu bytes \n", bytes); + + return 1; +} + +static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum, + unsigned short image_sum) +{ + unsigned short sum, part_sum; + unsigned long offset; + int i; + + sum = 0; + offset = 0; + + part_sum = ipchksum(ehdr, sizeof *ehdr); + sum = add_ipchksums(offset, sum, part_sum); + offset += sizeof *ehdr; + + part_sum = ipchksum(phdr, phnum * sizeof(*phdr)); + sum = add_ipchksums(offset, sum, part_sum); + offset += phnum * sizeof(*phdr); + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + part_sum = ipchksum(phys_to_virt(phdr[i].p_paddr), phdr[i].p_memsz); + sum = add_ipchksums(offset, sum, part_sum); + offset += phdr[i].p_memsz; + } + + if (sum != image_sum) { + printf("Verify FAILED (image:%#04x vs computed:%#04x)\n", + image_sum, sum); + return 0; + } + return 1; +} + +static inline unsigned const padded(unsigned s) +{ + return (s + 3) & ~3; +} + +static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name, + unsigned type, const char *desc, unsigned descsz) +{ + Elf_Nhdr nhdr; + unsigned ent_size, new_size, pad; + char *addr; + + if (!bhdr) + return NULL; + + nhdr.n_namesz = name? strlen(name)+1 : 0; + nhdr.n_descsz = descsz; + nhdr.n_type = type; + ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz); + if (bhdr->b_size + ent_size > 0xffff) { + printf("Boot notes too big\n"); + free(bhdr); + return NULL; + } + if (bhdr->b_size + ent_size > bhdr->b_checksum) { + do { + new_size = bhdr->b_checksum * 2; + } while (new_size < bhdr->b_size + ent_size); + if (new_size > 0xffff) + new_size = 0xffff; + debug("expanding boot note size to %u\n", new_size); +#ifdef HAVE_REALLOC + bhdr = realloc(bhdr, new_size); + bhdr->b_checksum = new_size; +#else + printf("Boot notes too big\n"); + free(bhdr); + return NULL; +#endif + } + + addr = (char *) bhdr; + addr += bhdr->b_size; + memcpy(addr, &nhdr, sizeof(nhdr)); + addr += sizeof(nhdr); + + memcpy(addr, name, nhdr.n_namesz); + addr += nhdr.n_namesz; + pad = padded(nhdr.n_namesz) - nhdr.n_namesz; + memset(addr, 0, pad); + addr += pad; + + memcpy(addr, desc, nhdr.n_descsz); + addr += nhdr.n_descsz; + pad = padded(nhdr.n_descsz) - nhdr.n_descsz; + memset(addr, 0, pad); + addr += pad; + + bhdr->b_size += ent_size; + bhdr->b_records++; + return bhdr; +} + +static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name, + unsigned type, const char *desc) +{ + return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1); +} + +static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline) +{ + Elf_Bhdr *bhdr; + + bhdr = malloc(256); + bhdr->b_signature = ELF_BHDR_MAGIC; + bhdr->b_size = sizeof *bhdr; + bhdr->b_checksum = 256; /* XXX cache the current buffer size here */ + bhdr->b_records = 0; + + if (info->firmware) + bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, info->firmware); + bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name); + bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version); + if (cmdline) + bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline); + if (!bhdr) + return bhdr; + bhdr->b_checksum = 0; + bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size); + return bhdr; +} + +int elf_load(struct sys_info *info, const char *filename, const char *cmdline) +{ + Elf_ehdr ehdr; + Elf_phdr *phdr = NULL; + unsigned long phdr_size; + unsigned long checksum_offset; + unsigned short checksum; + Elf_Bhdr *boot_notes = NULL; + int retval = -1; + int image_retval; + + image_name = image_version = 0; + + if (!file_open(filename)) + goto out; + + if (lfile_read(&ehdr, sizeof ehdr) != sizeof ehdr) { + debug("Can't read ELF header\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 + || ehdr.e_ident[EI_MAG1] != ELFMAG1 + || ehdr.e_ident[EI_MAG2] != ELFMAG2 + || ehdr.e_ident[EI_MAG3] != ELFMAG3 + || ehdr.e_ident[EI_CLASS] != ARCH_ELF_CLASS + || ehdr.e_ident[EI_DATA] != ARCH_ELF_DATA + || ehdr.e_ident[EI_VERSION] != EV_CURRENT + || ehdr.e_type != ET_EXEC + || !ARCH_ELF_MACHINE_OK(ehdr.e_machine) + || ehdr.e_version != EV_CURRENT + || ehdr.e_phentsize != sizeof(Elf_phdr)) { + debug("Not a bootable ELF image\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + phdr_size = ehdr.e_phnum * sizeof *phdr; + phdr = malloc(phdr_size); + file_seek(ehdr.e_phoff); + if (lfile_read(phdr, phdr_size) != phdr_size) { + printf("Can't read program header\n"); + goto out; + } + + if (!check_mem_ranges(info, phdr, ehdr.e_phnum)) + goto out; + + checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum); + + printf("Loading %s", image_name ? image_name : "image"); + if (image_version) + printf(" version %s", image_version); + printf("...\n"); + + if (!load_segments(phdr, ehdr.e_phnum, checksum_offset)) + goto out; + + if (checksum_offset) { + if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum)) + goto out; + } + + boot_notes = build_boot_notes(info, cmdline); + + //debug("current time: %lu\n", currticks()); + + debug("entry point is %#x\n", ehdr.e_entry); + printf("Jumping to entry point...\n"); + image_retval = start_elf(ehdr.e_entry, virt_to_phys(boot_notes)); + + // console_init(); FIXME + printf("Image returned with return value %#x\n", image_retval); + retval = 0; + +out: + if (phdr) + free(phdr); + if (boot_notes) + free(boot_notes); + if (image_name) + free(image_name); + if (image_version) + free(image_version); + return retval; +} diff --git a/arch/amd64/init.fs b/arch/amd64/init.fs new file mode 100644 index 0000000..0d0d74a --- /dev/null +++ b/arch/amd64/init.fs @@ -0,0 +1,77 @@ +:noname + ." Type 'help' for detailed information" cr + \ ." boot secondary slave cdrom: " cr + \ ." 0 > boot hd:2,\boot\vmlinuz root=/dev/hda2" cr + ; DIAG-initializer + +" /" find-device + +new-device + " memory" device-name + \ 12230 encode-int " reg" property + external + : open true ; + : close ; + \ claim ( phys size align -- base ) + \ release ( phys size -- ) +finish-device + +new-device + " cpus" device-name + 1 " #address-cells" int-property + 0 " #size-cells" int-property + + external + : open true ; + : close ; + : decode-unit parse-hex ; + +finish-device + +: make-openable ( path ) + find-dev if + begin ?dup while + \ install trivial open and close methods + dup active-package! is-open + parent + repeat + then +; + +: preopen ( chosen-str node-path ) + 2dup make-openable + + " /chosen" find-device + open-dev ?dup if + encode-int 2swap property + else + 2drop + then +; + +:noname + set-defaults +; SYSTEM-initializer + +\ preopen device nodes (and store the ihandles under /chosen) +:noname + " memory" " /memory" preopen + " mmu" " /cpus/@0" preopen + " stdout" " /builtin/console" preopen + " stdin" " /builtin/console" preopen + +; SYSTEM-initializer + +\ use the tty interface if available +:noname + " /builtin/console" find-dev if drop + " /builtin/console" " input-device" $setenv + " /builtin/console" " output-device" $setenv + then +; SYSTEM-initializer + +:noname + " keyboard" input +; CONSOLE-IN-initializer + + diff --git a/arch/amd64/ldscript b/arch/amd64/ldscript new file mode 100644 index 0000000..8976c7a --- /dev/null +++ b/arch/amd64/ldscript @@ -0,0 +1,73 @@ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +ENTRY(entry) + +/* Initial load address + * To be loaded by GRUB, this must be >= 1MB + */ +BASE_ADDR = 0x100000; + +/* 16KB heap and stack */ +HEAP_SIZE = 16384; +STACK_SIZE = 16384; + +SECTIONS +{ + . = BASE_ADDR; + + /* Put Multiboot header near beginning of file, if any. */ + .hdr : { *(.hdr) *(.hdr.*) } + + /* Start of the program. + * Now the version string is in the note, we must include it + * in the program. Otherwise we lose the string after relocation. */ + . = ALIGN(16); + _start = .; + + /* Putting ELF notes near beginning of file might help bootloaders. + * We discard .note sections other than .note.ELFBoot, + * because some versions of GCC generates useless ones. */ + .note : { *(.note.ELFBoot) } + + /* Normal sections */ + .text : { *(.text) *(.text.*) } + .rodata : { + . = ALIGN(4); + sound_drivers_start = .; + *(.rodata.sound_drivers) + sound_drivers_end = .; + *(.rodata) + *(.rodata.*) + } + .data : { *(.data) *(.data.*) } + + .bss : { + *(.bss) + *(.bss.*) + *(COMMON) + + /* Put heap and stack here, so they are included in PT_LOAD segment + * and the bootloader is aware of it. */ + + . = ALIGN(16); + _heap = .; + . += HEAP_SIZE; + . = ALIGN(16); + _eheap = .; + + _stack = .; + . += STACK_SIZE; + . = ALIGN(16); + _estack = .; + } + + .initctx : { + /* Initial contents of stack. This MUST BE just after the stack. */ + *(.initctx) + } + + _end = .; + + /DISCARD/ : { *(.comment) *(.note) } +} diff --git a/arch/amd64/lib.c b/arch/amd64/lib.c new file mode 100644 index 0000000..88cd79e --- /dev/null +++ b/arch/amd64/lib.c @@ -0,0 +1,58 @@ +/* lib.c + * tag: simple function library + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "asm/types.h" +#include +#include "libc/stdlib.h" +#include "libc/vsprintf.h" +#include "openbios/kernel.h" + +/* Format a string and print it on the screen, just like the libc + * function printf. + */ +int printk( const char *fmt, ... ) +{ + char *p, buf[512]; /* XXX: no buffer overflow protection... */ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + + for( p=buf; *p; p++ ) + putchar(*p); + return i; +} + +// dumb quick memory allocator until we get a decent thing here. + +#define MEMSIZE 128*1024 +static char memory[MEMSIZE]; +static void *memptr=memory; +static int memsize=MEMSIZE; + +void *malloc(int size) +{ + void *ret=(void *)0; + if(memsize>=size) { + memsize-=size; + ret=memptr; + memptr+=size; + } + return ret; +} + +void free(void *ptr) +{ + /* Nothing yet */ +} + + diff --git a/arch/amd64/linux_load.c b/arch/amd64/linux_load.c new file mode 100644 index 0000000..3fc40e2 --- /dev/null +++ b/arch/amd64/linux_load.c @@ -0,0 +1,647 @@ +/* + * Linux/i386 loader + * Supports bzImage, zImage and Image format. + * + * Based on work by Steve Gehlbach. + * Portions are taken from mkelfImage. + * + * 2003-09 by SONE Takeshi + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/bindings.h" +#include "sys_info.h" +#include "context.h" +#include "segment.h" +#include "loadfs.h" + +#define printf printk +#define debug printk +#define strtoull_with_suffix strtol + +#define LINUX_PARAM_LOC 0x90000 +#define COMMAND_LINE_LOC 0x91000 +#define GDT_LOC 0x92000 +#define STACK_LOC 0x93000 + +#define E820MAX 32 /* number of entries in E820MAP */ +struct e820entry { + unsigned long long addr; /* start of memory segment */ + unsigned long long size; /* size of memory segment */ + unsigned long type; /* type of memory segment */ +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ +#define E820_NVS 4 +}; + +/* The header of Linux/i386 kernel */ +struct linux_header { + uint8_t reserved1[0x1f1]; /* 0x000 */ + uint8_t setup_sects; /* 0x1f1 */ + uint16_t root_flags; /* 0x1f2 */ + uint8_t reserved2[6]; /* 0x1f4 */ + uint16_t vid_mode; /* 0x1fa */ + uint16_t root_dev; /* 0x1fc */ + uint16_t boot_sector_magic; /* 0x1fe */ + /* 2.00+ */ + uint8_t reserved3[2]; /* 0x200 */ + uint8_t header_magic[4]; /* 0x202 */ + uint16_t protocol_version; /* 0x206 */ + uint32_t realmode_swtch; /* 0x208 */ + uint16_t start_sys; /* 0x20c */ + uint16_t kver_addr; /* 0x20e */ + uint8_t type_of_loader; /* 0x210 */ + uint8_t loadflags; /* 0x211 */ + uint16_t setup_move_size; /* 0x212 */ + uint32_t code32_start; /* 0x214 */ + uint32_t ramdisk_image; /* 0x218 */ + uint32_t ramdisk_size; /* 0x21c */ + uint8_t reserved4[4]; /* 0x220 */ + /* 2.01+ */ + uint16_t heap_end_ptr; /* 0x224 */ + uint8_t reserved5[2]; /* 0x226 */ + /* 2.02+ */ + uint32_t cmd_line_ptr; /* 0x228 */ + /* 2.03+ */ + uint32_t initrd_addr_max; /* 0x22c */ +} __attribute__ ((packed)); + + +/* Paramters passed to 32-bit part of Linux + * This is another view of the structure above.. */ +struct linux_params { + uint8_t orig_x; /* 0x00 */ + uint8_t orig_y; /* 0x01 */ + uint16_t ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */ + uint16_t orig_video_page; /* 0x04 */ + uint8_t orig_video_mode; /* 0x06 */ + uint8_t orig_video_cols; /* 0x07 */ + uint16_t unused2; /* 0x08 */ + uint16_t orig_video_ega_bx; /* 0x0a */ + uint16_t unused3; /* 0x0c */ + uint8_t orig_video_lines; /* 0x0e */ + uint8_t orig_video_isVGA; /* 0x0f */ + uint16_t orig_video_points; /* 0x10 */ + + /* VESA graphic mode -- linear frame buffer */ + uint16_t lfb_width; /* 0x12 */ + uint16_t lfb_height; /* 0x14 */ + uint16_t lfb_depth; /* 0x16 */ + uint32_t lfb_base; /* 0x18 */ + uint32_t lfb_size; /* 0x1c */ + uint16_t cl_magic; /* 0x20 */ +#define CL_MAGIC_VALUE 0xA33F + uint16_t cl_offset; /* 0x22 */ + uint16_t lfb_linelength; /* 0x24 */ + uint8_t red_size; /* 0x26 */ + uint8_t red_pos; /* 0x27 */ + uint8_t green_size; /* 0x28 */ + uint8_t green_pos; /* 0x29 */ + uint8_t blue_size; /* 0x2a */ + uint8_t blue_pos; /* 0x2b */ + uint8_t rsvd_size; /* 0x2c */ + uint8_t rsvd_pos; /* 0x2d */ + uint16_t vesapm_seg; /* 0x2e */ + uint16_t vesapm_off; /* 0x30 */ + uint16_t pages; /* 0x32 */ + uint8_t reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */ + + //struct apm_bios_info apm_bios_info; /* 0x40 */ + uint8_t apm_bios_info[0x40]; + //struct drive_info_struct drive_info; /* 0x80 */ + uint8_t drive_info[0x20]; + //struct sys_desc_table sys_desc_table; /* 0xa0 */ + uint8_t sys_desc_table[0x140]; + uint32_t alt_mem_k; /* 0x1e0 */ + uint8_t reserved5[4]; /* 0x1e4 */ + uint8_t e820_map_nr; /* 0x1e8 */ + uint8_t reserved6[9]; /* 0x1e9 */ + uint16_t mount_root_rdonly; /* 0x1f2 */ + uint8_t reserved7[4]; /* 0x1f4 */ + uint16_t ramdisk_flags; /* 0x1f8 */ +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 + uint8_t reserved8[2]; /* 0x1fa */ + uint16_t orig_root_dev; /* 0x1fc */ + uint8_t reserved9[1]; /* 0x1fe */ + uint8_t aux_device_info; /* 0x1ff */ + uint8_t reserved10[2]; /* 0x200 */ + uint8_t param_block_signature[4]; /* 0x202 */ + uint16_t param_block_version; /* 0x206 */ + uint8_t reserved11[8]; /* 0x208 */ + uint8_t loader_type; /* 0x210 */ +#define LOADER_TYPE_LOADLIN 1 +#define LOADER_TYPE_BOOTSECT_LOADER 2 +#define LOADER_TYPE_SYSLINUX 3 +#define LOADER_TYPE_ETHERBOOT 4 +#define LOADER_TYPE_KERNEL 5 + uint8_t loader_flags; /* 0x211 */ + uint8_t reserved12[2]; /* 0x212 */ + uint32_t kernel_start; /* 0x214 */ + uint32_t initrd_start; /* 0x218 */ + uint32_t initrd_size; /* 0x21c */ + uint8_t reserved12_5[8]; /* 0x220 */ + uint32_t cmd_line_ptr; /* 0x228 */ + uint8_t reserved13[164]; /* 0x22c */ + struct e820entry e820_map[E820MAX]; /* 0x2d0 */ + uint8_t reserved16[688]; /* 0x550 */ +#define COMMAND_LINE_SIZE 256 + /* Command line is copied here by 32-bit i386/kernel/head.S. + * So I will follow the boot protocol, rather than putting it + * directly here. --ts1 */ + uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */ + uint8_t reserved17[1792]; /* 0x900 - 0x1000 */ +}; + +uint64_t forced_memsize; + +/* Load the first part the file and check if it's Linux */ +static uint32_t load_linux_header(struct linux_header *hdr) +{ + int load_high; + uint32_t kern_addr; + + if (lfile_read(hdr, sizeof *hdr) != sizeof *hdr) { + debug("Can't read Linux header\n"); + return 0; + } + if (hdr->boot_sector_magic != 0xaa55) { + debug("Not a Linux kernel image\n"); + return 0; + } + + /* Linux is found. Print some information */ + if (memcmp(hdr->header_magic, "HdrS", 4) != 0) { + /* This may be floppy disk image or something. + * Perform a simple (incomplete) sanity check. */ + if (hdr->setup_sects >= 16 + || file_size() - (hdr->setup_sects<<9) >= 512<<10) { + debug("This looks like a bootdisk image but not like Linux...\n"); + return 0; + } + + printf("Possible very old Linux"); + /* This kernel does not even have a protocol version. + * Force the value. */ + hdr->protocol_version = 0; /* pre-2.00 */ + } else + printf("Found Linux"); + if (hdr->protocol_version >= 0x200 && hdr->kver_addr) { + char kver[256]; + file_seek(hdr->kver_addr + 0x200); + if (lfile_read(kver, sizeof kver) != 0) { + kver[255] = 0; + printf(" version %s", kver); + } + } + debug(" (protocol %#x)", hdr->protocol_version); + load_high = 0; + if (hdr->protocol_version >= 0x200) { + debug(" (loadflags %#x)", hdr->loadflags); + load_high = hdr->loadflags & 1; + } + if (load_high) { + printf(" bzImage"); + kern_addr = 0x100000; + } else { + printf(" zImage or Image"); + kern_addr = 0x1000; + } + printf(".\n"); + + return kern_addr; +} + +/* Set up parameters for 32-bit kernel */ +static void +init_linux_params(struct linux_params *params, struct linux_header *hdr) +{ + debug("Setting up paramters at %#lx\n", virt_to_phys(params)); + memset(params, 0, sizeof *params); + + /* Copy some useful values from header */ + params->mount_root_rdonly = hdr->root_flags; + params->orig_root_dev = hdr->root_dev; + + /* Video parameters. + * This assumes we have VGA in standard 80x25 text mode, + * just like our vga.c does. + * Cursor position is filled later to allow some more printf's. */ + params->orig_video_mode = 3; + params->orig_video_cols = 80; + params->orig_video_lines = 25; + params->orig_video_isVGA = 1; + params->orig_video_points = 16; + + params->loader_type = 0xff; /* Unregistered Linux loader */ +} + +/* Memory map */ +static void +set_memory_size(struct linux_params *params, struct sys_info *info) +{ + int i; + uint64_t end; + uint32_t ramtop = 0; + struct e820entry *linux_map; + struct memrange *filo_map; + + linux_map = params->e820_map; + filo_map = info->memrange; + for (i = 0; i < info->n_memranges; i++, linux_map++, filo_map++) { + if (i < E820MAX) { + /* Convert to BIOS e820 style */ + linux_map->addr = filo_map->base; + linux_map->size = filo_map->size; + linux_map->type = E820_RAM; + debug("%016Lx - %016Lx\n", linux_map->addr, + linux_map->addr + linux_map->size); + params->e820_map_nr = i+1; + } + + /* Find out top of RAM. XXX This ignores hole above 1MB */ + end = filo_map->base + filo_map->size; + if (end < (1ULL << 32)) { /* don't count memory above 4GB */ + if (end > ramtop) + ramtop = (uint32_t) end; + } + } + debug("ramtop=%#x\n", ramtop); + /* Size of memory above 1MB in KB */ + params->alt_mem_k = (ramtop - (1<<20)) >> 10; + /* old style, 64MB max */ + if (ramtop >= (64<<20)) + params->ext_mem_k = (63<<10); + else + params->ext_mem_k = params->alt_mem_k; + debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k); +} + +/* + * Parse command line + * Some parameters, like initrd=, are not passed to kernel, + * we are responsible to process them. + * Parameters for kernel are copied to kern_cmdline. Returns name of initrd. + */ +static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline) +{ + const char *start, *sep, *end, *val; + char name[64]; + int len; + int k_len; + int to_kern; + char *initrd = 0; + int toolong = 0; + + forced_memsize = 0; + + if (!orig_cmdline) { + *kern_cmdline = 0; + return 0; + } + + k_len = 0; + debug("original command line: \"%s\"\n", orig_cmdline); + debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline)); + + start = orig_cmdline; + while (*start == ' ') + start++; + while (*start) { + end = strchr(start, ' '); + if (!end) + end = start + strlen(start); + sep = strchr(start, '='); + if (!sep || sep > end) + sep = end; + len = sep - start; + if (len >= sizeof(name)) + len = sizeof(name) - 1; + memcpy(name, start, len); + name[len] = 0; + + if (*sep == '=') { + val = sep + 1; + len = end - val; + } else { + val = 0; + len = 0; + } + + /* Only initrd= and mem= are handled here. vga= is not, + * which I believe is a paramter to the realmode part of Linux, + * which we don't execute. */ + if (strcmp(name, "initrd") == 0) { + if (!val) + printf("Missing filename to initrd parameter\n"); + else { + initrd = malloc(len + 1); + memcpy(initrd, val, len); + initrd[len] = 0; + debug("initrd=%s\n", initrd); + } + /* Don't pass this to kernel */ + to_kern = 0; + } else if (strcmp(name, "mem") == 0) { + if (!val) + printf("Missing value for mem parameter\n"); + else { + forced_memsize = strtoull_with_suffix(val, (char**)&val, 0); + if (forced_memsize == 0) + printf("Invalid mem option, ignored\n"); + if (val != end) { + printf("Garbage after mem=, ignored\n"); + forced_memsize = 0; + } + debug("mem=%Lu\n", forced_memsize); + } + /* mem= is for both loader and kernel */ + to_kern = 1; + } else + to_kern = 1; + + if (to_kern) { + /* Copy to kernel command line buffer */ + if (k_len != 0) + kern_cmdline[k_len++] = ' '; /* put separator */ + len = end - start; + if (k_len + len >= COMMAND_LINE_SIZE) { + len = COMMAND_LINE_SIZE - k_len - 1; + if (!toolong) { + printf("Kernel command line is too long; truncated to " + "%d bytes\n", COMMAND_LINE_SIZE-1); + toolong = 1; + } + } + memcpy(kern_cmdline + k_len, start, len); + k_len += len; + } + + start = end; + while (*start == ' ') + start++; + } + kern_cmdline[k_len] = 0; + debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline); + + return initrd; +} + +/* Set command line location */ +static void set_command_line_loc(struct linux_params *params, + struct linux_header *hdr) +{ + if (hdr->protocol_version >= 0x202) { + /* new style */ + params->cmd_line_ptr = COMMAND_LINE_LOC; + } else { + /* old style */ + params->cl_magic = CL_MAGIC_VALUE; + params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC; + } +} + +/* Load 32-bit part of kernel */ +static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr) +{ + uint32_t kern_offset, kern_size; + + if (hdr->setup_sects == 0) + hdr->setup_sects = 4; + kern_offset = (hdr->setup_sects + 1) * 512; + file_seek(kern_offset); + kern_size = file_size() - kern_offset; + debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size); + +#if 0 + if (using_devsize) { + printf("Attempt to load up to end of device as kernel; " + "specify the image size\n"); + return 0; + } +#endif + + printf("Loading kernel... "); + if (lfile_read(phys_to_virt(kern_addr), kern_size) != kern_size) { + printf("Can't read kernel\n"); + return 0; + } + printf("ok\n"); + + return kern_size; +} + +static int load_initrd(struct linux_header *hdr, struct sys_info *info, + uint32_t kern_end, struct linux_params *params, const char *initrd_file) +{ + uint32_t max; + uint32_t start, end, size; + uint64_t forced; + extern char _start[], _end[]; + + if (!file_open(initrd_file)) { + printf("Can't open initrd: %s\n", initrd_file); + return -1; + } + +#if 0 + if (using_devsize) { + printf("Attempt to load up to end of device as initrd; " + "specify the image size\n"); + return -1; + } +#endif + + size = file_size(); + + + /* Find out the kernel's restriction on how high the initrd can be + * placed */ + if (hdr->protocol_version >= 0x203) + max = hdr->initrd_addr_max; + else + max = 0x38000000; /* Hardcoded value for older kernels */ + + /* FILO itself is at the top of RAM. (relocated) + * So, try putting initrd just below us. */ + end = virt_to_phys(_start); + if (end > max) + end = max; + + /* If "mem=" option is given, we have to put the initrd within + * the specified range. */ + if (forced_memsize) { + forced = forced_memsize; + if (forced > max) + forced = max; + /* If the "mem=" is lower, it's easy */ + if (forced <= end) + end = forced; + else { + /* Otherwise, see if we can put it above us */ + if (virt_to_phys(_end) + size <= forced) + end = forced; /* Ok */ + } + } + + start = end - size; + start &= ~0xfff; /* page align */ + end = start + size; + + debug("start=%#x end=%#x\n", start, end); + + if (start < kern_end) { + printf("Initrd is too big to fit in memory\n"); + return -1; + } + + printf("Loading initrd... "); + if (lfile_read(phys_to_virt(start), size) != size) { + printf("Can't read initrd\n"); + return -1; + } + printf("ok\n"); + + params->initrd_start = start; + params->initrd_size = size; + + return 0; +} + +static void hardware_setup(void) +{ + /* Disable nmi */ + outb(0x80, 0x70); + + /* Make sure any coprocessor is properly reset.. */ + outb(0, 0xf0); + outb(0, 0xf1); + + /* we're getting screwed again and again by this problem of the 8259. + * so we're going to leave this lying around for inclusion into + * crt0.S on an as-needed basis. + * + * well, that went ok, I hope. Now we have to reprogram the interrupts :-( + * we put them right after the intel-reserved hardware interrupts, at + * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really + * messed this up with the original PC, and they haven't been able to + * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, + * which is used for the internal hardware interrupts as well. We just + * have to reprogram the 8259's, and it isn't fun. + */ + + outb(0x11, 0x20); /* initialization sequence to 8259A-1 */ + outb(0x11, 0xA0); /* and to 8259A-2 */ + + outb(0x20, 0x21); /* start of hardware int's (0x20) */ + outb(0x28, 0xA1); /* start of hardware int's 2 (0x28) */ + + outb(0x04, 0x21); /* 8259-1 is master */ + outb(0x02, 0xA1); /* 8259-2 is slave */ + + outb(0x01, 0x21); /* 8086 mode for both */ + outb(0x01, 0xA1); + + outb(0xFF, 0xA1); /* mask off all interrupts for now */ + outb(0xFB, 0x21); /* mask all irq's but irq2 which is cascaded */ +} + +/* Start Linux */ +static int start_linux(uint32_t kern_addr, struct linux_params *params) +{ + struct segment_desc *linux_gdt; + struct context *ctx; + //extern int cursor_x, cursor_y; + + ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0); + + /* Linux expects GDT being in low memory */ + linux_gdt = phys_to_virt(GDT_LOC); + memset(linux_gdt, 0, 13*sizeof(struct segment_desc)); + /* Normal kernel code/data segments */ + linux_gdt[2] = gdt[FLAT_CODE]; + linux_gdt[3] = gdt[FLAT_DATA]; + /* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible + * segments (2 and 3), so it SHOULD not be a problem. + * However, some distro kernels (eg. RH9) with backported threading + * patch use 12 and 13 also when booting... */ + linux_gdt[12] = gdt[FLAT_CODE]; + linux_gdt[13] = gdt[FLAT_DATA]; + ctx->gdt_base = GDT_LOC; + ctx->gdt_limit = 14*8-1; + ctx->cs = 0x10; + ctx->ds = 0x18; + ctx->es = 0x18; + ctx->fs = 0x18; + ctx->gs = 0x18; + ctx->ss = 0x18; + + /* Parameter location */ + ctx->esi = virt_to_phys(params); + + /* Entry point */ + ctx->eip = kern_addr; + + debug("eip=%#x\n", kern_addr); + printf("Jumping to entry point...\n"); + +#ifdef VGA_CONSOLE + /* Update VGA cursor position. + * This must be here because the printf changes the value! */ + params->orig_x = cursor_x; + params->orig_y = cursor_y; +#endif + + /* Go... */ + ctx = switch_to(ctx); + + /* It's impossible but... */ + printf("Returned with eax=%#x\n", ctx->eax); + + return ctx->eax; +} + +int linux_load(struct sys_info *info, const char *file, const char *cmdline) +{ + struct linux_header hdr; + struct linux_params *params; + uint32_t kern_addr, kern_size; + char *initrd_file = 0; + + if (!file_open(file)) + return -1; + + kern_addr = load_linux_header(&hdr); + if (kern_addr == 0) + return LOADER_NOT_SUPPORT; + + params = phys_to_virt(LINUX_PARAM_LOC); + init_linux_params(params, &hdr); + set_memory_size(params, info); + initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC)); + set_command_line_loc(params, &hdr); + + kern_size = load_linux_kernel(&hdr, kern_addr); + if (kern_size == 0) { + if (initrd_file) + free(initrd_file); + return -1; + } + + if (initrd_file) { + if (load_initrd(&hdr, info, kern_addr+kern_size, params, initrd_file) + != 0) { + free(initrd_file); + return -1; + } + free(initrd_file); + } + + hardware_setup(); + + start_linux(kern_addr, params); + return 0; +} diff --git a/arch/amd64/loadfs.c b/arch/amd64/loadfs.c new file mode 100644 index 0000000..6081b01 --- /dev/null +++ b/arch/amd64/loadfs.c @@ -0,0 +1,46 @@ +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "libc/diskio.h" +#include "loadfs.h" + +static int load_fd=-1; + +int file_open(const char *filename) +{ + load_fd=open_io(filename); + /* if(load_fd!=-1) */ seek_io(load_fd, 0); + return load_fd>-1; +} + +int lfile_read(void *buf, unsigned long len) +{ + int ret; + ret=read_io(load_fd, buf, len); + return ret; +} + +int file_seek(unsigned long offset) +{ + return seek_io(load_fd, offset); +} + +unsigned long file_size(void) +{ + llong fpos, fsize; + + /* save current position */ + fpos=tell(load_fd); + + /* go to end of file and get position */ + seek_io(load_fd, -1); + fsize=tell(load_fd); + + /* go back to old position */ + seek_io(load_fd, 0); + seek_io(load_fd, fpos); + + return fsize; +} + + + diff --git a/arch/amd64/loadfs.h b/arch/amd64/loadfs.h new file mode 100644 index 0000000..71b39c1 --- /dev/null +++ b/arch/amd64/loadfs.h @@ -0,0 +1,7 @@ +int file_open(const char *filename); +int lfile_read(void *buf, unsigned long len); +int file_seek(unsigned long offset); +unsigned long file_size(void); + + + diff --git a/arch/amd64/multiboot.c b/arch/amd64/multiboot.c new file mode 100644 index 0000000..c35ab0f --- /dev/null +++ b/arch/amd64/multiboot.c @@ -0,0 +1,125 @@ +/* Support for Multiboot */ + +#include "openbios/config.h" +#include "asm/io.h" +#include "sys_info.h" +#include "multiboot.h" + +#define printf printk +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +struct mbheader { + unsigned int magic, flags, checksum; +}; +const struct mbheader multiboot_header + __attribute__((section (".hdr"))) = +{ + MULTIBOOT_HEADER_MAGIC, + MULTIBOOT_HEADER_FLAGS, + -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) +}; + +/* Multiboot information structure, provided by loader to us */ + +struct multiboot_mmap { + unsigned entry_size; + unsigned base_lo, base_hi; + unsigned size_lo, size_hi; + unsigned type; +}; + +#define MULTIBOOT_MEM_VALID 0x01 +#define MULTIBOOT_BOOT_DEV_VALID 0x02 +#define MULTIBOOT_CMDLINE_VALID 0x04 +#define MULTIBOOT_MODS_VALID 0x08 +#define MULTIBOOT_AOUT_SYMS_VALID 0x10 +#define MULTIBOOT_ELF_SYMS_VALID 0x20 +#define MULTIBOOT_MMAP_VALID 0x40 + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ + struct multiboot_info *mbinfo; + struct multiboot_mmap *mbmem; + unsigned mbcount, mbaddr; + int i; + struct memrange *mmap; + int mmap_count; + module_t *mod; + + if (info->boot_type != 0x2BADB002) + return; + + debug("Using Multiboot information at %#lx\n", info->boot_data); + + mbinfo = phys_to_virt(info->boot_data); + + if (mbinfo->mods_count != 1) { + printf("Multiboot: no dictionary\n"); + return; + } + + mod = (module_t *) mbinfo->mods_addr; + info->dict_start=(unsigned long *)mod->mod_start; + info->dict_end=(unsigned long *)mod->mod_end; + + if (mbinfo->flags & MULTIBOOT_MMAP_VALID) { + /* convert mmap records */ + mbmem = phys_to_virt(mbinfo->mmap_addr); + mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4); + mmap = malloc(mbcount * sizeof(struct memrange)); + mmap_count = 0; + mbaddr = mbinfo->mmap_addr; + for (i = 0; i < mbcount; i++) { + mbmem = phys_to_virt(mbaddr); + debug("%08x%08x %08x%08x (%d)\n", + mbmem->base_hi, + mbmem->base_lo, + mbmem->size_hi, + mbmem->size_lo, + mbmem->type); + if (mbmem->type == 1) { /* Only normal RAM */ + mmap[mmap_count].base = mbmem->base_lo + + (((unsigned long long) mbmem->base_hi) << 32); + mmap[mmap_count].size = mbmem->size_lo + + (((unsigned long long) mbmem->size_hi) << 32); + mmap_count++; + } + mbaddr += mbmem->entry_size + 4; + if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length) + break; + } + /* simple sanity check - there should be at least 2 RAM segments + * (base 640k and extended) */ + if (mmap_count >= 2) + goto got_it; + + printf("Multiboot mmap is broken\n"); + free(mmap); + /* fall back to mem_lower/mem_upper */ + } + + if (mbinfo->flags & MULTIBOOT_MEM_VALID) { + /* use mem_lower and mem_upper */ + mmap_count = 2; + mmap = malloc(2 * sizeof(*mmap)); + mmap[0].base = 0; + mmap[0].size = mbinfo->mem_lower << 10; + mmap[1].base = 1 << 20; /* 1MB */ + mmap[1].size = mbinfo->mem_upper << 10; + goto got_it; + } + + printf("Can't get memory information from Multiboot\n"); + return; + +got_it: + info->memrange = mmap; + info->n_memranges = mmap_count; + + return; +} diff --git a/arch/amd64/multiboot.h b/arch/amd64/multiboot.h new file mode 100644 index 0000000..14e1e03 --- /dev/null +++ b/arch/amd64/multiboot.h @@ -0,0 +1,96 @@ +/* multiboot.h + * tag: header for multiboot + * + * Copyright (C) 2003-2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +/* magic number for multiboot header */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* flags for multiboot header */ +#define MULTIBOOT_HEADER_FLAGS 0x00010003 + +/* magic number passed by multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (8KB). */ +#define STACK_SIZE 0x2000 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* We don't want these declarations in boot.S */ + +/* multiboot header */ +typedef struct multiboot_header { + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* symbol table for a.out */ +typedef struct aout_symbol_table { + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* section header table for ELF */ +typedef struct elf_section_header_table { + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* multiboot information */ +typedef struct multiboot_info { + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; +} multiboot_info_t; + +/* module structure */ +typedef struct module { + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map { + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +#endif /* ! ASM */ diff --git a/arch/amd64/openbios.c b/arch/amd64/openbios.c new file mode 100644 index 0000000..c756fbc --- /dev/null +++ b/arch/amd64/openbios.c @@ -0,0 +1,109 @@ +/* tag: openbios forth environment, executable code + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "asm/types.h" +#include "dict.h" +#include "openbios/kernel.h" +#include "openbios/stack.h" +#include "sys_info.h" +#include "openbios.h" +#include "relocate.h" + +void boot(void); +void ob_ide_init(void); + +static char intdict[256 * 1024]; + +static void init_memory(void) +{ + /* push start and end of available memory to the stack + * so that the forth word QUIT can initialize memory + * management. For now we use hardcoded memory between + * 0x10000 and 0x9ffff (576k). If we need more memory + * than that we have serious bloat. + */ + + PUSH(0x10000); + PUSH(0x9FFFF); +} + +void exception(cell no) +{ + /* The exception mechanism is used during bootstrap to catch + * build errors. In a running system this is a noop since we + * can't break out to the unix host os anyways. + */ +} + +static void +arch_init( void ) +{ + void setup_timers(void); + + modules_init(); +#ifdef CONFIG_DRIVER_IDE + setup_timers(); + ob_ide_init(); +#endif + device_end(); + bind_func("platform-boot", boot ); +} + +int openbios(void) +{ + extern struct sys_info sys_info; +#ifdef CONFIG_DEBUG_CONSOLE +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED); +#endif + /* Clear the screen. */ + cls(); +#endif + + collect_sys_info(&sys_info); + + dict=intdict; + load_dictionary((char *)sys_info.dict_start, + sys_info.dict_end-sys_info.dict_start); + + relocate(&sys_info); + +#ifdef CONFIG_DEBUG_CONSOLE + video_init(); +#endif +#ifdef CONFIG_DEBUG_BOOT + printk("forth started.\n"); + printk("initializing memory..."); +#endif + + init_memory(); + +#ifdef CONFIG_DEBUG_BOOT + printk("done\n"); +#endif + + PUSH_xt( bind_noname_func(arch_init) ); + fword("PREPOST-initializer"); + + PC = (ucell)findword("initialize-of"); + + if (!PC) { + printk("panic: no dictionary entry point.\n"); + return -1; + } +#ifdef CONFIG_DEBUG_DICTIONARY + printk("done (%d bytes).\n", dicthead); + printk("Jumping to dictionary...\n"); +#endif + + enterforth((xt_t)PC); + + return 0; +} diff --git a/arch/amd64/openbios.h b/arch/amd64/openbios.h new file mode 100644 index 0000000..f4df27d --- /dev/null +++ b/arch/amd64/openbios.h @@ -0,0 +1,29 @@ +/* + * Creation Date: <2004/01/15 16:14:05 samuel> + * Time-stamp: <2004/01/15 16:14:05 samuel> + * + * + * + * + * + * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_OPENBIOS +#define _H_OPENBIOS + +int openbios(void); + +/* console.c */ +extern void cls(void); +#ifdef CONFIG_DEBUG_CONSOLE +extern int uart_init(int port, unsigned long speed); +extern void video_init(void); +#endif + +#endif /* _H_OPENBIOS */ diff --git a/arch/amd64/plainboot.c b/arch/amd64/plainboot.c new file mode 100644 index 0000000..e09af50 --- /dev/null +++ b/arch/amd64/plainboot.c @@ -0,0 +1,22 @@ +/* tag: openbios fixed address forth starter + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "sys_info.h" +#include "multiboot.h" + +#define FIXED_DICTSTART 0xfffe0000 +#define FIXED_DICTEND 0xfffeffff + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ + info->dict_start=(unsigned long *)FIXED_DICTSTART; + info->dict_end=(unsigned long *)FIXED_DICTEND; +} + diff --git a/arch/amd64/relocate.h b/arch/amd64/relocate.h new file mode 100644 index 0000000..2087540 --- /dev/null +++ b/arch/amd64/relocate.h @@ -0,0 +1,2 @@ +void relocate(struct sys_info *); + diff --git a/arch/amd64/segment.c b/arch/amd64/segment.c new file mode 100644 index 0000000..4f40083 --- /dev/null +++ b/arch/amd64/segment.c @@ -0,0 +1,134 @@ +/* Segmentation of the AMD64 architecture. + * + * 2003-07 by SONE Takeshi + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "sys_info.h" +#include "relocate.h" +#include "segment.h" + +#define printf printk +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +/* i386 lgdt argument */ +struct gdtarg { + unsigned short limit; + unsigned int base; +} __attribute__((packed)); + +/* How far the virtual address (used in C) is different from physical + * address. Since we start in flat mode, the initial value is zero. */ +unsigned long virt_offset = 0; + +/* GDT, the global descriptor table */ +struct segment_desc gdt[NUM_SEG] = { + /* 0x00: null segment */ + {0, 0, 0, 0, 0, 0}, + /* 0x08: flat code segment */ + {0xffff, 0, 0, 0x9f, 0xcf, 0}, + /* 0x10: flat data segment */ + {0xffff, 0, 0, 0x93, 0xcf, 0}, + /* 0x18: code segment for relocated execution */ + {0xffff, 0, 0, 0x9f, 0xcf, 0}, + /* 0x20: data segment for relocated execution */ + {0xffff, 0, 0, 0x93, 0xcf, 0}, +}; + +extern char _start[], _end[]; + +void relocate(struct sys_info *info) +{ + int i; + unsigned long prog_addr; + unsigned long prog_size; + unsigned long addr, new_base; + unsigned long long segsize; + unsigned long new_offset; + unsigned d0, d1, d2; + struct gdtarg gdtarg; +#define ALIGNMENT 16 + + prog_addr = virt_to_phys(&_start); + prog_size = virt_to_phys(&_end) - virt_to_phys(&_start); + debug("Current location: %#lx-%#lx\n", prog_addr, prog_addr+prog_size-1); + + new_base = 0; + for (i = 0; i < info->n_memranges; i++) { + if (info->memrange[i].base >= 1ULL<<32) + continue; + segsize = info->memrange[i].size; + if (info->memrange[i].base + segsize > 1ULL<<32) + segsize = (1ULL<<32) - info->memrange[i].base; + if (segsize < prog_size+ALIGNMENT) + continue; + addr = info->memrange[i].base + segsize - prog_size; + addr &= ~(ALIGNMENT-1); + if (addr >= prog_addr && addr < prog_addr + prog_size) + continue; + if (prog_addr >= addr && prog_addr < addr + prog_size) + continue; + if (addr > new_base) + new_base = addr; + } + if (new_base == 0) { + printf("Can't find address to relocate\n"); + return; + } + + debug("Relocating to %#lx-%#lx... ", + new_base, new_base + prog_size - 1); + + /* New virtual address offset */ + new_offset = new_base - (unsigned long) &_start; + + /* Tweak the GDT */ + gdt[RELOC_CODE].base_0 = (unsigned short) new_offset; + gdt[RELOC_CODE].base_16 = (unsigned char) (new_offset>>16); + gdt[RELOC_CODE].base_24 = (unsigned char) (new_offset>>24); + gdt[RELOC_DATA].base_0 = (unsigned short) new_offset; + gdt[RELOC_DATA].base_16 = (unsigned char) (new_offset>>16); + gdt[RELOC_DATA].base_24 = (unsigned char) (new_offset>>24); + + /* Load new GDT and reload segments */ + gdtarg.base = new_offset + (unsigned long) gdt; + gdtarg.limit = GDT_LIMIT; + __asm__ __volatile__ ( + "rep; movsb\n\t" /* copy everything */ + "lgdt %3\n\t" + "ljmp %4, $1f\n1:\t" + "movw %5, %%ds\n\t" + "movw %5, %%es\n\t" + "movw %5, %%fs\n\t" + "movw %5, %%gs\n\t" + "movw %5, %%ss\n" + : "=&S" (d0), "=&D" (d1), "=&c" (d2) + : "m" (gdtarg), "n" (RELOC_CS), "q" ((unsigned short) RELOC_DS), + "0" (&_start), "1" (new_base), "2" (prog_size)); + + virt_offset = new_offset; + debug("ok\n"); +} + +#if 0 +/* Copy GDT to new location and reload it */ +void move_gdt(unsigned long newgdt) +{ + struct gdtarg gdtarg; + + debug("Moving GDT to %#lx...", newgdt); + memcpy(phys_to_virt(newgdt), gdt, sizeof gdt); + gdtarg.base = newgdt; + gdtarg.limit = GDT_LIMIT; + debug("reloading GDT..."); + __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg)); + debug("reloading CS for fun..."); + __asm__ __volatile__ ("ljmp %0, $1f\n1:" : : "n" (RELOC_CS)); + debug("ok\n"); +} +#endif diff --git a/arch/amd64/segment.h b/arch/amd64/segment.h new file mode 100644 index 0000000..0371a80 --- /dev/null +++ b/arch/amd64/segment.h @@ -0,0 +1,30 @@ + +/* Segment indexes. Must match the gdt definition in segment.c. */ +enum { + NULL_SEG, + FLAT_CODE, + FLAT_DATA, + RELOC_CODE, + RELOC_DATA, + NUM_SEG, +}; + +/* Values for segment selector register */ +#define FLAT_CS (FLAT_CODE << 3) +#define FLAT_DS (FLAT_DATA << 3) +#define RELOC_CS (RELOC_CODE << 3) +#define RELOC_DS (RELOC_DATA << 3) + +/* i386 segment descriptor */ +struct segment_desc { + unsigned short limit_0; + unsigned short base_0; + unsigned char base_16; + unsigned char types; + unsigned char flags; + unsigned char base_24; +}; + +extern struct segment_desc gdt[NUM_SEG]; + +#define GDT_LIMIT ((NUM_SEG << 3) - 1) diff --git a/arch/amd64/switch.S b/arch/amd64/switch.S new file mode 100644 index 0000000..76ac75b --- /dev/null +++ b/arch/amd64/switch.S @@ -0,0 +1,116 @@ + .globl entry, __switch_context, __exit_context, halt + + .text + .align 4 + +/* + * Entry point + * We start execution from here. + * It is assumed that CPU is in 32-bit protected mode and + * all segments are 4GB and base zero (flat model). + */ +entry: + /* Save boot context and switch to our main context. + * Main context is statically defined in C. + */ + pushl %cs + call __switch_context + + /* We get here when the main context switches back to + * the boot context. + * Return to previous bootloader. + */ + ret + +/* + * Switch execution context + * This saves registers, segments, and GDT in the stack, then + * switches the stack, and restores everything from the new stack. + * This function takes no argument. New stack pointer is + * taken from global variable __context, and old stack pointer + * is also saved to __context. This way we can just jump to + * this routine to get back to the original context. + * + * Call this routine with lcall or pushl %cs; call. + */ +__switch_context: + /* Save everything in current stack */ + pushfl /* 56 */ + pushl %ds /* 52 */ + pushl %es /* 48 */ + pushl %fs /* 44 */ + pushl %gs /* 40 */ + pushal /* 8 */ + subl $8, %esp + movw %ss, (%esp) /* 0 */ + sgdt 2(%esp) /* 2 */ + +#if 0 + /* Swap %cs and %eip on the stack, so lret will work */ + movl 60(%esp), %eax + xchgl %eax, 64(%esp) + movl %eax, 60(%esp) +#endif + + /* At this point we don't know if we are on flat segment + * or relocated. So compute the address offset from %eip. + * Assuming CS.base==DS.base==SS.base. + */ + call 1f +1: popl %ebx + subl $1b, %ebx + + /* Interrupts are not allowed... */ + cli + + /* Current context pointer is our stack pointer */ + movl %esp, %esi + + /* Normalize the ctx pointer */ + subl %ebx, %esi + + /* Swap it with new value */ + xchgl %esi, __context(%ebx) + + /* Adjust new ctx pointer for current address offset */ + addl %ebx, %esi + + /* Load new %ss and %esp to temporary */ + movzwl (%esi), %edx + movl 20(%esi), %eax + + /* Load new GDT */ + lgdt 2(%esi) + + /* Load new stack segment with new GDT */ + movl %edx, %ss + + /* Set new stack pointer, but we have to adjust it because + * pushal saves %esp value before pushal, and we want the value + * after pushal. + */ + leal -32(%eax), %esp + + /* Load the rest from new stack */ + popal + popl %gs + popl %fs + popl %es + popl %ds + popfl + + /* Finally, load new %cs and %eip */ + lret + +__exit_context: + /* Get back to the original context */ + pushl %cs + call __switch_context + + /* We get here if the other context attempt to switch to this + * dead context. This should not happen. */ + +halt: + cli + hlt + jmp halt diff --git a/arch/amd64/sys_info.c b/arch/amd64/sys_info.c new file mode 100644 index 0000000..4cddcf0 --- /dev/null +++ b/arch/amd64/sys_info.c @@ -0,0 +1,57 @@ +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "sys_info.h" +#include "context.h" + +#define printf printk +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +void collect_multiboot_info(struct sys_info *); + +void collect_sys_info(struct sys_info *info) +{ + int i; + unsigned long long total = 0; + struct memrange *mmap; + + /* Pick up paramters given by bootloader to us */ + info->boot_type = boot_ctx->eax; + info->boot_data = boot_ctx->ebx; + info->boot_arg = boot_ctx->param[0]; + debug("boot eax = %#lx\n", info->boot_type); + debug("boot ebx = %#lx\n", info->boot_data); + debug("boot arg = %#lx\n", info->boot_arg); + + collect_elfboot_info(info); +#ifdef CONFIG_LINUXBIOS + collect_linuxbios_info(info); +#endif +#ifdef CONFIG_IMAGE_ELF_MULTIBOOT + collect_multiboot_info(info); +#endif + + if (!info->memrange) { + printf("Can't get memory map from firmware. " + "Using hardcoded default.\n"); + info->n_memranges = 2; + info->memrange = malloc(2 * sizeof(struct memrange)); + info->memrange[0].base = 0; + info->memrange[0].size = 640*1024; + info->memrange[1].base = 1024*1024; + info->memrange[1].size = 32*1024*1024 + - info->memrange[1].base; + } + + debug("\n"); + mmap=info->memrange; + for (i = 0; i < info->n_memranges; i++) { + debug("%016Lx-", mmap[i].base); + debug("%016Lx\n", mmap[i].base+mmap[i].size); + total += mmap[i].size; + } + debug("RAM %Ld MB\n", (total + 512*1024) >> 20); +} diff --git a/arch/build.xml b/arch/build.xml new file mode 100644 index 0000000..dde65be --- /dev/null +++ b/arch/build.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig new file mode 100644 index 0000000..572debb --- /dev/null +++ b/arch/ia64/Kconfig @@ -0,0 +1,24 @@ +mainmenu "OpenBIOS Configuration" + +config IPF + bool + default y + help + Building for IPF hardware. + +config LITTLE_ENDIAN + bool + default y + help + IPF is little endian. + +menu "Build hosted UNIX Binary" +source "arch/unix/Kconfig" +endmenu + +source "kernel/Kconfig" +source "forth/Kconfig" +source "modules/Kconfig" +source "drivers/Kconfig" + + diff --git a/arch/ia64/build.xml b/arch/ia64/build.xml new file mode 100644 index 0000000..bfb8930 --- /dev/null +++ b/arch/ia64/build.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig new file mode 100644 index 0000000..70cd97e --- /dev/null +++ b/arch/ia64/defconfig @@ -0,0 +1,65 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_IPF=y +CONFIG_LITTLE_ENDIAN=y + +# +# Kernel binaries (x86) +# +# CONFIG_IMAGE_ELF is not set +# CONFIG_IMAGE_ELF_EMBEDDED is not set +# CONFIG_IMAGE_ELF_MULTIBOOT is not set + +# +# Build hosted UNIX Binary +# +CONFIG_HOST_UNIX=y +# CONFIG_PLUGIN_PCI is not set + +# +# Kernel Debugging +# +# CONFIG_DEBUG is not set +CONFIG_DEBUG_CONSOLE=y +CONFIG_DEBUG_CONSOLE_SERIAL=y +CONFIG_SERIAL_PORT=1 +CONFIG_SERIAL_SPEED=115200 +CONFIG_DEBUG_CONSOLE_VGA=y + +# +# Module Configuration +# +CONFIG_CMDLINE=y +CONFIG_DEBLOCKER=y + +# +# Filesystem Configuration +# +CONFIG_DISK_LABEL=y +CONFIG_PART_SUPPORT=y +CONFIG_PC_PARTS=y +CONFIG_FS=y +CONFIG_GRUBFS=y +CONFIG_FSYS_EXT2FS=y +CONFIG_FSYS_FAT=y +CONFIG_FSYS_JFS=y +# CONFIG_FSYS_MINIX is not set +CONFIG_FSYS_REISERFS=y +CONFIG_FSYS_XFS=y +CONFIG_FSYS_ISO9660=y +# CONFIG_FSYS_FFS is not set +# CONFIG_FSYS_VSTAFS is not set +# CONFIG_DEBUG_FS is not set + +# +# Miscellaneous +# +CONFIG_LINUXBIOS=y + +# +# Drivers +# +CONFIG_DRIVER_PCI=y +CONFIG_DRIVER_IDE=y +# CONFIG_DEBUG_IDE is not set diff --git a/arch/ia64/init.fs b/arch/ia64/init.fs new file mode 100644 index 0000000..0d0d74a --- /dev/null +++ b/arch/ia64/init.fs @@ -0,0 +1,77 @@ +:noname + ." Type 'help' for detailed information" cr + \ ." boot secondary slave cdrom: " cr + \ ." 0 > boot hd:2,\boot\vmlinuz root=/dev/hda2" cr + ; DIAG-initializer + +" /" find-device + +new-device + " memory" device-name + \ 12230 encode-int " reg" property + external + : open true ; + : close ; + \ claim ( phys size align -- base ) + \ release ( phys size -- ) +finish-device + +new-device + " cpus" device-name + 1 " #address-cells" int-property + 0 " #size-cells" int-property + + external + : open true ; + : close ; + : decode-unit parse-hex ; + +finish-device + +: make-openable ( path ) + find-dev if + begin ?dup while + \ install trivial open and close methods + dup active-package! is-open + parent + repeat + then +; + +: preopen ( chosen-str node-path ) + 2dup make-openable + + " /chosen" find-device + open-dev ?dup if + encode-int 2swap property + else + 2drop + then +; + +:noname + set-defaults +; SYSTEM-initializer + +\ preopen device nodes (and store the ihandles under /chosen) +:noname + " memory" " /memory" preopen + " mmu" " /cpus/@0" preopen + " stdout" " /builtin/console" preopen + " stdin" " /builtin/console" preopen + +; SYSTEM-initializer + +\ use the tty interface if available +:noname + " /builtin/console" find-dev if drop + " /builtin/console" " input-device" $setenv + " /builtin/console" " output-device" $setenv + then +; SYSTEM-initializer + +:noname + " keyboard" input +; CONSOLE-IN-initializer + + diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig new file mode 100644 index 0000000..83e2f9e --- /dev/null +++ b/arch/ppc/Kconfig @@ -0,0 +1,48 @@ +mainmenu "OpenBIOS Configuration" + +config PPC + bool + default y + help + Building for PPC hardware. + +config BIG_ENDIAN + bool + default y + help + PPC hardware is big endian (per default) + +choice + prompt "Platform Type" + default MOL + +config MOL + bool "Mac-on-Linux" + help + Build an image for Mac-on-Linux + +config MPC107 + bool "MPC107 board (Crescendo)" + help + Build for Crescendo board. + +config BRIQ + bool "Total Impact briQ" + help + Build an image for the Total Impact briQ + +config NO_ARCH + bool "None" + help + Don't build any images. + +endchoice + +menu "Build hosted UNIX Binary" +source "arch/unix/Kconfig" +endmenu + +source "kernel/Kconfig" +source "forth/Kconfig" +source "modules/Kconfig" +source "drivers/Kconfig" diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile new file mode 100644 index 0000000..e182825 --- /dev/null +++ b/arch/ppc/Makefile @@ -0,0 +1,79 @@ + +include ../../config/Makefile.top + +SUBDIRS = +MOL = $(CONFIG_MOL:y=mol) +BRIQ = $(CONFIG_BRIQ:y=briq) +XTARGETS = $(MOL) $(BRIQ) ppc mollink +DICTIONARIES = $(MOL) $(BRIQ) + +INCLUDES = -I../../kernel -I../../kernel/include \ + -I../../include/molasm -I$(ODIR)/include + +############################################################################# + +mol-OBJS = mol/init.o mol/main.o mol/mol.o mol/console.o mol/osi-blk.o \ + mol/osi-scsi.o mol/pseudodisk.o mol/methods.o ofmem.o \ + mol/video.o mol/prom.o mol/tree.o misc.o mol/kernel.o + +briq-OBJS = briq/init.o briq/main.o briq/briq.o briq/vfd.o \ + ofmem.o briq/methods.o briq/tree.o \ + misc.o briq/kernel.o + +ppc-OBJS = $(KOBJS) $(MODULE_LIBS) \ + $(FS_LIBS) $(DRIVER_LIBS) $(LIBC_LIBS) + +all-$(CONFIG_MOL) += $(ODIR)/mol.image +all-$(CONFIG_BRIQ) += $(ODIR)/briq.image +all-$(CONFIG_MPC107) += $(ODIR)/mpc107.image + + +############################################################################# + +mol-SRC = ppc.fs tree.fs mol.fs $(ARCHDICT_SRC) +briq-SRC = ppc.fs briq/tree.fs briq/briq.fs $(ARCHDICT_SRC) + +$(ODIR)/mol/kernel.o: $(ODIR)/include/mol-dict.h +$(ODIR)/briq/kernel.o: $(ODIR)/include/briq-dict.h + +$(ODIR)/include/mol-dict.h: $(ODIR)/mol.dict + test -d $(dir $@) || $(INSTALL) -d $(dir $@) + @echo "static const char forth_dictionary[] = {" > $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@ + +$(ODIR)/include/briq-dict.h: $(ODIR)/briq.dict + test -d $(dir $@) || $(INSTALL) -d $(dir $@) + @echo "static const char forth_dictionary[] = {" > $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@ + +############################################################################# + +$(ODIR)/mol.image: $(ODIR)/start.o $(ODIR)/libmol.a $(ODIR)/libppc.a + @printf "= Building %-22s : " $@ + building= + $(LD) -Ttext=0x01e01000 -Bstatic $^ $(LIBGCC) -o $@ + @nm $@ | sort > $(ODIR)/mol.syms + strip -g $@ + @echo "ok" + +$(ODIR)/briq.image: $(ODIR)/start.o $(ODIR)/timebase.o $(ODIR)/libbriq.a $(ODIR)/libppc.a + @printf "= Building %-22s : " $@ + building= + $(LD) -g -Ttext=0x01e01000 -Bstatic $^ $(LIBGCC) -o $@ + @nm $@ | sort > $(ODIR)/briq.syms + #strip -g $@ + @echo "ok" + +$(ODIR)/mpc107.image: + @echo "BUILDING mpc107.image (not yet implemented)" + +clean-local: + $(RM) $(ODIR)/*.image $(ODIR)/*.syms $(ODIR)/include/mol-dict.h + +include Makefile.asm +include $(rules)/Rules.make +include $(rules)/Rules.forth diff --git a/arch/ppc/Makefile.asm b/arch/ppc/Makefile.asm new file mode 100644 index 0000000..32d4337 --- /dev/null +++ b/arch/ppc/Makefile.asm @@ -0,0 +1,32 @@ +# -*- makefile -*- +# +# Makefile.asm - assembly support +# +# Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# version 2 + + +################################################# +# Rules for asm targets +################################################# + +ASMFLAGS = -D__ASSEMBLY__ -I$(top_srcdir) $(ALTIVEC) +FILTERBIN = $(top_srcdir)/scripts/asfilter +ASFILTER = $(shell if test -x $(FILTERBIN) ; then echo $(FILTERBIN) \ + ; else echo "tr ';' '\n'" ; fi) +INVOKE_M4 = | $(M4) -s $(M4_NO_GNU) | $(ASFILTER) + +$(ODIR)/%.o: %.S + @printf " Compiling %-20s: " $(notdir $@) + assembly= + @install -d $(dir $@) + @$(RM) $@ $@.s + @$(CPP) $(ASMFLAGS) $(IDIRS) $< > /dev/null + $(CPP) $(ASMFLAGS) $(IDIRS) $(DEPFLAGS) $< $(INVOKE_M4) > $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + @$(DEPEXTRA) + @$(RM) $@.s + @echo "ok" diff --git a/arch/ppc/briq/briq.c b/arch/ppc/briq/briq.c new file mode 100644 index 0000000..dbd1706 --- /dev/null +++ b/arch/ppc/briq/briq.c @@ -0,0 +1,194 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Copyright (C) 2004, Greg Watson + * + * derived from mol.c + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/nvram.h" +#include "libc/vsprintf.h" +#include "libc/string.h" +#include "briq/briq.h" +#include + +#define UART_BASE 0x3f8 + +unsigned long virt_offset = 0; + +void +exit( int status ) +{ + for (;;); +} + +void +fatal_error( const char *err ) +{ + printk("Fatal error: %s\n", err ); + exit(0); +} + +void +panic( const char *err ) +{ + printk("Panic: %s\n", err ); + exit(0); + + /* won't come here... this keeps the gcc happy */ + for( ;; ) + ; +} + + +/************************************************************************/ +/* print using OSI interface */ +/************************************************************************/ + +static int do_indent; + +int +printk( const char *fmt, ... ) +{ + char *p, buf[1024]; /* XXX: no buffer overflow protection... */ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + + for( p=buf; *p; p++ ) { + if( *p == '\n' ) + do_indent = 0; + if( do_indent++ == 1 ) { + putchar( '>' ); + putchar( '>' ); + putchar( ' ' ); + } + putchar( *p ); + } + return i; +} + + +/************************************************************************/ +/* TTY iface */ +/************************************************************************/ + +static int ttychar = -1; + +static int +tty_avail( void ) +{ + return 1; +} + +static int +tty_putchar( int c ) +{ + if( tty_avail() ) { + while (!(inb(UART_BASE + 0x05) & 0x20)) + ; + outb(c, UART_BASE); + while (!(inb(UART_BASE + 0x05) & 0x40)) + ; + } + return c; +} + +int +availchar( void ) +{ + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + ttychar = inb(UART_BASE); + return (ttychar >= 0); +} + +int +getchar( void ) +{ + int ch; + + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + return inb(UART_BASE); + ch = ttychar; + ttychar = -1; + return ch; +} + +int +putchar( int c ) +{ + if (c == '\n') + tty_putchar('\r'); + return tty_putchar(c); +} + + +/************************************************************************/ +/* briQ specific stuff */ +/************************************************************************/ + +static char nvram[2048]; + +void +dump_nvram(void) +{ + static char hexdigit[] = "0123456789abcdef"; + int i; + for (i = 0; i < 16*4; i++) + { + printk ("%c", hexdigit[nvram[i] >> 4]); + printk ("%c", hexdigit[nvram[i] % 16]); + if (!((i + 1) % 16)) + { + printk ("\n"); + } + else + { + printk (" "); + } + } +} + + +int +arch_nvram_size( void ) +{ + return sizeof(nvram); +} + +void +arch_nvram_put( char *buf ) +{ + memcpy(nvram, buf, sizeof(nvram)); + printk("new nvram:\n"); + dump_nvram(); +} + +void +arch_nvram_get( char *buf ) +{ + memcpy(buf, nvram, sizeof(nvram)); + printk("current nvram:\n"); + dump_nvram(); +} diff --git a/arch/ppc/briq/briq.fs b/arch/ppc/briq/briq.fs new file mode 100644 index 0000000..78d7797 --- /dev/null +++ b/arch/ppc/briq/briq.fs @@ -0,0 +1,115 @@ +\ briq specific initialization code +\ +\ Copyright (C) 2004 Greg Watson +\ +\ This program is free software; you can redistribute it and/or +\ modify it under the terms of the GNU General Public License +\ as published by the Free Software Foundation +\ + + +\ ------------------------------------------------------------------------- +\ initialization +\ ------------------------------------------------------------------------- + +: make-openable ( path ) + find-dev if + begin ?dup while + \ install trivial open and close methods + dup active-package! is-open + parent + repeat + then +; + +: preopen ( chosen-str node-path ) + 2dup make-openable + + " /chosen" find-device + open-dev ?dup if + encode-int 2swap property + else + 2drop + then +; + +\ preopen device nodes (and store the ihandles under /chosen) +:noname + " rtc" " /pci/isa/rtc" preopen + " memory" " /memory" preopen + " mmu" " /cpu@0" preopen + " stdout" " /packages/terminal-emulator" preopen + " stdin" " keyboard" preopen + +; SYSTEM-initializer + + +\ ------------------------------------------------------------------------- +\ device tree fixing +\ ------------------------------------------------------------------------- + +\ add decode-address methods +: (make-decodable) ( phandle -- ) + + dup " #address-cells" rot get-package-property 0= if + decode-int nip nip + over " decode-unit" rot find-method if 2drop else + ( save phandle ncells ) + + over active-package! + case + 1 of ['] parse-hex " decode-unit" is-xt-func endof + 3 of + " bus-range" active-package get-package-property 0= if + decode-int nip nip + ['] encode-unit-pci " encode-unit" is-xt-func + " decode-unit" is-func-begin + ['] (lit) , , + ['] decode-unit-pci-bus , + is-func-end + then + endof + endcase + then + then + drop +; + +: init-briq-tree ( -- ) + active-package + + iterate-tree-begin + begin ?dup while + + dup (make-decodable) + + iterate-tree + repeat + + active-package! +; + +\ use the tty interface if available +: activate-tty-interface + " /packages/terminal-emulator" find-dev if drop + " /packages/terminal-emulator" " input-device" $setenv + " /packages/terminal-emulator" " output-device" $setenv + then +; + +:noname + " keyboard" input +; CONSOLE-IN-initializer + + +\ ------------------------------------------------------------------------- +\ pre-booting +\ ------------------------------------------------------------------------- + +: update-chosen + " /chosen" find-device + stdin @ encode-int " stdin" property + stdout @ encode-int " stdout" property + " /pci/isa/interrupt-controller" find-dev if encode-int " interrupt-controller" property then + device-end +; diff --git a/arch/ppc/briq/briq.h b/arch/ppc/briq/briq.h new file mode 100644 index 0000000..8858554 --- /dev/null +++ b/arch/ppc/briq/briq.h @@ -0,0 +1,24 @@ +/* + * Creation Date: <2004/08/28 17:50:12 stepan> + * Time-stamp: <2004/08/28 17:50:12 stepan> + * + * + * + * Copyright (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_BRIQ +#define _H_BRIQ + +/* vfd.c */ +extern int vfd_draw_str( const char *str ); +extern void vfd_close( void ); + +#include "kernel.h" + +#endif /* _H_BRIQ */ diff --git a/arch/ppc/briq/init.c b/arch/ppc/briq/init.c new file mode 100644 index 0000000..6c63114 --- /dev/null +++ b/arch/ppc/briq/init.c @@ -0,0 +1,129 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Initialization for briq + * + * Copyright (C) 2004 Greg Watson + * + * based on mol/init.c: + * + * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel & David Rydh + * (samuel@ibrium.se, dary@lindesign.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/nvram.h" +#include "briq/briq.h" +#include "ofmem.h" +#include "openbios-version.h" + +extern void unexpected_excep( int vector ); +extern void ob_ide_init( void ); +extern void setup_timers( void ); + +#if 0 +int +get_bool_res( const char *res ) +{ + char buf[8], *p; + + p = BootHGetStrRes( res, buf, sizeof(buf) ); + if( !p ) + return -1; + if( !strcasecmp(p,"true") || !strcasecmp(p,"yes") || !strcasecmp(p,"1") ) + return 1; + return 0; +} +#endif + +void +unexpected_excep( int vector ) +{ + printk("briQ panic: Unexpected exception %x\n", vector ); + for( ;; ) + ; +} + +void +entry( void ) +{ + printk("\n"); + printk("=============================================================\n"); + printk("OpenBIOS %s [%s]\n", OPENBIOS_RELEASE, OPENBIOS_BUILD_DATE ); + + ofmem_init(); + initialize_forth(); + /* won't return */ + + printk("of_startup returned!\n"); + for( ;; ) + ; +} + +static void +setenv( char *env, char *value ) +{ + push_str( value ); + push_str( env ); + fword("$setenv"); +} + +void +arch_of_init( void ) +{ +#if USE_RTAS + phandle_t ph; +#endif + int autoboot; + + devtree_init(); + node_methods_init(); + nvram_init(); + modules_init(); +#ifdef CONFIG_DRIVER_PCI + ob_pci_init(); +#endif +#ifdef CONFIG_DRIVER_IDE + setup_timers(); + ob_ide_init(); +#endif + +#if USE_RTAS + if( !(ph=find_dev("/rtas")) ) + printk("Warning: No /rtas node\n"); + else { + ulong size = 0x1000; + while( size < (ulong)of_rtas_end - (ulong)of_rtas_start ) + size *= 2; + set_property( ph, "rtas-size", (char*)&size, sizeof(size) ); + } +#endif + +#if 0 + /* tweak boot settings */ + autoboot = !!get_bool_res("autoboot"); +#endif + autoboot = 0; + if( !autoboot ) + printk("Autobooting disabled - dropping into OpenFirmware\n"); + setenv("auto-boot?", autoboot ? "true" : "false" ); + setenv("boot-command", "briqboot"); + +#if 0 + if( get_bool_res("tty-interface") == 1 ) +#endif + fword("activate-tty-interface"); + + /* hack */ + device_end(); + bind_func("briqboot", boot ); +} diff --git a/arch/ppc/briq/kernel.c b/arch/ppc/briq/kernel.c new file mode 100644 index 0000000..c03c07b --- /dev/null +++ b/arch/ppc/briq/kernel.c @@ -0,0 +1,17 @@ +/* + * Creation Date: <2004/08/28 18:03:25 stepan> + * Time-stamp: <2004/08/28 18:03:25 stepan> + * + * + * + * Copyright (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "briq-dict.h" +#include "../kernel.c" + diff --git a/arch/ppc/briq/main.c b/arch/ppc/briq/main.c new file mode 100644 index 0000000..73200a3 --- /dev/null +++ b/arch/ppc/briq/main.c @@ -0,0 +1,145 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Copyright (C) 2004 Greg Watson + * + * Based on MOL specific code which is + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/elfload.h" +#include "openbios/nvram.h" +#include "libc/diskio.h" +#include "libc/vsprintf.h" +#include "briq/briq.h" +#include "ofmem.h" + +static void +transfer_control_to_elf( ulong entry ) +{ + extern void call_elf( ulong entry ); + printk("Starting ELF image at 0x%08lX\n", entry); + call_elf( 0x400000 ); + //call_elf( entry ); + + fatal_error("call_elf returned unexpectedly\n"); +} + +static int +load_elf_rom( ulong *entry, int fd ) +{ + int i, lszz_offs, elf_offs; + char buf[128], *addr; + Elf_ehdr ehdr; + Elf_phdr *phdr; + size_t s; + + printk("Loading '%s'\n", get_file_path(fd)); + + /* the ELF-image (usually) starts at offset 0x4000 */ + if( (elf_offs=find_elf(fd)) < 0 ) { + printk("----> %s is not an ELF image\n", buf ); + exit(1); + } + if( !(phdr=elf_readhdrs(fd, elf_offs, &ehdr)) ) + fatal_error("elf_readhdrs failed\n"); + + *entry = ehdr.e_entry; + + /* load segments. Compressed ROM-image assumed to be located immediately + * after the last segment */ + lszz_offs = elf_offs; + for( i=0; i= phdr[i].p_vaddr && *entry < phdr[i].p_vaddr + s ) { + patch_newworld_rom( (char*)phdr[i].p_vaddr, s ); + newworld_timer_hack( (char*)phdr[i].p_vaddr, s ); + } +#endif + flush_icache_range( addr, addr+s ); + + /*printk("ELF ROM-section loaded at %08lX (size %08lX)\n", + (ulong)phdr[i].p_vaddr, (ulong)phdr[i].p_memsz );*/ + } + free( phdr ); + return lszz_offs; +} + + +static void +encode_bootpath( const char *spec, const char *args ) +{ + phandle_t chosen_ph = find_dev("/chosen"); + set_property( chosen_ph, "bootpath", spec, strlen(spec)+1 ); + set_property( chosen_ph, "bootargs", args, strlen(args)+1 ); +} + +/************************************************************************/ +/* briq booting */ +/************************************************************************/ + +static void +briq_startup( void ) +{ + const char *paths[] = { "hd:0,\\zImage.chrp", NULL }; + const char *args[] = { "root=/dev/hda2 console=ttyS0,115200", NULL }; + ulong entry; + int i, fd; + + for( i=0; paths[i]; i++ ) { + if( (fd=open_io(paths[i])) == -1 ) + continue; + (void) load_elf_rom( &entry, fd ); + close_io( fd ); + encode_bootpath( paths[i], args[i] ); + + update_nvram(); + transfer_control_to_elf( entry ); + /* won't come here */ + } + printk("*** Boot failure! No secondary bootloader specified ***\n"); +} + + +/************************************************************************/ +/* entry */ +/************************************************************************/ + +void +boot( void ) +{ + fword("update-chosen"); + briq_startup(); +} diff --git a/arch/ppc/briq/methods.c b/arch/ppc/briq/methods.c new file mode 100644 index 0000000..5a84971 --- /dev/null +++ b/arch/ppc/briq/methods.c @@ -0,0 +1,333 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Misc device node methods + * + * Copyright (C) 2004 Greg Watson + * + * Based on MOL specific code which is + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/string.h" +#include "briq/briq.h" +#include "ofmem.h" + +/************************************************************************/ +/* RTAS (run-time abstraction services) */ +/************************************************************************/ + +#ifdef USE_RTAS +DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" ); + +/* ( physbase -- rtas_callback ) */ +static void +rtas_instantiate( void ) +{ + int physbase = POP(); + int s=0x1000, size = (int)of_rtas_end - (int)of_rtas_start; + ulong virt; + + while( s < size ) + s += 0x1000; + virt = ofmem_claim_virt( 0, s, 0x1000 ); + ofmem_map( physbase, virt, s, -1 ); + memcpy( (char*)virt, of_rtas_start, size ); + + printk("RTAS instantiated at %08x\n", physbase ); + flush_icache_range( (char*)virt, (char*)virt + size ); + + PUSH( physbase ); +} + +NODE_METHODS( rtas ) = { + { "instantiate", rtas_instantiate }, + { "instantiate-rtas", rtas_instantiate }, +}; +#endif + + +/************************************************************************/ +/* stdout */ +/************************************************************************/ + +DECLARE_NODE( vfd_stdout, INSTALL_OPEN, 0, "Tdisplay" ); + +/* ( addr len -- actual ) */ +static void +stdout_write( void ) +{ + int len = POP(); + char *addr = (char*)POP(); + char *s = malloc( len + 1 ); + + strncpy_nopad( s, addr, len ); + s[len]=0; + + printk( "%s", s ); + //vfd_draw_str( s ); + free( s ); + + PUSH( len ); +} + +NODE_METHODS( vfd_stdout ) = { + { "write", stdout_write }, +}; + + +/************************************************************************/ +/* tty */ +/************************************************************************/ + +DECLARE_NODE( tty, INSTALL_OPEN, 0, "/packages/terminal-emulator" ); + +/* ( addr len -- actual ) */ +static void +tty_read( void ) +{ + int ch, len = POP(); + char *p = (char*)POP(); + int ret=0; + + if( len > 0 ) { + ret = 1; + ch = getchar(); + if( ch >= 0 ) { + *p = ch; + } else { + ret = 0; + } + } + PUSH( ret ); +} + +/* ( addr len -- actual ) */ +static void +tty_write( void ) +{ + int i, len = POP(); + char *p = (char*)POP(); + for( i=0; i + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * device tree setup + * + * Copyright (C) 2004 Greg Watson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" + +void devtree_init( void ) +{ + fword("init-briq-tree"); +} diff --git a/arch/ppc/briq/tree.fs b/arch/ppc/briq/tree.fs new file mode 100644 index 0000000..7c5499b --- /dev/null +++ b/arch/ppc/briq/tree.fs @@ -0,0 +1,247 @@ +\ briq specific initialization code +\ +\ Copyright (C) 2004 Greg Watson +\ +\ This program is free software; you can redistribute it and/or +\ modify it under the terms of the GNU General Public License +\ as published by the Free Software Foundation +\ + +\ ------------------------------------------------------------- +\ device-tree +\ ------------------------------------------------------------- + +" /" find-device + +" chrp" device-type +" TotalImpact,BRIQ-1" model +h# 80000000 encode-int " isa-io-base" property +1 encode-int " #interrupt-cells" property +1 encode-int " #size-cells" property + +new-device + " memory" device-name + " memory" device-type + 0 encode-int h# 1E00000 encode-int encode+ + h# 2000000 encode-int encode+ h# 40000000 encode-int encode+ + " available" property + 0 h# 40000000 reg + external + : open true ; + : close ; +finish-device + +new-device + " cpu" device-name + " cpu" device-type + " " encode-string " translations" property + 0 encode-phys h# 8000000 encode-int encode+ " available" property + d# 32 encode-int " d-cache-block-size" property + 8 encode-int " d-cache-sets" property + d# 32768 encode-int " d-cache-size" property + d# 32 encode-int " i-cache-block-size" property + 8 encode-int " i-cache-sets" property + d# 32768 encode-int " i-cache-size" property + " " encode-string " cache-unified" property + 2 encode-int " i-tlb-sets" property + d# 128 encode-int " i-tlb-size" property + 2 encode-int " d-tlb-sets" property + d# 128 encode-int " d-tlb-size" property + " " encode-string " tlb-split" property + 2 encode-int " tlb-sets" property + d# 256 encode-int " tlb-size" property + " " encode-string " performance-monitor" property + " " encode-string " graphics" property + 4 encode-int " reservation-granule-size" property + d# 25000000 encode-int " timebase-frequency" property + d# 300000000 encode-int " clock-frequency" property + d# 66000000 encode-int " bus-frequency" property + h# 88201 encode-int " cpu-version" property + 0 encode-int " reg" property +finish-device + +" /pci" find-device + h# 01000000 encode-int 0 encode-int encode+ 0 encode-int encode+ + h# 80000000 encode-int encode+ 0 encode-int encode+ + h# 01000000 encode-int encode+ + h# 02000000 encode-int encode+ 0 encode-int encode+ 0 encode-int encode+ + h# C0000000 encode-int encode+ 0 encode-int encode+ + h# 08000000 encode-int encode+ + " ranges" property + " IBM,CPC710" model + h# FF5F7700 encode-int " 8259-interrupt-acknowledge" property + h# 0000F800 encode-int 0 encode-int encode+ 0 encode-int encode+ + 7 encode-int encode+ + " interrupt-map-mask" property + 1 encode-int " #interrupt-cells" property + h# 80000000 encode-int " system-dma-base" property + d# 33333333 encode-int " clock-frequency" property + " " encode-string " primary-bridge" property + 0 encode-int " pci-bridge-number" property + h# FF500000 encode-int h# 100000 encode-int encode+ " reg" property + 0 encode-int 0 encode-int encode+ " bus-range" property + +new-device + " ide" device-name + " ide" device-type + " WINBOND,82C553" model + h# 28 encode-int " max-latency" property + h# 2 encode-int " min-grant" property + h# 1 encode-int " devsel-speed" property + h# 0 encode-int " subsystem-vendor-id" property + h# 0 encode-int " subsystem-id" property + h# 1018A encode-int " class-code" property + h# 5 encode-int " revision-id" property + h# 105 encode-int " device-id" property + h# 10AD encode-int " vendor-id" property + h# 1003110 encode-int 0 encode-int encode+ h# 10020 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003114 encode-int 0 encode-int encode+ h# 10030 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003118 encode-int 0 encode-int encode+ h# 10040 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 100311C encode-int 0 encode-int encode+ h# 10034 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003120 encode-int 0 encode-int encode+ h# 10050 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003124 encode-int 0 encode-int encode+ h# 10060 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + " assigned-addresses" property + h# 3100 encode-int 0 encode-int encode+ 0 encode-int encode+ + 0 encode-int encode+ 0 encode-int encode+ + h# 1003110 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003114 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003118 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 100311C encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003120 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003124 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + " reg" property +finish-device + +new-device + " ethernet" device-name + " network" device-type + " AMD,79C973" model + h# 3800 encode-int 0 encode-int encode+ 0 encode-int encode+ + 0 encode-int encode+ 0 encode-int encode+ + " reg" property +finish-device + +" /pci/isa" find-device + 0 0 " assigned-addresses" property + 0 0 " ranges" property + 0 encode-int " slot-names" property + d# 8333333 encode-int " clock-frequency" property + 0 encode-int " eisa-slots" property + 2 encode-int " #interrupt-cells" property + " W83C553F" encode-string " compatible" property + " WINBOND,82C553" model + 0 encode-int " max-latency" property + 0 encode-int " min-grant" property + 1 encode-int " devsel-speed" property + 0 encode-int " subsystem-vendor-id" property + 0 encode-int " subsystem-id" property + h# 60100 encode-int " class-code" property + h# 10 encode-int " revision-id" property + h# 565 encode-int " device-id" property + h# 10AD encode-int " vendor-id" property + h# 3000 encode-int 0 encode-int encode+ 0 encode-int encode+ + 0 encode-int encode+ 0 encode-int encode+ " reg" property + +new-device + " rtc" device-name + " rtc" device-type + " DS17285S" model + " MC146818" encode-string + " DS17285S" encode-string encode+ + " pnpPNP,b00" encode-string encode+ " compatible" property + 8 encode-int 0 encode-int encode+ " interrupts" property + h# 70 encode-int 1 encode-int encode+ + 2 encode-int encode+ " reg" property +finish-device + +new-device + " interrupt-controller" device-name + " interrupt-controller" device-type + " 8259" model + " " encode-string " interrupt-controller" property + 2 encode-int " #interrupt-cells" property + 1 encode-int + 2 encode-int encode+ + 3 encode-int encode+ + 6 encode-int encode+ + " reserved-interrupts" property + " 8259" encode-string + " chrp,iic" encode-string encode+ + " compatible" property + h# 20 encode-int 1 encode-int encode+ + 2 encode-int encode+ " reg" property +finish-device + +new-device + " serial" device-name + " serial" device-type + " no" encode-string " ctsrts" property + " no" encode-string " xon" property + " no" encode-string " parity" property + d# 115200 encode-int " bps" property + 1 encode-int " stop-bits" property + 8 encode-int " data-bits" property + h# 70800 encode-int " divisor" property + h# 708000 encode-int " clock-frequency" property + 4 encode-int 0 encode-int encode+ " interrupts" property + h# 3F8 encode-int 1 encode-int encode+ + 8 encode-int encode+ " reg" property +finish-device + +" /pci" find-device + " /pci/isa/interrupt-controller" find-dev if + encode-int " interrupt-parent" property + then + h# 3800 encode-int 0 encode-int encode+ + 0 encode-int encode+ 1 encode-int encode+ + " /pci/isa/interrupt-controller" find-dev if + encode-int encode+ + then + h# 0C encode-int encode+ 1 encode-int encode+ + " interrupt-map" property + +" /pci/isa" find-device + " /pci/isa/interrupt-controller" find-dev if + encode-int " interrupt-parent" property + then + +\ ------------------------------------------------------------- +\ /packages +\ ------------------------------------------------------------- + +" /packages" find-device + + " packages" device-name + external + \ allow packages to be opened with open-dev + : open true ; + : close ; + +\ /packages/terminal-emulator +new-device + " terminal-emulator" device-name + external + : open true ; + : close ; + \ : write ( addr len -- actual ) + \ dup -rot type + \ ; +finish-device + +\ ------------------------------------------------------------- +\ The END +\ ------------------------------------------------------------- +device-end + diff --git a/arch/ppc/briq/vfd.c b/arch/ppc/briq/vfd.c new file mode 100644 index 0000000..9fa7faa --- /dev/null +++ b/arch/ppc/briq/vfd.c @@ -0,0 +1,42 @@ +/* + * Creation Date: <2004/08/28 17:29:43 greg> + * Time-stamp: <2004/08/28 17:29:43 greg> + * + * + * + * Simple text console + * + * Copyright (C) 2004 Greg Watson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "briq/briq.h" + +static int vfd_is_open; + +static int +vfd_init( void ) +{ + vfd_is_open = 1; + return 0; +} + +void +vfd_close( void ) +{ +} + +int +vfd_draw_str( const char *str ) +{ + if (!vfd_is_open) + vfd_init(); + + return 0; +} diff --git a/arch/ppc/build.xml b/arch/ppc/build.xml new file mode 100644 index 0000000..bf54bfb --- /dev/null +++ b/arch/ppc/build.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@ + ]]> + + + + + + + + + + + $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@ + ]]> + + + + + + + + + + + $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@ + ]]> + + + + + + + + + + + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + + + + + + + + + + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + + + + + + + + + + + + + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + + + + + + + + + + + + + + + + $(LD) -g -Ttext=0x01e01000 -Bstatic $^ $(shell $(CC) -print-libgcc-file-name) -o $@ + $(NM) $@ | sort > $(ODIR)/openbios-briq.syms + cp $@ $@.nostrip + $(STRIP) $@ + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + + + + + + + + + + + $(LD) -g -Ttext=0x01e01000 -Bstatic $^ $(shell $(CC) -print-libgcc-file-name) -o $@ + $(NM) $@ | sort > $(ODIR)/openbios-pearpc.syms + cp $@ $@.nostrip + $(STRIP) $@ + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + + + + + + + + + + + + $(LD) -g -Ttext=0x01e01000 -Bstatic $^ $(shell $(CC) -print-libgcc-file-name) -o $@ + $(NM) $@ | sort > $(ODIR)/openbios-mol.syms + cp $@ $@.nostrip + $(STRIP) $@ + + + + $@.s + $(AS) $@.s $(AS_FLAGS) -o $@ + ]]> + + + + + + + + + + + diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig new file mode 100644 index 0000000..adfb181 --- /dev/null +++ b/arch/ppc/defconfig @@ -0,0 +1,48 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_PPC=y +CONFIG_MOL=y +# CONFIG_MPC107 is not set +# CONFIG_NO_ARCH is not set + +# +# Build hosted UNIX Binary +# +CONFIG_HOST_UNIX=y +# CONFIG_PLUGIN_PCI is not set + +# +# Kernel Debugging +# +CONFIG_DEBUG=y +CONFIG_DEBUG_BOOT=y +# CONFIG_DEBUG_DSTACK is not set +# CONFIG_DEBUG_RSTACK is not set +# CONFIG_DEBUG_DICTIONARY is not set +# CONFIG_DEBUG_INTERNAL is not set +# CONFIG_DEBUG_INTERPRETER is not set +CONFIG_DEBUG_CONSOLE=y +CONFIG_DEBUG_CONSOLE_SERIAL=y +CONFIG_SERIAL_PORT=1 +CONFIG_SERIAL_SPEED=115200 +CONFIG_DEBUG_CONSOLE_VGA=y + +# +# Packages +# +# CONFIG_PKG_DEBLOCKER is not set +# CONFIG_PKG_DISKLABEL is not set +# CONFIG_PKG_OBP_TFTP is not set +# CONFIG_PKG_TERMINAL_EMULATOR is not set + +# +# Module Configuration +# +CONFIG_DEBLOCKER=y +CONFIG_DISK_LABEL=y +CONFIG_PART_SUPPORT=y +CONFIG_MAC_PARTS=y +CONFIG_FS=y +CONFIG_HFS=y +CONFIG_HFSP=y diff --git a/arch/ppc/kernel.c b/arch/ppc/kernel.c new file mode 100644 index 0000000..31c003d --- /dev/null +++ b/arch/ppc/kernel.c @@ -0,0 +1,106 @@ +/* + * Creation Date: <2003/10/25 14:07:17 samuel> + * Time-stamp: <2004/08/28 17:48:19 stepan> + * + * + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2003, 2004 Stefan Reinauer + * + * Based upon unix.c (from OpenBIOS): + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "dict.h" +#include "openbios/bindings.h" +#include "openbios/stack.h" +#include "openbios/kernel.h" +#include "libc/string.h" +#include "kernel.h" + +#define MEMORY_SIZE (256*1024) /* 256K ram for hosted system */ +#define DICTIONARY_SIZE (512*1024) /* 128K for the dictionary */ + +extern unsigned char *dict; +extern cell dicthead; +static ucell *memory; + +/************************************************************************/ +/* F U N C T I O N S */ +/************************************************************************/ + +void +exception( int errcode ) +{ + /* no-op */ +} + +int +forth_segv_handler( char *segv_addr ) +{ + ucell addr = 0xdeadbeef; + + if( PC >= (ucell) dict && PC <= (ucell) dict + dicthead ) + addr = *(ucell *) PC; + + printk("panic: segmentation violation at %x\n", (int)segv_addr); + printk("dict=0x%x here=0x%x(dict+0x%x) pc=0x%x(dict+0x%x)\n", + (int)dict, (int)(dict + dicthead), dicthead, + PC, PC - (ucell) dict); + printk("dstackcnt=%d rstackcnt=%d instruction=%x\n", + dstackcnt, rstackcnt, addr); + +#ifdef DEBUG_DSTACK + printdstack(); +#endif +#ifdef DEBUG_RSTACK + printrstack(); +#endif + return -1; +} + +/* + * allocate memory and prepare engine for memory management. + */ + +static void +init_memory( void ) +{ + memory = malloc(MEMORY_SIZE); + if( !memory ) + panic("panic: not enough memory on host system.\n"); + + /* we push start and end of memory to the stack + * so that it can be used by the forth word QUIT + * to initialize the memory allocator + */ + + PUSH( (ucell)memory ); + PUSH( (ucell)memory + MEMORY_SIZE ); +} + +int +initialize_forth( void ) +{ + dict = malloc(DICTIONARY_SIZE); + load_dictionary( forth_dictionary, sizeof(forth_dictionary) ); + + PUSH_xt( bind_noname_func(arch_of_init) ); + fword("PREPOST-initializer"); + + PC = (ucell)findword("initialize-of"); + if( PC ) { + init_memory(); + enterforth((xt_t)PC); + free( memory ); + } + free( dict ); + return 0; +} diff --git a/arch/ppc/kernel.h b/arch/ppc/kernel.h new file mode 100644 index 0000000..be12141 --- /dev/null +++ b/arch/ppc/kernel.h @@ -0,0 +1,41 @@ +/* + * Creation Date: <2004/08/28 17:50:12 stepan> + * Time-stamp: <2004/08/28 17:50:12 stepan> + * + * + * + * Copyright (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef __KERNEL_H__ +#define __KERNEL_H__ + +/* misc.c */ +extern void fatal_error( const char *str ); +extern void exit( int status ); + +/* start.S */ +extern void flush_icache_range( char *start, char *stop ); +extern char of_rtas_start[], of_rtas_end[]; + +/* methods.c */ +extern void node_methods_init( void ); + +/* main.c */ +extern void boot( void ); + +/* init.c */ +extern void entry( void ); +extern void arch_of_init( void ); +extern int get_bool_res( const char *str ); + +/* tree.c */ +extern void devtree_init( void ); + + +#endif /* __KERNEL_H__ */ diff --git a/arch/ppc/misc.S b/arch/ppc/misc.S new file mode 100644 index 0000000..4d632f3 --- /dev/null +++ b/arch/ppc/misc.S @@ -0,0 +1,76 @@ +/* + * Creation Date: <2002/10/20 15:54:50 samuel> + * Time-stamp: <2002/10/20 15:57:21 samuel> + * + * + * + * Low-level stuff + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * Based upon misc.S from the the linux kernel with the following + * copyrights: + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org), + * Cort Dougan (cort@cs.nmt.edu), Paul Mackerras + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +changequote([[[[[,]]]]]) [[[[[ /* shield includes from m4-expansion */ +#include "asm/asmdefs.h" +#include "asm/processor.h" + + +/* + * Extended precision shifts. + * + * Updated to be valid for shift counts from 0 to 63 inclusive. + * -- Gabriel + * + * R3/R4 has 64 bit value + * R5 has shift count + * result in R3/R4 + * + * ashrdi3: arithmetic right shift (sign propagation) + * lshrdi3: logical right shift + * ashldi3: left shift + */ +GLOBL(__ashrdi3): + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 + sraw r7,r3,r7 # t2 = MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 + sraw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 + blr + +GLOBL(__ashldi3): + subfic r6,r5,32 + slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count + addi r7,r5,32 # could be xori, or addi with -32 + srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) + slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) + or r3,r3,r6 # MSW |= t1 + slw r4,r4,r5 # LSW = LSW << count + or r3,r3,r7 # MSW |= t2 + blr + +GLOBL(__lshrdi3): + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + srw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 + blr + diff --git a/arch/ppc/mmutypes.h b/arch/ppc/mmutypes.h new file mode 100644 index 0000000..810f727 --- /dev/null +++ b/arch/ppc/mmutypes.h @@ -0,0 +1,76 @@ +/* + * Creation Date: <2002/01/13 13:53:14 samuel> + * Time-stamp: <2002/01/27 19:56:11 samuel> + * + * + * + * MMU definitions + * + * Most of these declarations originate from the Linux Kernel + * + * Copyright (C) 2002 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_MMUTYPES +#define _H_MMUTYPES + +/* Hardware Page Table Entry */ +typedef struct mPTE { + unsigned long v:1; /* Entry is valid */ + unsigned long vsid:24; /* Virtual segment identifier */ + unsigned long h:1; /* Hash algorithm indicator */ + unsigned long api:6; /* Abbreviated page index */ + + unsigned long rpn:20; /* Real (physical) page number */ + unsigned long :3; /* Unused */ + unsigned long r:1; /* Referenced */ + unsigned long c:1; /* Changed */ + unsigned long w:1; /* Write-thru cache mode */ + unsigned long i:1; /* Cache inhibited */ + unsigned long m:1; /* Memory coherence */ + unsigned long g:1; /* Guarded */ + unsigned long :1; /* Unused */ + unsigned long pp:2; /* Page protection */ +} mPTE_t; + + +typedef struct _mBATU { /* Upper part of BAT (all except 601) */ + unsigned long bepi:15; /* Effective page index (virtual address) */ + unsigned long :4; /* Unused */ + unsigned long bl:11; /* Block size mask */ + unsigned long vs:1; /* Supervisor valid */ + unsigned long vp:1; /* User valid */ +} mBATU; + +typedef struct _mBATL { /* Lower part of BAT (all except 601) */ + unsigned long brpn:15; /* Real page index (physical address) */ + unsigned long :10; /* Unused */ + unsigned long w:1; /* Write-thru cache */ + unsigned long i:1; /* Cache inhibit */ + unsigned long m:1; /* Memory coherence */ + unsigned long g:1; /* Guarded (MBZ in IBAT) */ + unsigned long :1; /* Unused */ + unsigned long pp:2; /* Page access protections */ +} mBATL; + +typedef struct _mBAT { + mBATU batu; /* Upper register */ + mBATL batl; /* Lower register */ +} mBAT; + +typedef struct _mSEGREG { + unsigned long t:1; /* Normal or I/O type */ + unsigned long ks:1; /* Supervisor 'key' (normally 0) */ + unsigned long kp:1; /* User 'key' (normally 1) */ + unsigned long n:1; /* No-execute */ + unsigned long :4; /* Unused */ + unsigned long vsid:24; /* Virtual Segment Identifier */ +} mSEGREG; + + +#endif /* _H_MMUTYPES */ diff --git a/arch/ppc/mol/console.c b/arch/ppc/mol/console.c new file mode 100644 index 0000000..7f5aa28 --- /dev/null +++ b/arch/ppc/mol/console.c @@ -0,0 +1,32 @@ +/* + * Creation Date: <2002/10/29 18:59:05 samuel> + * Time-stamp: <2003/12/28 22:51:11 samuel> + * + * + * + * Simple text console + * + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2005 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/diskio.h" +#include "osi_calls.h" +#include "ofmem.h" +#include "mol/mol.h" +#include "boothelper_sh.h" +#include "video_sh.h" + +#define openbios_GetFBInfo(x) OSI_GetFBInfo(x) + +#include "../../../modules/video.c" +#include "../../../modules/console.c" + + diff --git a/arch/ppc/mol/init.c b/arch/ppc/mol/init.c new file mode 100644 index 0000000..ee8534c --- /dev/null +++ b/arch/ppc/mol/init.c @@ -0,0 +1,112 @@ +/* + * Creation Date: <1999/11/16 00:49:26 samuel> + * Time-stamp: <2004/04/12 16:26:50 samuel> + * + * + * + * Initialization + * + * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel & David Rydh + # (samuel@ibrium.se, dary@lindesign.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/nvram.h" +#include "mol/mol.h" +#include "ofmem.h" +#include "mol/prom.h" +#include "openbios-version.h" +#include "osi_calls.h" +#include "boothelper_sh.h" + +extern void unexpected_excep( int vector ); + +int +get_bool_res( const char *res ) +{ + char buf[8], *p; + + p = BootHGetStrRes( res, buf, sizeof(buf) ); + if( !p ) + return -1; + if( !strcasecmp(p,"true") || !strcasecmp(p,"yes") || !strcasecmp(p,"1") ) + return 1; + return 0; +} + +void +unexpected_excep( int vector ) +{ + printk("MOL panic: Unexpected exception %x\n", vector ); + for( ;; ) + ; +} + +void +entry( void ) +{ + printk("\n"); + printk("=============================================================\n"); + printk("OpenBIOS %s [%s]\n", OPENBIOS_RELEASE, OPENBIOS_BUILD_DATE ); + + ofmem_init(); + initialize_forth(); + /* won't return */ + + printk("of_startup returned!\n"); + for( ;; ) + ; +} + +static void +setenv( char *env, char *value ) +{ + push_str( value ); + push_str( env ); + fword("$setenv"); +} + +void +arch_of_init( void ) +{ + mol_phandle_t ph; + int autoboot; + + devtree_init(); + node_methods_init(); + nvram_init(); + modules_init(); + pseudodisk_init(); + osiblk_init(); + osiscsi_init(); + init_video(); + + if( (ph=prom_find_device("/rtas")) == -1 ) + printk("Warning: No /rtas node\n"); + else { + ulong size = 0x1000; + while( size < (ulong)of_rtas_end - (ulong)of_rtas_start ) + size *= 2; + prom_set_prop( ph, "rtas-size", (char*)&size, sizeof(size) ); + } + + /* tweak boot settings */ + autoboot = !!get_bool_res("autoboot"); + if( !autoboot ) + printk("Autobooting disabled - dropping into OpenFirmware\n"); + setenv("auto-boot?", autoboot ? "true" : "false" ); + setenv("boot-command", "molboot"); + + if( get_bool_res("tty-interface") == 1 ) + fword("activate-tty-interface"); + + /* hack */ + device_end(); + bind_func("molboot", boot ); +} diff --git a/arch/ppc/mol/kernel.c b/arch/ppc/mol/kernel.c new file mode 100644 index 0000000..8a5b83c --- /dev/null +++ b/arch/ppc/mol/kernel.c @@ -0,0 +1,17 @@ +/* + * Creation Date: <2004/08/28 18:03:25 stepan> + * Time-stamp: <2004/08/28 18:03:25 stepan> + * + * + * + * Copyright (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "mol-dict.h" +#include "../kernel.c" + diff --git a/arch/ppc/mol/main.c b/arch/ppc/mol/main.c new file mode 100644 index 0000000..8b39ade --- /dev/null +++ b/arch/ppc/mol/main.c @@ -0,0 +1,369 @@ +/* + * Creation Date: <2002/10/02 22:24:24 samuel> + * Time-stamp: <2004/03/27 01:57:55 samuel> + * + * + * + * + * + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/elfload.h" +#include "openbios/nvram.h" +#include "libc/diskio.h" +#include "libc/vsprintf.h" +#include "mol/mol.h" +#include "ofmem.h" +#include "osi_calls.h" +#include "ablk_sh.h" +#include "boothelper_sh.h" + + +static void patch_newworld_rom( char *start, size_t size ); +static void newworld_timer_hack( char *start, size_t size ); + +static void +transfer_control_to_elf( ulong entry ) +{ + extern void call_elf( ulong entry ); + printk("Starting ELF boot loader\n"); + call_elf( entry ); + + fatal_error("call_elf returned unexpectedly\n"); +} + +static int +load_elf_rom( ulong *entry, int fd ) +{ + int i, lszz_offs, elf_offs; + char buf[128], *addr; + Elf_ehdr ehdr; + Elf_phdr *phdr; + size_t s; + + printk("Loading '%s' from '%s'\n", get_file_path(fd), + get_volume_name(fd) ); + + /* the ELF-image (usually) starts at offset 0x4000 */ + if( (elf_offs=find_elf(fd)) < 0 ) { + printk("----> %s is not an ELF image\n", buf ); + exit(1); + } + if( !(phdr=elf_readhdrs(fd, elf_offs, &ehdr)) ) + fatal_error("elf_readhdrs failed\n"); + + *entry = ehdr.e_entry; + + /* load segments. Compressed ROM-image assumed to be located immediately + * after the last segment */ + lszz_offs = elf_offs; + for( i=0; i= phdr[i].p_vaddr && *entry < phdr[i].p_vaddr + s ) { + patch_newworld_rom( (char*)phdr[i].p_vaddr, s ); + newworld_timer_hack( (char*)phdr[i].p_vaddr, s ); + } + flush_icache_range( addr, addr+s ); + + /* printk("ELF ROM-section loaded at %08lX (size %08lX)\n", + (ulong)phdr[i].p_vaddr, (ulong)phdr[i].p_memsz );*/ + } + free( phdr ); + return lszz_offs; +} + + +/************************************************************************/ +/* newworld ROM loading */ +/************************************************************************/ + +#define ROM_BASE 0x1100000 /* where we decide to put things */ + +/* fix bug present in the 2.4 and the 3.0 Apple ROM */ +static void +patch_newworld_rom( char *start, size_t size ) +{ + int s; + ulong mark[] = { 0x7c7d1b78, /* mr r29,r3 */ + 0x7c9c2378, /* mr r28,r4 */ + 0x7cc33378, /* mr r3,r6 */ + 0x7c864214, /* add r4,r6,r8 <------ BUG -- */ + 0x80b10000, /* lwz r5,0(r17) */ + 0x38a500e8 }; /* addi r5,r5,232 */ + + /* Correcting add r4,r6,r8 ----> addi r4,r6,8 */ + for( s=0; s= 0 ) { + entry = (char*)load_newworld_rom( fd ); + close_io( fd ); + } + + /* determine boot volume */ + for( bootunit=-1, type=0; bootunit==-1 && type<3 ; type++ ) { + for( i=0; !OSI_ABlkDiskInfo(0, i, &info) ; i++ ) { + if( type<=1 && !(info.flags & ABLK_BOOT_HINT) ) + continue; + if( type>1 && (info.flags & ABLK_BOOT_HINT) ) + continue; + + for( j=0; !entry && j<32; j++ ) { + sprintf( spec, "%s/disk@%x:%d", path, i, j ); + entry = newworld_load( path, spec, (!type || type==2) ); + } + if( entry ) { + bootunit = i; + break; + } + } + } + + if( entry ) { + OSI_ABlkBlessDisk( 0 /*channel*/, bootunit ); + + update_nvram(); + transfer_control_to_elf( (ulong)entry ); + /* won't come here */ + return; + } + + printk("\n--- No bootable disk was found! -----------------------------\n"); + printk("If this is an oldworld machine, try booting from the MacOS\n"); + printk("install CD and install MacOS from within MOL.\n"); + printk("-------------------------------------------------------------\n"); + exit(1); +} + + +/************************************************************************/ +/* yaboot booting */ +/************************************************************************/ + +static void +yaboot_startup( void ) +{ + const char *paths[] = { "pseudo:,ofclient", "pseudo:,yaboot", NULL }; + ulong entry; + int i, fd; + + for( i=0; paths[i]; i++ ) { + if( (fd=open_io(paths[i])) == -1 ) + continue; + (void) load_elf_rom( &entry, fd ); + close_io( fd ); + encode_bootpath( paths[i], "" ); + + update_nvram(); + transfer_control_to_elf( entry ); + /* won't come here */ + } + printk("*** Boot failure! No secondary bootloader specified ***\n"); + exit(1); +} + + +/************************************************************************/ +/* entry */ +/************************************************************************/ + +void +boot( void ) +{ + fword("update-chosen"); + if( find_dev("/mol-platform") ) + yaboot_startup(); + else + newworld_startup(); +} diff --git a/arch/ppc/mol/methods.c b/arch/ppc/mol/methods.c new file mode 100644 index 0000000..a76e3f3 --- /dev/null +++ b/arch/ppc/mol/methods.c @@ -0,0 +1,475 @@ +/* + * Creation Date: <2003/10/18 13:24:29 samuel> + * Time-stamp: <2004/03/27 02:00:30 samuel> + * + * + * + * Misc device node methods + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/string.h" +#include "mol/mol.h" +#include "ofmem.h" +#include "mol/prom.h" +#include "osi_calls.h" +#include "kbd_sh.h" + +/************************************************************************/ +/* Power Management */ +/************************************************************************/ + +DECLARE_NODE( powermgt, INSTALL_OPEN, 0, "/pci/pci-bridge/mac-io/power-mgt" ); + +/* ( -- ) */ +static void +set_hybernot_flag( void ) +{ +} + +NODE_METHODS( powermgt ) = { + { "set-hybernot-flag", set_hybernot_flag }, +}; + + +/************************************************************************/ +/* RTAS (run-time abstraction services) */ +/************************************************************************/ + +DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" ); + +/* ( physbase -- rtas_callback ) */ +static void +rtas_instantiate( void ) +{ + int physbase = POP(); + int s=0x1000, size = (int)of_rtas_end - (int)of_rtas_start; + ulong virt; + + while( s < size ) + s += 0x1000; + virt = ofmem_claim_virt( 0, s, 0x1000 ); + ofmem_map( physbase, virt, s, -1 ); + memcpy( (char*)virt, of_rtas_start, size ); + + printk("RTAS instantiated at %08x\n", physbase ); + flush_icache_range( (char*)virt, (char*)virt + size ); + + PUSH( physbase ); +} + +NODE_METHODS( rtas ) = { + { "instantiate", rtas_instantiate }, + { "instantiate-rtas", rtas_instantiate }, +}; + + + +/************************************************************************/ +/* stdout */ +/************************************************************************/ + +DECLARE_NODE( video_stdout, INSTALL_OPEN, 0, "Tdisplay" ); + +/* ( addr len -- actual ) */ +static void +stdout_write( void ) +{ + int len = POP(); + char *addr = (char*)POP(); + char *s = malloc( len + 1 ); + + strncpy_nopad( s, addr, len ); + s[len]=0; + + /* printk( "%s", s ); */ + console_draw_str( s ); + free( s ); + + PUSH( len ); +} + +NODE_METHODS( video_stdout ) = { + { "write", stdout_write }, +}; + + +/************************************************************************/ +/* tty */ +/************************************************************************/ + +DECLARE_NODE( tty, INSTALL_OPEN, 0, "+/mol/mol-tty" ); + +/* ( addr len -- actual ) */ +static void +tty_read( void ) +{ + int ch, len = POP(); + char *p = (char*)POP(); + int ret=0; + + if( len > 0 ) { + ret = 1; + ch = OSI_TTYGetc(); + if( ch >= 0 ) { + *p = ch; + } else { + ret = 0; + OSI_USleep(1); + } + } + PUSH( ret ); +} + +/* ( addr len -- actual ) */ +static void +tty_write( void ) +{ + int i, len = POP(); + char *p = (char*)POP(); + for( i=0; i" + /* 0x30 */ "\t <\b \e " + /* 0x40 */ " . * + / - " + /* 0x50 */ " =01234567 89 " + /* 0x60 */ " " + /* 0x70 */ " "; + +DECLARE_NODE( kbd, INSTALL_OPEN, sizeof(kbd_state_t), + "/psuedo-hid/keyboard", + "/mol/mol-keyboard", + "/mol/keyboard" +); + +/* ( -- keymap ) (?) */ +/* should return a pointer to an array with 32 bytes (256 bits) */ +static void +kbd_get_key_map( kbd_state_t *ks ) +{ + /* printk("met_kbd_get_key_map\n"); */ + + /* keytable[5] = 0x40; */ + PUSH( (int)ks->keytable ); +} + +/* ( buf len --- actlen ) */ +static void +kbd_read( kbd_state_t *ks ) +{ + int ret=0, len = POP(); + char *p = (char*)POP(); + int key; + + if( !p || !len ) { + PUSH( -1 ); + return; + } + + if( ks->save_key ) { + *p = ks->save_key; + ks->save_key = 0; + RET( 1 ); + } + OSI_USleep(1); /* be nice */ + + for( ; (key=OSI_GetAdbKey()) >= 0 ; ) { + int code = (key & 0x7f); + int down = !(key & 0x80); + + if( code == 0x36 /* ctrl */ ) { + ks->cntrl = down; + continue; + } + if( code == 0x38 /* shift */ || code == 0x7b) { + ks->shift = down; + continue; + } + if( code == 0x37 /* command */ ) { + ks->meta = down; + continue; + } + if( code == 0x3a /* alt */ ) { + ks->alt = down; + continue; + } + if( !down ) + continue; + + ret = 1; + if( ks->shift ) + key = adb_shift_table[ key & 0x7f ]; + else + key = adb_ascii_table[ key & 0x7f ]; + + if( ks->meta ) { + ks->save_key = key; + key = 27; + } else if( ks->cntrl ) { + key = key - 'a' + 1; + } + *p = key; + if( !*p ) + *p = 'x'; + break; + } + PUSH( ret ); +} + +NODE_METHODS( kbd ) = { + { "read", kbd_read }, + { "get-key-map", kbd_get_key_map }, +}; + + +/************************************************************************/ +/* client interface 'quiesce' */ +/************************************************************************/ + +DECLARE_NODE( ciface, 0, 0, "/packages/client-iface" ); + +/* ( -- ) */ +static void +ciface_quiesce( ulong args[], ulong ret[] ) +{ +#if 0 + ulong msr; + /* This seems to be the correct thing to do - but I'm not sure */ + asm volatile("mfmsr %0" : "=r" (msr) : ); + msr &= ~(MSR_IR | MSR_DR); + asm volatile("mtmsr %0" :: "r" (msr) ); +#endif + printk("=============================================================\n\n"); + prom_close(); + + OSI_KbdCntrl( kKbdCntrlSuspend ); +} + +/* ( -- ms ) */ +static void +ciface_milliseconds( ulong args[], ulong ret[] ) +{ + static ulong mticks=0, usecs=0; + ulong t; + + asm volatile("mftb %0" : "=r" (t) : ); + if( mticks ) + usecs += OSI_MticksToUsecs( t-mticks ); + mticks = t; + + PUSH( usecs/1000 ); +} + + +NODE_METHODS( ciface ) = { + { "quiesce", ciface_quiesce }, + { "milliseconds", ciface_milliseconds }, +}; + + +/************************************************************************/ +/* MMU/memory methods */ +/************************************************************************/ + +DECLARE_NODE( memory, INSTALL_OPEN, 0, "/memory" ); +DECLARE_NODE( mmu, INSTALL_OPEN, 0, "/cpus/@0" ); +DECLARE_NODE( mmu_ciface, 0, 0, "/packages/client-iface" ); + + +/* ( phys size align --- base ) */ +static void +mem_claim( void ) +{ + int align = POP(); + int size = POP(); + int phys = POP(); + int ret = ofmem_claim_phys( phys, size, align ); + + if( ret == -1 ) { + printk("MEM: claim failure\n"); + throw( -13 ); + return; + } + PUSH( ret ); +} + +/* ( phys size --- ) */ +static void +mem_release( void ) +{ + POP(); POP(); +} + +/* ( phys size align --- base ) */ +static void +mmu_claim( void ) +{ + int align = POP(); + int size = POP(); + int phys = POP(); + int ret = ofmem_claim_virt( phys, size, align ); + + if( ret == -1 ) { + printk("MMU: CLAIM failure\n"); + throw( -13 ); + return; + } + PUSH( ret ); +} + +/* ( phys size --- ) */ +static void +mmu_release( void ) +{ + POP(); POP(); +} + +/* ( phys virt size mode -- [ret???] ) */ +static void +mmu_map( void ) +{ + int mode = POP(); + int size = POP(); + int virt = POP(); + int phys = POP(); + int ret; + + /* printk("mmu_map: %x %x %x %x\n", phys, virt, size, mode ); */ + ret = ofmem_map( phys, virt, size, mode ); + + if( ret ) { + printk("MMU: map failure\n"); + throw( -13 ); + return; + } +} + +/* ( virt size -- ) */ +static void +mmu_unmap( void ) +{ + POP(); POP(); +} + +/* ( virt -- false | phys mode true ) */ +static void +mmu_translate( void ) +{ + ulong mode; + int virt = POP(); + int phys = ofmem_translate( virt, &mode ); + + if( phys == -1 ) { + PUSH( 0 ); + } else { + PUSH( phys ); + PUSH( (int)mode ); + PUSH( -1 ); + } +} + +/* ( virt size align -- baseaddr|-1 ) */ +static void +ciface_claim( void ) +{ + int align = POP(); + int size = POP(); + int virt = POP(); + int ret = ofmem_claim( virt, size, align ); + + /* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */ + PUSH( ret ); +} + +/* ( virt size -- ) */ +static void +ciface_release( void ) +{ + POP(); + POP(); +} + + +NODE_METHODS( memory ) = { + { "claim", mem_claim }, + { "release", mem_release }, +}; + +NODE_METHODS( mmu ) = { + { "claim", mmu_claim }, + { "release", mmu_release }, + { "map", mmu_map }, + { "unmap", mmu_unmap }, + { "translate", mmu_translate }, +}; + +NODE_METHODS( mmu_ciface ) = { + { "claim", ciface_claim }, + { "release", ciface_release }, +}; + + +/************************************************************************/ +/* init */ +/************************************************************************/ + +void +node_methods_init( void ) +{ + REGISTER_NODE( rtas ); + REGISTER_NODE( powermgt ); + REGISTER_NODE( kbd ); + REGISTER_NODE( video_stdout ); + REGISTER_NODE( ciface ); + REGISTER_NODE( memory ); + REGISTER_NODE( mmu ); + REGISTER_NODE( mmu_ciface ); + + if( OSI_CallAvailable(OSI_TTY_GETC) ) + REGISTER_NODE( tty ); + + OSI_KbdCntrl( kKbdCntrlActivate ); +} diff --git a/arch/ppc/mol/mol.c b/arch/ppc/mol/mol.c new file mode 100644 index 0000000..cfc657c --- /dev/null +++ b/arch/ppc/mol/mol.c @@ -0,0 +1,166 @@ +/* + * Creation Date: <2003/12/19 18:46:21 samuel> + * Time-stamp: <2004/04/12 16:27:12 samuel> + * + * + * + * + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/nvram.h" +#include "libc/vsprintf.h" +#include "libc/string.h" +#include "mol/mol.h" +#include "osi_calls.h" +#include + +void +exit( int status ) +{ + OSI_Exit(); +} + +void +fatal_error( const char *err ) +{ + printk("Fatal error: %s\n", err ); + OSI_Exit(); +} + +void +panic( const char *err ) +{ + printk("Panic: %s\n", err ); + OSI_Exit(); + + /* won't come here... this keeps the gcc happy */ + for( ;; ) + ; +} + + +/************************************************************************/ +/* print using OSI interface */ +/************************************************************************/ + +static int do_indent; + +int +printk( const char *fmt, ... ) +{ + char *p, buf[1024]; /* XXX: no buffer overflow protection... */ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + + for( p=buf; *p; p++ ) { + if( *p == '\n' ) + do_indent = 0; + if( do_indent++ == 1 ) { + OSI_PutC( '>' ); + OSI_PutC( '>' ); + OSI_PutC( ' ' ); + } + OSI_PutC( *p ); + } + return i; +} + + +/************************************************************************/ +/* TTY iface */ +/************************************************************************/ + +static int ttychar = -1; + +static int +tty_avail( void ) +{ + return OSI_CallAvailable( OSI_TTY_GETC ); +} + +int +availchar( void ) +{ + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + ttychar = OSI_TTYGetc(); + if( ttychar < 0 ) + OSI_USleep(1); + return (ttychar >= 0); +} + +int +getchar( void ) +{ + int ch; + + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + return OSI_TTYGetc(); + ch = ttychar; + ttychar = -1; + return ch; +} + +int +putchar( int c ) +{ + printk("%c", c ); + + if( tty_avail() ) + OSI_TTYPutc( c ); + return c; +} + + +/************************************************************************/ +/* MOL specific stuff */ +/************************************************************************/ + +int +arch_nvram_size( void ) +{ + return OSI_NVRamSize(); +} + +void +arch_nvram_put( char *buf ) +{ + int i, size = arch_nvram_size(); + + for( i=0; i + * Time-stamp: <2004/03/27 01:52:50 samuel> + * + * + * + * + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_MOL +#define _H_MOL + +/* video.c */ +extern void init_video( void ); +extern int video_get_res( int *w, int *h ); +extern void draw_pixel( int x, int y, int colind ); +extern void set_color( int index, ulong color ); + +/* console.c */ +extern int console_draw_str( const char *str ); +extern void console_close( void ); + +/* pseudodisk.c */ +extern void pseudodisk_init( void ); + +/* osi-blk.c */ +extern void osiblk_init( void ); + +/* osi-scsi.c */ +extern void osiscsi_init( void ); + +/* pseudofs.c */ +extern void pseudofs_init( void ); + +#include "../kernel.h" + +#endif /* _H_MOL */ diff --git a/arch/ppc/mol/osi-blk.c b/arch/ppc/mol/osi-blk.c new file mode 100644 index 0000000..f6b684b --- /dev/null +++ b/arch/ppc/mol/osi-blk.c @@ -0,0 +1,119 @@ +/* + * Creation Date: <2003/12/07 19:08:33 samuel> + * Time-stamp: <2004/01/07 19:38:36 samuel> + * + * + * + * OSI-block interface + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "mol/mol.h" +#include "osi_calls.h" + +typedef struct { + int unit; + int channel; +} osiblk_data_t; + + +DECLARE_NODE( osiblk, INSTALL_OPEN, sizeof(osiblk_data_t), + "/pci/pci-bridge/mol-blk/disk", "/mol/mol-blk" ); + + +static void +osiblk_open( osiblk_data_t *pb ) +{ + phandle_t ph; + + fword("my-unit"); + pb->unit = POP(); + pb->channel = 0; /* FIXME */ + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + /* printk("osi-blk: open %d\n", pb->unit ); */ + PUSH( -1 ); +} + +static void +osiblk_close( osiblk_data_t *pb ) +{ + selfword("close-deblocker"); +} + + +/* ( buf blk nblks -- actual ) */ +static void +osiblk_read_blocks( osiblk_data_t *pb ) +{ + int i, n = POP(); + int blk = POP(); + char *dest = (char*)POP(); + + /* printk("osiblk_read_blocks %x block=%d n=%d\n", (int)dest, blk, n ); */ + + for( i=0; ichannel, pb->unit, blk+i, (int)buf, m*512) < 0 ) { + printk("SyncRead: error\n"); + RET(0); + } + memcpy( dest, buf, m * 512 ); + i += m; + dest += m * 512; + } + PUSH( n ); +} + +/* ( -- bs ) */ +static void +osiblk_block_size( osiblk_data_t *pb ) +{ + PUSH( 512 ); +} + +/* ( -- maxbytes ) */ +static void +osiblk_max_transfer( osiblk_data_t *pb ) +{ + PUSH( 1024*1024 ); +} + +static void +osiblk_initialize( osiblk_data_t *pb ) +{ + fword("is-deblocker"); +} + + +NODE_METHODS( osiblk ) = { + { NULL, osiblk_initialize }, + { "open", osiblk_open }, + { "close", osiblk_close }, + { "read-blocks", osiblk_read_blocks }, + { "block-size", osiblk_block_size }, + { "max-transfer", osiblk_max_transfer }, +}; + +void +osiblk_init( void ) +{ + REGISTER_NODE( osiblk ); +} diff --git a/arch/ppc/mol/osi-scsi.c b/arch/ppc/mol/osi-scsi.c new file mode 100644 index 0000000..b725462 --- /dev/null +++ b/arch/ppc/mol/osi-scsi.c @@ -0,0 +1,271 @@ +/* + * Creation Date: <2003/12/11 21:23:54 samuel> + * Time-stamp: <2004/01/07 19:38:45 samuel> + * + * + * + * SCSI device node + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "mol/mol.h" +#include "scsi_sh.h" +#include "osi_calls.h" + +#define MAX_TARGETS 32 + +typedef struct { + int probed; + int valid; /* a useable device found */ + + int is_cd; + int blocksize; +} target_info_t; + +static target_info_t scsi_devs[ MAX_TARGETS ]; + +typedef struct { + int target; + target_info_t *info; +} instance_data_t; + + +DECLARE_NODE( scsi, INSTALL_OPEN, sizeof(instance_data_t), + "/pci/pci-bridge/mol-scsi/sd", "/mol/mol-scsi/sd" ); + + +static int +scsi_cmd_( instance_data_t *sd, const char *cmd, int cmdlen, char *dest, + int len, int prelen, int postlen ) +{ + char prebuf[4096], postbuf[4096]; + scsi_req_t r[2]; /* the [2] is a hack to get space for the sg-list */ + char sb[32]; + + /* memset( dest, 0, len ); */ + + if( (uint)prelen > sizeof(prebuf) || (uint)postlen > sizeof(postbuf) ) { + printk("bad pre/post len %d %d\n", prelen, postlen ); + return 1; + } + + memset( r, 0, sizeof(r[0]) ); + r->lun = 0; + r->target = sd->target; + r->is_write = 0; + memcpy( r->cdb, cmd, cmdlen ); + r->client_addr = (int)&r; + r->cdb_len = cmdlen; + r->sense[0].base = (int)&sb; + r->sense[0].size = sizeof(sb); + r->size = prelen + len + postlen; + r->n_sg = 3; + r->sglist.n_el = 3; + r->sglist.vec[0].base = (int)prebuf; + r->sglist.vec[0].size = prelen; + r->sglist.vec[1].base = (int)dest; + r->sglist.vec[1].size = len; + r->sglist.vec[2].base = (int)postbuf; + r->sglist.vec[2].size = postlen; + + if( OSI_SCSISubmit((int)&r) ) { + printk("OSI_SCSISubmit: error!\n"); + return 1; + } + while( !OSI_SCSIAck() ) + OSI_USleep( 10 ); + + if( r->adapter_status ) + return -1; + if( r->scsi_status ) + return ((sb[2] & 0xf) << 16) | (sb[12] << 8) | sb[13]; + return 0; +} + +static int +scsi_cmd( instance_data_t *sd, const char *cmd, int cmdlen ) +{ + return scsi_cmd_( sd, cmd, cmdlen, NULL, 0, 0, 0 ); +} + +/* ( buf blk nblks -- actual ) */ +static void +scsi_read_blocks( instance_data_t *sd ) +{ + int nblks = POP(); + int blk = POP(); + char *dest = (char*)POP(); + unsigned char cmd[10]; + int len = nblks * sd->info->blocksize; + + memset( dest, 0, len ); + + /* printk("READ: blk: %d length %d\n", blk, len ); */ + memset( cmd, 0, sizeof(cmd) ); + cmd[0] = 0x28; /* READ_10 */ + cmd[2] = blk >> 24; + cmd[3] = blk >> 16; + cmd[4] = blk >> 8; + cmd[5] = blk; + cmd[7] = nblks >> 8; + cmd[8] = nblks; + + if( scsi_cmd_(sd, cmd, 10, dest, len, 0, 0) ) { + printk("read: scsi_cmd failed\n"); + RET( -1 ); + } + PUSH( nblks ); +} + +static int +inquiry( instance_data_t *sd ) +{ + char inquiry_cmd[6] = { 0x12, 0, 0, 0, 32, 0 }; + char start_stop_unit_cmd[6] = { 0x1b, 0, 0, 0, 1, 0 }; + char test_unit_ready_cmd[6] = { 0x00, 0, 0, 0, 0, 0 }; + char prev_allow_medium_removal[6] = { 0x1e, 0, 0, 0, 1, 0 }; + char set_cd_speed_cmd[12] = { 0xbb, 0, 0xff, 0xff, 0xff, 0xff, + 0, 0, 0, 0, 0, 0 }; + target_info_t *info = &scsi_devs[sd->target]; + char ret[32]; + int i, sense; + + if( sd->target >= MAX_TARGETS ) + return -1; + sd->info = info; + + if( info->probed ) + return info->valid ? 0:-1; + info->probed = 1; + + if( (sense=scsi_cmd_(sd, inquiry_cmd, 6, ret, 2, 0, 0)) ) { + if( sense < 0 ) + return -1; + printk("INQUIRY failed\n"); + return -1; + } + + /* medium present? */ + if( (scsi_cmd(sd, test_unit_ready_cmd, 6) >> 8) == 0x23a ) { + printk("no media\n"); + return -1; + } + + info->is_cd = 0; + info->blocksize = 512; + + if( ret[0] == 5 /* CD/DVD */ ) { + info->blocksize = 2048; + info->is_cd = 1; + + scsi_cmd( sd, prev_allow_medium_removal, 6 ); + scsi_cmd( sd, set_cd_speed_cmd, 12 ); + scsi_cmd( sd, start_stop_unit_cmd, 6 ); + + } else if( ret[0] == 0 /* DISK */ ) { + scsi_cmd( sd, test_unit_ready_cmd, 6 ); + scsi_cmd( sd, start_stop_unit_cmd, 6 ); + } else { + /* don't boot from this device (could be a scanner :-)) */ + return -1; + } + + /* wait for spin-up (or whatever) to complete */ + for( i=0; ; i++ ) { + if( i > 300 ) { + printk("SCSI timeout (sense %x)\n", sense ); + return -1; + } + sense = scsi_cmd( sd, test_unit_ready_cmd, 6 ); + if( (sense & 0xf0000) == 0x20000 ) { + OSI_USleep( 10000 ); + continue; + } + break; + } + + info->valid = 1; + return 0; +} + +/* ( -- success? ) */ +static void +scsi_open( instance_data_t *sd ) +{ + static int once = 0; + phandle_t ph; + + fword("my-unit"); + sd->target = POP(); + + if( !once ) { + once++; + OSI_SCSIControl( SCSI_CTRL_INIT, 0 ); + } + + /* obtiain device information */ + if( inquiry(sd) ) + RET(0); + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + PUSH( -1 ); +} + +/* ( -- ) */ +static void +scsi_close( instance_data_t *pb ) +{ + selfword("close-deblocker"); +} + + +/* ( -- bs ) */ +static void +scsi_block_size( instance_data_t *sd ) +{ + PUSH( sd->info->blocksize ); +} + +/* ( -- maxbytes ) */ +static void +scsi_max_transfer( instance_data_t *sd ) +{ + PUSH( 1024*1024 ); +} + +static void +scsi_initialize( instance_data_t *sd ) +{ + fword("is-deblocker"); +} + + +NODE_METHODS( scsi ) = { + { NULL, scsi_initialize }, + { "open", scsi_open }, + { "close", scsi_close }, + { "read-blocks", scsi_read_blocks }, + { "block-size", scsi_block_size }, + { "max-transfer", scsi_max_transfer }, +}; + +void +osiscsi_init( void ) +{ + REGISTER_NODE( scsi ); +} diff --git a/arch/ppc/mol/prom.c b/arch/ppc/mol/prom.c new file mode 100644 index 0000000..f6a9c53 --- /dev/null +++ b/arch/ppc/mol/prom.c @@ -0,0 +1,177 @@ +/* + * Creation Date: <2002/10/03 20:55:02 samuel> + * Time-stamp: <2002/10/29 13:00:23 samuel> + * + * + * + * oftree interface + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "osi_calls.h" +#include "mol/prom.h" + +/* OSI_PromClose (free linux side device tree) */ +int +prom_close( void ) +{ + return OSI_PromIface( kPromClose, 0 ); +} + +/* ret: 0 no more peers, -1 if error */ +mol_phandle_t +prom_peer( mol_phandle_t phandle ) +{ + return OSI_PromIface( kPromPeer, phandle ); +} + +/* ret: 0 no child, -1 if error */ +mol_phandle_t +prom_child( mol_phandle_t phandle ) +{ + return OSI_PromIface( kPromChild, phandle ); +} + +/* ret: 0 if root node, -1 if error */ +mol_phandle_t +prom_parent( mol_phandle_t phandle ) +{ + return OSI_PromIface( kPromParent, phandle ); +} + +/* ret: -1 error */ +int +prom_package_to_path( mol_phandle_t phandle, char *buf, long buflen ) +{ + return OSI_PromIface2( kPromPackageToPath, phandle, (int)buf, buflen ); +} + +/* ret: -1 error */ +int +prom_get_prop_len( mol_phandle_t phandle, const char *name ) +{ + return OSI_PromIface1( kPromGetPropLen, phandle, (int)name ); +} + +/* ret: prop len or -1 if error */ +int +prom_get_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ) +{ + return OSI_PromIface3( kPromGetProp, phandle, (int)name, (int)buf, buflen ); +} + +/* ret: prop len or -1 if error */ +int +prom_get_prop_by_path( const char *path, const char *name, char *buf, long buflen ) +{ + mol_phandle_t ph = prom_find_device(path); + return (ph != -1)? prom_get_prop( ph, name, buf, buflen) : -1; +} + +/* ret: -1 error, 0 last prop, 1 otherwise */ +int +prom_next_prop( mol_phandle_t phandle, const char *prev, char *buf ) +{ + return OSI_PromIface2( kPromNextProp, phandle, (int)prev, (int)buf ); +} + +/* ret: -1 if error */ +int +prom_set_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ) +{ + return OSI_PromIface3( kPromSetProp, phandle, (int)name, (int)buf, buflen ); +} + +/* ret: -1 if error */ +mol_phandle_t +prom_create_node( const char *path ) +{ + return OSI_PromPathIface( kPromCreateNode, path ); +} + +/* ret: -1 if not found */ +mol_phandle_t +prom_find_device( const char *path ) +{ + mol_phandle_t ph; + char buf2[256], ch, *p; + + if( !path ) + return -1; + + if( (ph=OSI_PromPathIface( kPromFindDevice, path )) != -1 ) + return ph; + else if( path[0] == '/' ) + return -1; + + /* might be an alias */ + if( !(p=strpbrk(path, "@:/")) ) + p = (char*)path + strlen(path); + + ch = *p; + *p = 0; + if( (ph=prom_get_prop(prom_find_device("/aliases"), path, buf2, sizeof(buf2))) == -1 ) + return -1; + *p = ch; + strncat( buf2, p, sizeof(buf2) ); + + if( buf2[0] != '/' ) { + printk("Error: aliases must be absolute!\n"); + return -1; + } + ph = OSI_PromPathIface( kPromFindDevice, buf2 ); + return ph; +} + + + +/************************************************************************/ +/* search the tree for nodes with matching device_type */ +/************************************************************************/ + +static mol_phandle_t +prom_find_device_type_( mol_phandle_t ph, const char *type, int *icount, int index ) +{ + char buf[64]; + int ph2; + + if( ph == -1 || !ph ) + return -1; + if( prom_get_prop( ph, "device_type", buf, sizeof(buf)) > 0 ) + if( !strcmp(buf, type) ) + if( (*icount)++ == index ) + return ph; + if( (ph2=prom_find_device_type_( prom_peer(ph), type, icount, index )) != -1 ) + return ph2; + if( (ph2=prom_find_device_type_( prom_child(ph), type, icount, index )) != -1 ) + return ph2; + return -1; +} + +mol_phandle_t +prom_find_device_type( const char *type, int index ) +{ + int count = 0; + return prom_find_device_type_( prom_peer(0), type, &count, index ); +} + + +/************************************************************************/ +/* device tree tweaking */ +/************************************************************************/ + +/* -1 if error */ +int +prom_change_phandle( mol_phandle_t old_ph, mol_phandle_t new_ph ) +{ + return OSI_PromIface1( kPromChangePHandle, old_ph, (int)new_ph ); +} + + diff --git a/arch/ppc/mol/prom.h b/arch/ppc/mol/prom.h new file mode 100644 index 0000000..e8f28ef --- /dev/null +++ b/arch/ppc/mol/prom.h @@ -0,0 +1,47 @@ +/* + * Creation Date: <2002/10/03 21:07:27 samuel> + * Time-stamp: <2003/10/22 22:45:26 samuel> + * + * + * + * device tree interface + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_PROM +#define _H_PROM + +/* Note 1: MOL uses -1 as the invalid phandle while OpenFirmware uses 0 as the + * invalid phandle (it is also the root node). + * + * Note 2: phandles might be negative. For instance, phandles originating from + * a real Open Firmware tree might look like 0xff123000 (a ROM address)... + */ + +typedef enum { kGetRootPhandle=0 } mol_phandle_t; /* must promote to int */ + +extern int prom_close( void ); + +extern mol_phandle_t prom_peer( mol_phandle_t phandle ); +extern mol_phandle_t prom_child( mol_phandle_t phandle ); +extern mol_phandle_t prom_parent( mol_phandle_t phandle ); +extern int prom_package_to_path( mol_phandle_t phandle, char *buf, long buflen ); +extern int prom_get_prop_len( mol_phandle_t phandle, const char *name ); +extern int prom_get_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ); +extern int prom_get_prop_by_path( const char *path, const char *name, char *buf, long buflen ); +extern int prom_next_prop( mol_phandle_t phandle, const char *prev, char *buf ); +extern int prom_set_prop( mol_phandle_t phandle, const char *name, char *buf, long buflen ); +extern mol_phandle_t prom_create_node( const char *path ); +extern mol_phandle_t prom_find_device( const char *path ); + +extern mol_phandle_t prom_find_device_type( const char *type, int index ); + +extern int prom_change_phandle( mol_phandle_t old_ph, mol_phandle_t new_ph ); + +#endif /* _H_PROM */ diff --git a/arch/ppc/mol/pseudodisk.c b/arch/ppc/mol/pseudodisk.c new file mode 100644 index 0000000..a216cfb --- /dev/null +++ b/arch/ppc/mol/pseudodisk.c @@ -0,0 +1,178 @@ +/* + * Creation Date: <2003/11/26 16:55:47 samuel> + * Time-stamp: <2004/01/07 19:41:54 samuel> + * + * + * + * pseudodisk (contains files exported from linux) + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "osi_calls.h" +#include "libc/string.h" +#include "ofmem.h" +#include "mol/prom.h" +#include "mol/mol.h" +#include "osi_calls.h" +#include "pseudofs_sh.h" + +typedef struct { + int seekpos; + int fd; + char *myargs; + char *name; + int size; +} pdisk_data_t; + + +DECLARE_NODE( pdisk, INSTALL_OPEN, sizeof(pdisk_data_t), "/mol/pseudo-disk/disk" ); + +static void +pdisk_open( pdisk_data_t *pb ) +{ + char *ep, *name = NULL; + int part; + + pb->myargs = my_args_copy(); + /* printk("pdisk-open: %s\n", pb->myargs ); */ + + part = strtol( pb->myargs, &ep, 10 ); + if( *ep ) { + if( (name=strchr(pb->myargs, ',')) ) { + *name = 0; + name++; + } else { + name = pb->myargs; + } + } + if( part ) + goto err; + + if( !name || !strlen(name) ) + pb->fd = -1; + else { + if( (pb->fd=PseudoFSOpen(name)) < 0 ) + goto err; + pb->size = PseudoFSGetSize( pb->fd ); + } + pb->name = name; + RET( -1 ); + err: + free( pb->myargs ); + RET(0); +} + +/* ( addr len -- actual ) */ +static void +pdisk_read( pdisk_data_t *pb ) +{ + int len = POP(); + char *dest = (char*)POP(); + int cnt; + + if( pb->fd < 0 ) { + memset( dest, 0, len ); + PUSH(len); + return; + } + /* dest is not "mol-DMA" safe (might have a nontrivial mapping) */ + for( cnt=0; cntfd, pb->seekpos, buf, n ); + if( n <= 0 ) + break; + + memcpy( dest+cnt, buf, n ); + cnt += n; + pb->seekpos += n; + } + PUSH( cnt ); +} + +/* ( addr len -- actual ) */ +static void +pdisk_write( pdisk_data_t *pb ) +{ + POP(); POP(); PUSH(-1); + printk("pdisk write\n"); +} + +/* ( pos.lo pos.hi -- status ) */ +static void +pdisk_seek( pdisk_data_t *pb ) +{ + int pos_lo; + POP(); + pos_lo = POP(); + + if( pb->fd >= 0 ) { + if( pos_lo == -1 ) + pos_lo = pb->size; + } + + pb->seekpos = pos_lo; + + PUSH(0); /* ??? */ +} + +/* ( -- pos.d ) */ +static void +pdisk_tell( pdisk_data_t *pb ) +{ + DPUSH( pb->seekpos ); +} + +/* ( -- cstr ) */ +static void +pdisk_get_path( pdisk_data_t *pb ) +{ + PUSH( (int)pb->name ); +} + +/* ( -- cstr ) */ +static void +pdisk_get_fstype( pdisk_data_t *pb ) +{ + PUSH( (int)"PSEUDO" ); +} + +/* ( -- cstr ) */ +static void +pdisk_volume_name( pdisk_data_t *pb ) +{ + PUSH( (int)"Virtual Volume" ); +} + +static void +pdisk_block_size( pdisk_data_t *pb ) +{ + PUSH(1); +} + +NODE_METHODS( pdisk ) = { + { "open", pdisk_open }, + { "read", pdisk_read }, + { "write", pdisk_write }, + { "seek", pdisk_seek }, + { "tell", pdisk_tell }, + { "block-size", pdisk_block_size }, + { "get-path", pdisk_get_path }, + { "get-fstype", pdisk_get_fstype }, + { "volume-name", pdisk_volume_name }, +}; + +void +pseudodisk_init( void ) +{ + REGISTER_NODE( pdisk ); +} diff --git a/arch/ppc/mol/tree.c b/arch/ppc/mol/tree.c new file mode 100644 index 0000000..9494b6c --- /dev/null +++ b/arch/ppc/mol/tree.c @@ -0,0 +1,165 @@ +/* + * Creation Date: <2003/11/18 14:55:05 samuel> + * Time-stamp: <2004/03/27 02:03:55 samuel> + * + * + * + * device tree setup + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "mol/mol.h" +#include "mol/prom.h" + + +/************************************************************************/ +/* copy device tree */ +/************************************************************************/ + +static void +copy_node( mol_phandle_t molph ) +{ + char name[40], path[80]; + int exists; + phandle_t ph; + + if( !molph ) + return; + + prom_package_to_path( molph, path, sizeof(path) ); + + /* don't copy /options node */ + if( !strcmp("/options", path) ) { + copy_node( prom_peer(molph) ); + return; + } + + exists = 1; + if( !(ph=find_dev(path)) ) { + exists = 0; + fword("new-device"); + ph = get_cur_dev(); + } + activate_dev( ph ); + + name[0] = 0; + while( prom_next_prop(molph, name, name) > 0 ) { + int len = prom_get_prop_len( molph, name ); + char *p; +#if 0 + if( len > 0x1000 ) { + printk("prop to large (%d)\n", len ); + continue; + } +#endif + /* don't copy /chosen/{stdin,stdout} (XXX: ugly hack...) */ + if( !strcmp("/chosen", path) ) + if( !strcmp("stdio", name) || !strcmp("stdout", name) ) + continue; + + p = malloc( len ); + prom_get_prop( molph, name, p, len ); + set_property( ph, name, p, len ); + free( p ); + } + + set_int_property( ph, "MOL,phandle", molph ); + copy_node( prom_child(molph) ); + + if( !exists ) + fword("finish-device"); + else + activate_device(".."); + + copy_node( prom_peer(molph) ); +} + + + +/************************************************************************/ +/* device tree cloning and tweaking */ +/************************************************************************/ + +static phandle_t +translate_molph( mol_phandle_t molph ) +{ + static mol_phandle_t cached_molph; + static phandle_t cached_ph; + phandle_t ph=0; + + if( cached_molph == molph ) + return cached_ph; + + while( (ph=dt_iterate(ph)) ) + if( get_int_property(ph, "MOL,phandle", NULL) == molph ) + break; + cached_molph = molph; + cached_ph = ph; + + if( !ph ) + printk("failed to translate molph\n"); + return ph; +} + +static void +fix_phandles( void ) +{ + static char *pnames[] = { "interrupt-parent", "interrupt-controller", NULL } ; + int len, *map; + phandle_t ph=0; + char **pp; + + while( (ph=dt_iterate(ph)) ) { + for( pp=pnames; *pp; pp++ ) { + phandle_t *p = (phandle_t*)get_property( ph, *pp, &len ); + if( len == 4 ) + *p = translate_molph( *(int*)p ); + } + + /* need to fix interrupt map properties too */ + if( (map=(int*)get_property(ph, "interrupt-map", &len)) ) { + int i, acells = get_int_property(ph, "#address-cells", NULL); + int icells = get_int_property(ph, "#interrupt-cells", NULL); + + len /= sizeof(int); + for( i=0; i + * Time-stamp: <2004/01/07 19:42:36 samuel> + * + * + * + * OF Memory manager + * + * Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +/* TODO: Clean up MOLisms in a decent way */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/string.h" +#include "ofmem.h" +#include "kernel.h" +#ifdef I_WANT_MOLISMS +#include "mol/prom.h" +#include "mol/mol.h" +#endif +#include "mmutypes.h" +#include "asm/processor.h" +#ifdef I_WANT_MOLISMS +#include "osi_calls.h" +#endif + +#define BIT(n) (1U<<(31-(n))) + +/* called from assembly */ +extern void dsi_exception( void ); +extern void isi_exception( void ); +extern void setup_mmu( ulong code_base, ulong code_size, ulong ramsize ); + +/**************************************************************** + * Memory usage (before of_quiesce is called) + * + * Physical + * + * 0x00000000 Exception vectors + * 0x00004000 Free space + * 0x01e00000 Open Firmware (us) + * 0x01f00000 OF allocations + * 0x01ff0000 PTE Hash + * 0x02000000- Free space + * + * Allocations grow downwards from 0x01e00000 + * + ****************************************************************/ + +#define HASH_SIZE (2 << 15) +#define SEGR_BASE 0x400 /* segment number range to use */ + +#define FREE_BASE_1 0x00004000 +#define OF_CODE_START 0x01e00000 +/* #define OF_MALLOC_BASE 0x01f00000 */ +extern char _end[]; +#define OF_MALLOC_BASE _end + +#define HASH_BASE (0x02000000 - HASH_SIZE) +#define FREE_BASE_2 0x02000000 + +#define RAMSIZE 0x02000000 /* XXXXXXXXXXXXXXXXXXX FIXME XXXXXXXXXXXXXXX */ + +typedef struct alloc_desc { + struct alloc_desc *next; + int size; /* size (including) this struct */ +} alloc_desc_t; + +typedef struct mem_range { + struct mem_range *next; + ulong start; + ulong size; +} range_t; + +typedef struct trans { + struct trans *next; + ulong virt; /* chain is sorted by virt */ + ulong size; + ulong phys; + int mode; +} translation_t; + +static struct { + char *next_malloc; + alloc_desc_t *mfree; /* list of free malloc blocks */ + + range_t *phys_range; + range_t *virt_range; + + translation_t *trans; /* this is really a translation_t */ +} ofmem; + + +/************************************************************************/ +/* OF private allocations */ +/************************************************************************/ + +void * +malloc( int size ) +{ + alloc_desc_t *d, **pp; + char *ret; + + if( !size ) + return NULL; + + if( !ofmem.next_malloc ) + ofmem.next_malloc = (char*)OF_MALLOC_BASE; + + if( size & 3 ) + size += 4 - (size & 3); + size += sizeof(alloc_desc_t); + + /* look in the freelist */ + for( pp=&ofmem.mfree; *pp && (**pp).size < size; pp = &(**pp).next ) + ; + + /* waste at most 4K by taking an entry from the freelist */ + if( *pp && (**pp).size < size + 0x1000 ) { + ret = (char*)*pp + sizeof(alloc_desc_t); + memset( ret, 0, (**pp).size - sizeof(alloc_desc_t) ); + *pp = (**pp).next; + return ret; + } + + if( (ulong)ofmem.next_malloc + size > HASH_BASE ) { + printk("out of malloc memory (%x)!\n", size ); + return NULL; + } + d = (alloc_desc_t*) ofmem.next_malloc; + ofmem.next_malloc += size; + + d->next = NULL; + d->size = size; + + ret = (char*)d + sizeof(alloc_desc_t); + memset( ret, 0, size - sizeof(alloc_desc_t) ); + return ret; +} + +void +free( void *ptr ) +{ + alloc_desc_t **pp, *d; + + /* it is legal to free NULL pointers (size zero allocations) */ + if( !ptr ) + return; + + d = (alloc_desc_t*)(ptr - sizeof(alloc_desc_t)); + d->next = ofmem.mfree; + + /* insert in the (sorted) freelist */ + for( pp=&ofmem.mfree; *pp && (**pp).size < d->size ; pp = &(**pp).next ) + ; + d->next = *pp; + *pp = d; +} + +void * +realloc( void *ptr, size_t size ) +{ + alloc_desc_t *d = (alloc_desc_t*)(ptr - sizeof(alloc_desc_t)); + char *p; + + if( !ptr ) + return malloc( size ); + if( !size ) { + free( ptr ); + return NULL; + } + p = malloc( size ); + memcpy( p, ptr, MIN(d->size - sizeof(alloc_desc_t),size) ); + free( ptr ); + return p; +} + + +/************************************************************************/ +/* debug */ +/************************************************************************/ + +#if 0 +static void +print_range( range_t *r, char *str ) +{ + printk("--- Range %s ---\n", str ); + for( ; r; r=r->next ) + printk("%08lx - %08lx\n", r->start, r->start + r->size -1 ); + printk("\n"); +} + +static void +print_phys_range() +{ + print_range( ofmem.phys_range, "phys" ); +} + +static void +print_virt_range() +{ + print_range( ofmem.virt_range, "virt" ); +} + +static void +print_trans( void ) +{ + translation_t *t = ofmem.trans; + + printk("--- Translations ---\n"); + for( ; t; t=t->next ) + printk("%08lx -> %08lx [size %lx]\n", t->virt, t->phys, t->size ); + printk("\n"); +} +#endif + + +/************************************************************************/ +/* misc */ +/************************************************************************/ + +static inline int +def_memmode( ulong phys ) +{ + /* XXX: Guard bit not set as it should! */ + if( phys < 0x80000000 || phys >= 0xffc00000 ) + return 0x02; /*0xa*/ /* wim GxPp */ + return 0x6a; /* WIm GxPp, I/O */ +} + + +/************************************************************************/ +/* client interface */ +/************************************************************************/ + +static int +is_free( ulong ea, ulong size, range_t *r ) +{ + if( size == 0 ) + return 1; + for( ; r ; r=r->next ) { + if( r->start + r->size - 1 >= ea && r->start <= ea ) + return 0; + if( r->start >= ea && r->start <= ea + size - 1 ) + return 0; + } + return 1; +} + +static void +add_entry_( ulong ea, ulong size, range_t **r ) +{ + range_t *nr; + + for( ; *r && (**r).start < ea; r=&(**r).next ) + ; + nr = (range_t*)malloc( sizeof(range_t) ); + nr->next = *r; + nr->start = ea; + nr->size = size; + *r = nr; +} + +static int +add_entry( ulong ea, ulong size, range_t **r ) +{ + if( !is_free( ea, size, *r ) ) { + printk("add_entry: range not free!\n"); + return -1; + } + add_entry_( ea, size, r ); + return 0; +} + +static void +join_ranges( range_t **rr ) +{ + range_t *n, *r = *rr; + while( r ) { + if( !(n=r->next) ) + break; + + if( r->start + r->size - 1 >= n->start -1 ) { + int s = n->size + (n->start - r->start - r->size); + if( s > 0 ) + r->size += s; + r->next = n->next; + free( n ); + continue; + } + r=r->next; + } +} + +static void +fill_range( ulong ea, int size, range_t **rr ) +{ + add_entry_( ea, size, rr ); + join_ranges( rr ); +} + +static ulong +find_area( ulong align, ulong size, range_t *r, ulong min, ulong max, int reverse ) +{ + ulong base = min; + range_t *r2; + + if( (align & (align-1)) ) { + printk("bad alignment %ld\n", align); + align = 0x1000; + } + if( !align ) + align = 0x1000; + + base = reverse ? max - size : min; + r2 = reverse ? NULL : r; + + for( ;; ) { + if( !reverse ) { + base = (base + align - 1) & ~(align-1); + if( base < min ) + base = min; + if( base + size - 1 >= max -1 ) + break; + } else { + if( base > max - size ) + base = max - size; + base -= base & (align-1); + } + if( is_free( base, size, r ) ) + return base; + + if( !reverse ) { + if( !r2 ) + break; + base = r2->start + r2->size; + r2 = r2->next; + } else { + range_t *rp; + for( rp=r; rp && rp->next != r2 ; rp=rp->next ) + ; + r2 = rp; + if( !r2 ) + break; + base = r2->start - size; + } + } + return (ulong)-1; +} + +static ulong +ofmem_claim_phys_( ulong phys, ulong size, ulong align, int min, int max, int reverse ) +{ + if( !align ) { + if( !is_free( phys, size, ofmem.phys_range ) ) { + printk("Non-free physical memory claimed!\n"); + return -1; + } + add_entry( phys, size, &ofmem.phys_range ); + return phys; + } + phys = find_area( align, size, ofmem.phys_range, min, max, reverse ); + if( phys == (ulong)-1 ) { + printk("ofmem_claim_phys - out of space\n"); + return -1; + } + add_entry( phys, size, &ofmem.phys_range ); + return phys; +} + +/* if align != 0, phys is ignored. Returns -1 on error */ +ulong +ofmem_claim_phys( ulong phys, ulong size, ulong align ) +{ + /* printk("+ ofmem_claim phys %08lx %lx %ld\n", phys, size, align ); */ + return ofmem_claim_phys_( phys, size, align, 0, RAMSIZE, 0 ); +} + +static ulong +ofmem_claim_virt_( ulong virt, ulong size, ulong align, int min, int max, int reverse ) +{ + if( !align ) { + if( !is_free( virt, size, ofmem.virt_range ) ) { + printk("Non-free physical memory claimed!\n"); + return -1; + } + add_entry( virt, size, &ofmem.virt_range ); + return virt; + } + + virt = find_area( align, size, ofmem.virt_range, min, max, reverse ); + if( virt == (ulong)-1 ) { + printk("ofmem_claim_virt - out of space\n"); + return -1; + } + add_entry( virt, size, &ofmem.virt_range ); + return virt; +} + +ulong +ofmem_claim_virt( ulong virt, ulong size, ulong align ) +{ + /* printk("+ ofmem_claim virt %08lx %lx %ld\n", virt, size, align ); */ + return ofmem_claim_virt_( virt, size, align, RAMSIZE, 0x80000000, 0 ); +} + + +/* allocate both physical and virtual space and add a translation */ +ulong +ofmem_claim( ulong addr, ulong size, ulong align ) +{ + ulong virt, phys; + ulong offs = addr & 0xfff; + + /* printk("+ ofmem_claim %08lx %lx %ld\n", addr, size, align ); */ + virt = phys = 0; + if( !align ) { + if( is_free(addr, size, ofmem.virt_range) && is_free(addr, size, ofmem.phys_range) ) { + ofmem_claim_phys_( addr, size, 0, 0, 0, 0 ); + ofmem_claim_virt_( addr, size, 0, 0, 0, 0 ); + virt = phys = addr; + } else { + printk("**** ofmem_claim failure ***!\n"); + return -1; + } + } else { + if( align < 0x1000 ) + align = 0x1000; + phys = ofmem_claim_phys_( addr, size, align, 0, RAMSIZE, 1 /* reverse */ ); + virt = ofmem_claim_virt_( addr, size, align, 0, RAMSIZE, 1 /* reverse */ ); + if( phys == (ulong)-1 || virt == (ulong)-1 ) { + printk("ofmem_claim failed\n"); + return -1; + } + /* printk("...phys = %08lX, virt = %08lX, size = %08lX\n", phys, virt, size ); */ + } + + /* align */ + if( phys & 0xfff ) { + size += (phys & 0xfff); + virt -= (phys & 0xfff); + phys &= ~0xfff; + } + if( size & 0xfff ) + size = (size + 0xfff) & ~0xfff; + + /* printk("...free memory found... phys: %08lX, virt: %08lX, size %lX\n", phys, virt, size ); */ + ofmem_map( phys, virt, size, def_memmode(phys) ); + return virt + offs; +} + + +/************************************************************************/ +/* keep track of ea -> phys translations */ +/************************************************************************/ + +static void +split_trans( ulong virt ) +{ + translation_t *t, *t2; + + for( t=ofmem.trans; t; t=t->next ) { + if( virt > t->virt && virt < t->virt + t->size-1 ) { + t2 = (translation_t*)malloc( sizeof(translation_t) ); + t2->virt = virt; + t2->size = t->size - (virt - t->virt); + t->size = virt - t->virt; + t2->phys = t->phys + t->size; + t2->mode = t->mode; + t2->next = t->next; + t->next = t2; + } + } +} + +static int +map_page_range( ulong virt, ulong phys, ulong size, int mode ) +{ + translation_t *t, **tt; + + split_trans( virt ); + split_trans( virt + size ); + + /* detect remappings */ + for( t=ofmem.trans; t; ) { + if( virt == t->virt || (virt < t->virt && virt + size > t->virt )) { + if( t->phys + virt - t->virt != phys ) { + printk("mapping altered (ea %08lx)\n", t->virt ); + } else if( t->mode != mode ){ + printk("mapping mode altered\n"); + } + for( tt=&ofmem.trans; *tt != t ; tt=&(**tt).next ) + ; + *tt = t->next; + free((char*)t); + t=ofmem.trans; + continue; + } + t=t->next; + } + /* add mapping */ + for( tt=&ofmem.trans; *tt && (**tt).virt < virt ; tt=&(**tt).next ) + ; + t = (translation_t*)malloc( sizeof(translation_t) ); + t->virt = virt; + t->phys = phys; + t->size = size; + t->mode = mode; + t->next = *tt; + *tt = t; + + return 0; +} + +int +ofmem_map( ulong phys, ulong virt, ulong size, int mode ) +{ + /* printk("+ofmem_map: %08lX --> %08lX (size %08lX, mode 0x%02X)\n", + virt, phys, size, mode ); */ + + if( (phys & 0xfff) || (virt & 0xfff) || (size & 0xfff) ) { + printk("ofmem_map: Bad parameters (%08lX %08lX %08lX)\n", phys, virt, size ); + phys &= ~0xfff; + virt &= ~0xfff; + size = (size + 0xfff) & ~0xfff; + } +#if 1 + /* claim any unclaimed virtual memory in the range */ + fill_range( virt, size, &ofmem.virt_range ); + /* hmm... we better claim the physical range too */ + fill_range( phys, size, &ofmem.phys_range ); +#endif + //printk("map_page_range %08lx -> %08lx %08lx\n", virt, phys, size ); + map_page_range( virt, phys, size, (mode==-1)? def_memmode(phys) : mode ); + return 0; +} + +/* virtual -> physical. */ +ulong +ofmem_translate( ulong virt, ulong *mode ) +{ + translation_t *t; + + for( t=ofmem.trans; t && t->virt <= virt ; t=t->next ) { + ulong offs; + if( t->virt + t->size - 1 < virt ) + continue; + offs = virt - t->virt; + *mode = t->mode; + return t->phys + offs; + } + + //printk("ofmem_translate: no translation defined (%08lx)\n", virt); + //print_trans(); + return -1; +} + +/* release memory allocated by ofmem_claim */ +void +ofmem_release( ulong virt, ulong size ) +{ + /* printk("ofmem_release unimplemented (%08lx, %08lx)\n", virt, size ); */ +} + + +/************************************************************************/ +/* page fault handler */ +/************************************************************************/ + +static ulong +ea_to_phys( ulong ea, int *mode ) +{ + ulong phys; + + /* hardcode our translation needs */ + if( ea >= OF_CODE_START && ea < FREE_BASE_2 ) { + *mode = def_memmode( ea ); + return ea; + } + if( (phys=ofmem_translate(ea, (ulong*)mode)) == (ulong)-1 ) { +#ifdef I_WANT_MOLISMS + if( ea != 0x80816c00 ) + printk("ea_to_phys: no translation for %08lx, using 1-1\n", ea ); +#endif + phys = ea; + *mode = def_memmode( phys ); + +#ifdef I_WANT_MOLISMS + forth_segv_handler( (char*)ea ); + OSI_Debugger(1); +#endif + /* print_virt_range(); */ + /* print_phys_range(); */ + /* print_trans(); */ + } + return phys; +} + +static void +hash_page( ulong ea, ulong phys, int mode ) +{ + static int next_grab_slot=0; + ulong *upte, cmp, hash1; + int i, vsid, found; + mPTE_t *pp; + + vsid = (ea>>28) + SEGR_BASE; + cmp = BIT(0) | (vsid << 7) | ((ea & 0x0fffffff) >> 22); + + hash1 = vsid; + hash1 ^= (ea >> 12) & 0xffff; + hash1 &= (HASH_SIZE-1) >> 6; + + pp = (mPTE_t*)(HASH_BASE + (hash1 << 6)); + upte = (ulong*)pp; + + /* replace old translation */ + for( found=0, i=0; !found && i<8; i++ ) + if( cmp == upte[i*2] ) + found=1; + + /* otherwise use a free slot */ + for( i=0; !found && i<8; i++ ) + if( !pp[i].v ) + found=1; + + /* out of slots, just evict one */ + if( !found ) { + i = next_grab_slot + 1; + next_grab_slot = (next_grab_slot + 1) % 8; + } + i--; + upte[i*2] = cmp; + upte[i*2+1] = (phys & ~0xfff) | mode; + + asm volatile( "tlbie %0" :: "r"(ea) ); +} + +void +dsi_exception( void ) +{ + ulong dar, dsisr; + int mode; + + asm volatile("mfdar %0" : "=r" (dar) : ); + asm volatile("mfdsisr %0" : "=r" (dsisr) : ); + //printk("dsi-exception @ %08lx <%08lx>\n", dar, dsisr ); + hash_page( dar, ea_to_phys(dar, &mode), mode ); +} + +void +isi_exception( void ) +{ + ulong nip, srr1; + int mode; + + asm volatile("mfsrr0 %0" : "=r" (nip) : ); + asm volatile("mfsrr1 %0" : "=r" (srr1) : ); + + //printk("isi-exception @ %08lx <%08lx>\n", nip, srr1 ); + hash_page( nip, ea_to_phys(nip, &mode), mode ); +} + + +/************************************************************************/ +/* init / cleanup */ +/************************************************************************/ + +void +setup_mmu( ulong code_base, ulong code_size, ulong ramsize ) +{ + ulong sdr1 = HASH_BASE | ((HASH_SIZE-1) >> 16); + ulong sr_base = (0x20 << 24) | SEGR_BASE; + ulong msr; + int i; + + asm volatile("mtsdr1 %0" :: "r" (sdr1) ); + for( i=0; i<16; i++ ) { + int j = i << 28; + asm volatile("mtsrin %0,%1" :: "r" (sr_base + i), "r" (j) ); + } + asm volatile("mfmsr %0" : "=r" (msr) : ); + msr |= MSR_IR | MSR_DR; + asm volatile("mtmsr %0" :: "r" (msr) ); +} + +void +ofmem_init( void ) +{ + /* In case we can't rely on memory being zero initialized */ + memset(&ofmem, 0, sizeof(ofmem)); + + ofmem_claim_phys( 0, FREE_BASE_1, 0 ); + ofmem_claim_virt( 0, FREE_BASE_1, 0 ); + ofmem_claim_phys( OF_CODE_START, FREE_BASE_2 - OF_CODE_START, 0 ); + ofmem_claim_virt( OF_CODE_START, FREE_BASE_2 - OF_CODE_START, 0 ); +} diff --git a/arch/ppc/osi.h b/arch/ppc/osi.h new file mode 100644 index 0000000..e6390bd --- /dev/null +++ b/arch/ppc/osi.h @@ -0,0 +1,170 @@ +/* + * Creation Date: <1999/03/18 03:19:43 samuel> + * Time-stamp: <2003/12/26 16:58:19 samuel> + * + * + * + * This file includes definitions for drivers + * running in the "emulated" OS. (Mainly the 'sc' + * mechanism of communicating) + * + * Copyright (C) 1999, 2000, 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_OSI +#define _H_OSI + +/* Magic register values loaded into r3 and r4 before the 'sc' assembly instruction */ +#define OSI_SC_MAGIC_R3 0x113724FA +#define OSI_SC_MAGIC_R4 0x77810F9B + + +/************************************************************************/ +/* Selectors (passed in r5) */ +/************************************************************************/ + +#define OSI_CALL_AVAILABLE 0 +#define OSI_DEBUGGER 1 /* enter debugger */ +/* obsolete OSI_LOG_STR 3 */ +#define OSI_CMOUNT_DRV_VOL 4 /* conditionally mount driver volume */ +/* obsolete OSI_SCSI_xxx 5-6 */ +#define OSI_GET_GMT_TIME 7 +#define OSI_MOUSE_CNTRL 8 +#define OSI_GET_LOCALTIME 9 /* return time in secs from 01/01/04 */ + +#define OSI_ENET_OPEN 10 +#define OSI_ENET_CLOSE 11 +#define OSI_ENET_GET_ADDR 12 +#define OSI_ENET_GET_STATUS 13 +#define OSI_ENET_CONTROL 14 +#define OSI_ENET_ADD_MULTI 16 +#define OSI_ENET_DEL_MULTI 17 +#define OSI_ENET_GET_PACKET 18 +#define OSI_ENET_SEND_PACKET 19 + +#define OSI_OF_INTERFACE 20 +#define OSI_OF_TRAP 21 +#define OSI_OF_RTAS 22 + +#define OSI_SCSI_CNTRL 23 +#define OSI_SCSI_SUBMIT 24 +#define OSI_SCSI_ACK 25 + +#define OSI_GET_MOUSE 26 /* -- r3 status, r4-r8 mouse data */ +#define OSI_ACK_MOUSE_IRQ 27 /* -- int */ + +#define OSI_SET_VMODE 28 /* modeID, depth -- error */ +#define OSI_GET_VMODE_INFO 29 /* mode, depth -- r3 status, r4-r9 pb */ +#define OSI_GET_MOUSE_DPI 30 /* -- mouse_dpi */ + +#define OSI_SET_VIDEO_POWER 31 +#define OSI_GET_FB_INFO 32 /* void -- r3 status, r4-r8 video data */ + +#define OSI_SOUND_WRITE 33 +/* #define OSI_SOUND_FORMAT 34 */ +#define OSI_SOUND_SET_VOLUME 35 +#define OSI_SOUND_CNTL 36 +/* obsolete OSI_SOUND call 37 */ + +#define OSI_VIDEO_ACK_IRQ 38 +#define OSI_VIDEO_CNTRL 39 + +#define OSI_SOUND_IRQ_ACK 40 +#define OSI_SOUND_START_STOP 41 + +#define OSI_REGISTER_IRQ 42 /* reg_property[0] appl_int -- irq_cookie */ +/* obsolete OSI_IRQ 43-46 */ + +#define OSI_LOG_PUTC 47 /* char -- */ + +#define OSI_KBD_CNTRL 50 +#define OSI_GET_ADB_KEY 51 /* -- adb_keycode (keycode | keycode_id in r4) */ + +#define OSI_WRITE_NVRAM_BYTE 52 /* offs, byte -- */ +#define OSI_READ_NVRAM_BYTE 53 /* offs -- byte */ + +#define OSI_EXIT 54 + +#define OSI_KEYCODE_TO_ADB 55 /* (keycode | keycode_id) -- adb_keycode */ +#define OSI_MAP_ADB_KEY 56 /* keycode, adbcode -- */ +#define OSI_SAVE_KEYMAPPING 57 /* -- */ +#define OSI_USLEEP 58 /* usecs -- */ +#define OSI_SET_COLOR 59 /* index value -- */ + +#define OSI_PIC_MASK_IRQ 60 /* irq -- */ +#define OSI_PIC_UNMASK_IRQ 61 /* irq -- */ +#define OSI_PIC_ACK_IRQ 62 /* irq mask_flag -- */ +#define OSI_PIC_GET_ACTIVE_IRQ 63 + +#define OSI_GET_COLOR 64 /* index -- value */ + +/* 65-67 old ablk implementation */ +#define OSI_IRQTEST 65 + +#define OSI_ENET2_OPEN 68 +#define OSI_ENET2_CLOSE 69 +#define OSI_ENET2_CNTRL 70 +#define OSI_ENET2_RING_SETUP 71 +#define OSI_ENET2_KICK 72 +#define OSI_ENET2_GET_HWADDR 73 +#define OSI_ENET2_IRQ_ACK 74 + +#define OSI_PROM_IFACE 76 +#define kPromClose 0 +#define kPromPeer 1 +#define kPromChild 2 +#define kPromParent 3 +#define kPromPackageToPath 4 +#define kPromGetPropLen 5 +#define kPromGetProp 6 +#define kPromNextProp 7 +#define kPromSetProp 8 +#define kPromChangePHandle 9 + +#define OSI_PROM_PATH_IFACE 77 +#define kPromCreateNode 16 +#define kPromFindDevice 17 + +#define OSI_BOOT_HELPER 78 +#define kBootHAscii2Unicode 32 +#define kBootHUnicode2Ascii 33 +#define kBootHGetStrResInd 34 /* key, buf, len -- buf */ +#define kBootHGetRAMSize 35 /* -- ramsize */ + +#define OSI_ABLK_RING_SETUP 79 +#define OSI_ABLK_CNTRL 80 +#define OSI_ABLK_DISK_INFO 81 +#define OSI_ABLK_KICK 82 +#define OSI_ABLK_IRQ_ACK 83 +#define OSI_ABLK_SYNC_READ 84 +#define OSI_ABLK_SYNC_WRITE 85 +#define OSI_ABLK_BLESS_DISK 86 + +#define OSI_EMUACCEL 89 /* EMULATE_xxx, nip -- index */ +#define OSI_MAPIN_MREGS 90 /* mphys */ +#define OSI_NVRAM_SIZE 91 + +#define OSI_MTICKS_TO_USECS 92 +#define OSI_USECS_TO_MTICKS 93 + +/* obsolete OSI_BLK 94-95 */ + +#define OSI_PSEUDO_FS 96 +#define kPseudoFSOpen 1 +#define kPseudoFSClose 2 +#define kPseudoFSGetSize 3 +#define kPseudoFSRead 4 +#define kPseudoFSIndex2Name 5 + +#define OSI_TTY_PUTC 97 +#define OSI_TTY_GETC 98 +#define OSI_TTY_IRQ_ACK 99 + +#define NUM_OSI_SELECTORS 100 /* remember to increase this... */ + +#endif /* _H_OSI */ diff --git a/arch/ppc/osi_calls.h b/arch/ppc/osi_calls.h new file mode 100644 index 0000000..e475a8e --- /dev/null +++ b/arch/ppc/osi_calls.h @@ -0,0 +1,454 @@ +/* + * Creation Date: <2002/06/16 01:40:57 samuel> + * Time-stamp: <2003/12/26 17:02:09 samuel> + * + * + * + * OSI call inlines + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_OSI_CALLS +#define _H_OSI_CALLS + +#include "osi.h" + +/* Old gcc versions have a limit on the number of registers used. + * Newer gcc versions (gcc 3.3) require that the clobber list does + * not overlap declared registers. + */ +#if __GNUC__ == 2 || ( __GNUC__ == 3 && __GNUC_MINOR__ < 3 ) +#define SHORT_REGLIST +#endif + + +/************************************************************************/ +/* OSI call instantiation macros */ +/************************************************************************/ + +#define dreg(n) __oc_##n __asm__ (#n) +#define ir(n) "r" (__oc_##n) +#define rr(n) "=r" (__oc_##n) + +#define _oc_head( input_regs... ) \ +{ \ + int _ret=0; \ + { \ + register unsigned long dreg(r3); \ + register unsigned long dreg(r4); \ + register unsigned long dreg(r5) \ + ,##input_regs ; + +#define _oc_syscall( number, extra_ret_regs... ) \ + __oc_r3 = OSI_SC_MAGIC_R3; \ + __oc_r4 = OSI_SC_MAGIC_R4; \ + __oc_r5 = number; \ + __asm__ __volatile__ ( \ + "sc " : rr(r3) ,## extra_ret_regs + +#define _oc_input( regs... ) \ + : ir(r3), ir(r4), ir(r5) \ + , ## regs \ + : "memory" ); + +/* the tail memory clobber is necessary since we violate the strict + * aliasing rules when we return structs through the registers. + */ +#define _oc_tail \ + asm volatile ( "" : : : "memory" ); \ + _ret = __oc_r3; \ + } \ + return _ret; \ +} + + +/************************************************************************/ +/* Alternatives */ +/************************************************************************/ + +#ifdef SHORT_REGLIST +#define _oc_syscall_r10w6( number, inputregs... ) \ + __oc_r3 = OSI_SC_MAGIC_R3; \ + __oc_r4 = OSI_SC_MAGIC_R4; \ + __oc_r5 = number; \ + __asm__ __volatile__ ( \ + "sc \n" \ + "stw 4,0(10) \n" \ + "stw 5,4(10) \n" \ + "stw 6,8(10) \n" \ + "stw 7,12(10) \n" \ + "stw 8,16(10) \n" \ + "stw 9,20(10) \n" \ + : rr(r3) \ + : ir(r3), ir(r4), ir(r5), ir(r10) \ + ,## inputregs \ + : "memory", \ + "r4", "r5", "r6", "r7", "r8", "r9" ); +#endif + + +/************************************************************************/ +/* Common helper functions */ +/************************************************************************/ + +#define _osi_call0( type, name, number ) \ +type name( void ) \ + _oc_head() \ + _oc_syscall( number ) \ + _oc_input() \ + _oc_tail + +#define _osi_call1( type, name, number, type1, arg1 ) \ +type name( type1 arg1 ) \ + _oc_head( dreg(r6) ) \ + __oc_r6 = (ulong)arg1; \ + _oc_syscall( number ) \ + _oc_input( ir(r6) ) \ + _oc_tail + +#define _osi_call2( type, name, number, t1, a1, t2, a2 ) \ +type name( t1 a1, t2 a2 ) \ + _oc_head( dreg(r6), dreg(r7) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + _oc_syscall( number ) \ + _oc_input( ir(r6), ir(r7) ) \ + _oc_tail + +#define _osi_call3( type, name, number, t1, a1, t2, a2, t3, a3 ) \ +type name( t1 a1, t2 a2, t3 a3 ) \ + _oc_head( dreg(r6), dreg(r7), dreg(r8) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + __oc_r8 = (ulong)a3; \ + _oc_syscall( number ) \ + _oc_input( ir(r6), ir(r7), ir(r8) ) \ + _oc_tail + +#define _osi_call4( type, name, number, t1, a1, t2, a2, t3, a3, t4, a4 ) \ +type name( t1 a1, t2 a2, t3 a3, t4 a4 ) \ + _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + __oc_r8 = (ulong)a3; \ + __oc_r9 = (ulong)a4; \ + _oc_syscall( number ) \ + _oc_input( ir(r6), ir(r7), ir(r8), ir(r9) ) \ + _oc_tail + +#define _osi_call5( type, name, number, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5 ) \ +type name( t1 a1, t2 a2, t3 a3, t4 a4, t5 a5 ) \ + _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9), dreg(r10) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + __oc_r8 = (ulong)a3; \ + __oc_r9 = (ulong)a4; \ + __oc_r10 = (ulong)a5; \ + _oc_syscall( number ) \ + _oc_input( ir(r6), ir(r7), ir(r8), ir(r9), ir(r10) ) \ + _oc_tail + +#define _osi_call6( type, name, number, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6 ) \ +type name( t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6 ) \ + _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9), dreg(r10), dreg(r11) )\ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + __oc_r8 = (ulong)a3; \ + __oc_r9 = (ulong)a4; \ + __oc_r10 = (ulong)a5; \ + __oc_r11 = (ulong)a6; \ + _oc_syscall( number ) \ + _oc_input( ir(r6), ir(r7), ir(r8), ir(r9), ir(r10), ir(r11) ) \ + _oc_tail + + +/************************************************************************/ +/* Special */ +/************************************************************************/ + +/* r4 returned in retarg1 pointer */ +#define _osi_call0_w1( type, name, number, type1, retarg1 ) \ +type name( type1 retarg1 ) \ + _oc_head() \ + _oc_syscall( number, rr(r4) ) \ + _oc_input() \ + *retarg1 = __oc_r4; \ + _oc_tail + +#define _osi_call0_w2( type, name, number, type1, retarg1 ) \ +type name( type1 retarg1 ) \ + _oc_head() \ + _oc_syscall( number, rr(r4), rr(r5) ) \ + _oc_input() \ + ((ulong*)retarg1)[0] = __oc_r4; \ + ((ulong*)retarg1)[1] = __oc_r5; \ + _oc_tail + +/* r4-r8 returned in retarg1 pointer */ +#define _osi_call0_w5( type, name, number, type1, retarg1 ) \ +type name( type1 retarg1 ) \ + _oc_head( dreg(r6), dreg(r7), dreg(r8) ) \ + _oc_syscall( number, \ + rr(r4), rr(r5), rr(r6), rr(r7), rr(r8) ) \ + _oc_input() \ + ((ulong*)retarg1)[0] = __oc_r4; \ + ((ulong*)retarg1)[1] = __oc_r5; \ + ((ulong*)retarg1)[2] = __oc_r6; \ + ((ulong*)retarg1)[3] = __oc_r7; \ + ((ulong*)retarg1)[4] = __oc_r8; \ + _oc_tail + +/* r4 returned in retarg pointer */ +#define _osi_call1_w1( type, name, number, t1, a1, t2, retarg ) \ +type name( t1 a1, t2 retarg ) \ + _oc_head( dreg(r6) ) \ + __oc_r6 = (ulong)a1; \ + _oc_syscall( number, rr(r4) ) \ + _oc_input( ir(r6) ) \ + ((ulong*)retarg)[0] = __oc_r4; \ + _oc_tail + +/* r4,r5 returned in retarg1, retarg2 */ +#define _osi_call1_w1w1( type, name, number, t1, a1, t2, retarg1, t3, retarg2 ) \ +type name( t1 a1, t2 retarg1, t3 retarg2 ) \ + _oc_head( dreg(r6) ) \ + __oc_r6 = (ulong)a1; \ + _oc_syscall( number, rr(r4), rr(r5) ) \ + _oc_input( ir(r6) ) \ + ((ulong*)retarg1)[0] = __oc_r4; \ + ((ulong*)retarg2)[0] = __oc_r5; \ + _oc_tail + +/* r4,r5 returned in retarg1, retarg2, retarg3 */ +#define _osi_call1_w1w1w1( type, name, number, t1, a1, t2, retarg1, t3, retarg2, t4, retarg3 ) \ +type name( t1 a1, t2 retarg1, t3 retarg2, t4 retarg3 ) \ + _oc_head( dreg(r6) ) \ + __oc_r6 = (ulong)a1; \ + _oc_syscall( number, rr(r4), rr(r5), rr(r6) ) \ + _oc_input( ir(r6) ) \ + ((ulong*)retarg1)[0] = __oc_r4; \ + ((ulong*)retarg2)[0] = __oc_r5; \ + ((ulong*)retarg3)[0] = __oc_r6; \ + _oc_tail + +/* r4,r5 returned in retarg pointer */ +#define _osi_call1_w2( type, name, number, t1, a1, t2, retarg ) \ +type name( t1 a1, t2 retarg ) \ + _oc_head( dreg(r6) ) \ + __oc_r6 = (ulong)a1; \ + _oc_syscall( number, rr(r4), rr(r5) ) \ + _oc_input( ir(r6) ) \ + ((ulong*)retarg)[0] = __oc_r4; \ + ((ulong*)retarg)[1] = __oc_r5; \ + _oc_tail + +/* r4-r7 returned in retarg pointer */ +#define _osi_call1_w4( type, name, number, t1, a1, t2, retarg ) \ +type name( t1 a1, t2 retarg ) \ + _oc_head( dreg(r6), dreg(r7) ) \ + __oc_r6 = (ulong)a1; \ + _oc_syscall( number, rr(r4), rr(r5), rr(r6), rr(r7) ) \ + _oc_input( ir(r6) ) \ + ((ulong*)retarg)[0] = __oc_r4; \ + ((ulong*)retarg)[1] = __oc_r5; \ + ((ulong*)retarg)[2] = __oc_r6; \ + ((ulong*)retarg)[3] = __oc_r7; \ + _oc_tail + + +/* r4-r5 returned in retarg pointer */ +#define _osi_call2_w2( type, name, number, t1, a1, t2, a2, t3, retarg ) \ +type name( t1 a1, t2 a2, t3 retarg ) \ + _oc_head( dreg(r6), dreg(r7) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + _oc_syscall( number, rr(r4), rr(r5) ) \ + _oc_input( ir(r6), ir(r7) ) \ + ((ulong*)retarg)[0] = __oc_r4; \ + ((ulong*)retarg)[1] = __oc_r5; \ + _oc_tail + +/* r4-r7 returned in retarg pointer */ +#define _osi_call2_w4( type, name, number, t1, a1, t2, a2, t3, retarg ) \ +type name( t1 a1, t2 a2, t3 retarg ) \ + _oc_head( dreg(r6), dreg(r7) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + _oc_syscall( number, rr(r4), rr(r5), rr(r6), rr(r7) ) \ + _oc_input( ir(r6), ir(r7) ) \ + ((ulong*)retarg)[0] = __oc_r4; \ + ((ulong*)retarg)[1] = __oc_r5; \ + ((ulong*)retarg)[2] = __oc_r6; \ + ((ulong*)retarg)[3] = __oc_r7; \ + _oc_tail + +#ifdef SHORT_REGLIST +/* r4-r9 returned in retarg pointer */ +#define _osi_call2_w6( type, name, number, t1, a1, t2, a2, t3, retarg ) \ +type name( t1 a1, t2 a2, t3 retarg ) \ + _oc_head( dreg(r6), dreg(r7), dreg(r10) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + __oc_r10 = (ulong)retarg; \ + _oc_syscall_r10w6( number, ir(r6), ir(r7) ) \ + _oc_tail + +#else /* SHORT_REGLIST */ + +/* r4-r9 returned in retarg pointer */ +#define _osi_call2_w6( type, name, number, t1, a1, t2, a2, t3, retarg ) \ +type name( t1 a1, t2 a2, t3 retarg ) \ + _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9) ) \ + __oc_r6 = (ulong)a1; \ + __oc_r7 = (ulong)a2; \ + _oc_syscall( number, rr(r4), rr(r5), rr(r6), rr(r7), rr(r8), rr(r9) ) \ + _oc_input( ir(r6), ir(r7) ) \ + ((ulong*)retarg)[0] = __oc_r4; \ + ((ulong*)retarg)[1] = __oc_r5; \ + ((ulong*)retarg)[2] = __oc_r6; \ + ((ulong*)retarg)[3] = __oc_r7; \ + ((ulong*)retarg)[4] = __oc_r8; \ + ((ulong*)retarg)[5] = __oc_r9; \ + _oc_tail + +#endif /* SHORT_REGLIST */ + + +/************************************************************************/ +/* OSI call inlines */ +/************************************************************************/ + +static inline _osi_call1( int, OSI_CallAvailable, OSI_CALL_AVAILABLE, int, osi_num ); + +static inline _osi_call1( int, OSI_PutC, OSI_LOG_PUTC, int, ch ); + +static inline _osi_call1( int, OSI_Debugger, OSI_DEBUGGER, int, num ); +static inline _osi_call0( int, OSI_Exit, OSI_EXIT ); + +/* misc */ +static inline _osi_call0( ulong, OSI_GetLocalTime, OSI_GET_LOCALTIME ); +static inline _osi_call0( ulong, OSI_GetGMTTime, OSI_GET_GMT_TIME ); +static inline _osi_call1( int, OSI_USleep, OSI_USLEEP, int, usecs ); + +/* NVRAM */ +static inline _osi_call0( int, OSI_NVRamSize, OSI_NVRAM_SIZE ); +static inline _osi_call1( int, OSI_ReadNVRamByte, OSI_READ_NVRAM_BYTE, int, offs ); +static inline _osi_call2( int, OSI_WriteNVRamByte, OSI_WRITE_NVRAM_BYTE, int, offs, + unsigned char, ch ); + +/* keyboard stuff */ +static inline _osi_call0_w1( int, OSI_GetAdbKey2, OSI_GET_ADB_KEY, int *, raw_key ); +static inline _osi_call1( int, OSI_KbdCntrl, OSI_KBD_CNTRL, int, cmd ); + +static inline int OSI_GetAdbKey( void ) + { int dummy_raw_key; return OSI_GetAdbKey2( &dummy_raw_key ); } +static inline _osi_call2( int, OSI_MapAdbKey, OSI_MAP_ADB_KEY, int, keycode, int, adbkey ) +static inline _osi_call1( int, OSI_KeycodeToAdb, OSI_KEYCODE_TO_ADB, int, keycode ); +static inline _osi_call0( int, OSI_SaveKeymapping, OSI_SAVE_KEYMAPPING ); + +/* mouse support */ +struct osi_mouse; +static inline _osi_call0_w5( int, OSI_GetMouse, OSI_GET_MOUSE, struct osi_mouse *, ret ); +static inline _osi_call0( int, OSI_GetMouseDPI, OSI_GET_MOUSE_DPI ); + +/* video */ +static inline _osi_call2( int, OSI_SetVMode_, OSI_SET_VMODE, int, mode, int, depth_mode ); +struct osi_get_vmode_info; +static inline _osi_call2_w6( int, OSI_GetVModeInfo_, OSI_GET_VMODE_INFO, int, mode, int, depth_mode, + struct osi_get_vmode_info *, ret ); +static inline _osi_call1( int, OSI_SetVPowerState, OSI_SET_VIDEO_POWER, int, power_state ); +static inline _osi_call2( int, OSI_SetColor, OSI_SET_COLOR, int, index, int, rgb ); +static inline _osi_call0_w1( int, OSI_VideoAckIRQ, OSI_VIDEO_ACK_IRQ, int *, events ); + +static inline void OSI_RefreshPalette( void ) { OSI_SetColor(-1,0); } + +/* PIC (mac-io replacement) */ +static inline _osi_call1( int, OSI_PICMaskIRQ, OSI_PIC_MASK_IRQ, int, irq ); +static inline _osi_call1( int, OSI_PICUnmaskIRQ, OSI_PIC_UNMASK_IRQ, int, irq ); +static inline _osi_call2( int, OSI_PICAckIRQ, OSI_PIC_ACK_IRQ, int, irq, int, mask_it ); +static inline _osi_call0( int, OSI_PICGetActiveIRQ, OSI_PIC_GET_ACTIVE_IRQ ); + +/* sound */ +static inline _osi_call1( int, OSI_SoundCntl, OSI_SOUND_CNTL, int, cmd ); +static inline _osi_call2( int, OSI_SoundCntl1, OSI_SOUND_CNTL, int, cmd, int, p1 ); +static inline _osi_call3( int, OSI_SoundCntl2, OSI_SOUND_CNTL, int, cmd, int, p1, int, p2 ); +static inline _osi_call0_w2( int, OSI_SoundIRQAck, OSI_SOUND_IRQ_ACK, ulong *, timestamp ); +static inline _osi_call3( int, OSI_SoundWrite, OSI_SOUND_WRITE, int, physbuf, int, len, int, restart ); +static inline _osi_call3( int, OSI_SoundSetVolume, OSI_SOUND_SET_VOLUME, int, hwvol, int, speakervol, int, mute ); + +/* async block driver */ +struct ablk_disk_info; +static inline _osi_call2_w4( int, OSI_ABlkDiskInfo, OSI_ABLK_DISK_INFO, int, channel, int, unit, + struct ablk_disk_info *, retinfo ); +static inline _osi_call1( int, OSI_ABlkKick, OSI_ABLK_KICK, int, channel ); +static inline _osi_call1_w1w1w1( int, OSI_ABlkIRQAck, OSI_ABLK_IRQ_ACK, int, channel, int *, req_count, + int *, active, int *, events ); +static inline _osi_call3( int, OSI_ABlkRingSetup, OSI_ABLK_RING_SETUP, int, channel, int, mphys, int, n_el ); +static inline _osi_call2( int, OSI_ABlkCntrl, OSI_ABLK_CNTRL, int, channel, int, cmd ); +static inline _osi_call3( int, OSI_ABlkCntrl1, OSI_ABLK_CNTRL, int, channel, int, cmd, int, param ); +static inline _osi_call5( int, OSI_ABlkSyncRead, OSI_ABLK_SYNC_READ, int, channel, int, unit, + int, blk, ulong, mphys, int, size ); +static inline _osi_call5( int, OSI_ABlkSyncWrite, OSI_ABLK_SYNC_WRITE, int, channel, int, unit, + int, blk, ulong, mphys, int, size ); +static inline _osi_call2( int, OSI_ABlkBlessDisk, OSI_ABLK_BLESS_DISK, int, channel, int, unit ); + +static inline _osi_call0( int, OSI_CMountDrvVol, OSI_CMOUNT_DRV_VOL ); + +/* enet2 */ +static inline _osi_call0( int, OSI_Enet2Open, OSI_ENET2_OPEN ); +static inline _osi_call0( int, OSI_Enet2Close, OSI_ENET2_CLOSE ); +static inline _osi_call3( int, OSI_Enet2RingSetup, OSI_ENET2_RING_SETUP, int, which_ring, + int, ring_mphys, int, n_el ); +static inline _osi_call2( int, OSI_Enet2Cntrl1, OSI_ENET2_CNTRL, int, cmd, int, param ); +static inline _osi_call1( int, OSI_Enet2Cntrl, OSI_ENET2_CNTRL, int, cmd ); +static inline _osi_call0( int, OSI_Enet2Kick, OSI_ENET2_KICK ); + +static inline _osi_call0_w2( int, OSI_Enet2GetHWAddr__, OSI_ENET2_GET_HWADDR, ulong *, retbuf ); +static inline int OSI_Enet2GetHWAddr( unsigned char *addr ) { + int ret; + ulong buf[2]; + + ret = OSI_Enet2GetHWAddr__( buf ); + + ((ulong*)addr)[0] = buf[0]; + ((ushort*)addr)[2] = (buf[1] >> 16); + return ret; +} +static inline _osi_call2( int, OSI_Enet2IRQAck, OSI_ENET2_IRQ_ACK, int, irq_enable, int, rx_head ); + +/* PROM (device-tree) */ +static inline _osi_call2( int, OSI_PromIface, OSI_PROM_IFACE, int, what, int, ph ); +static inline _osi_call3( int, OSI_PromIface1, OSI_PROM_IFACE, int, what, int, ph, int, p1 ); +static inline _osi_call4( int, OSI_PromIface2, OSI_PROM_IFACE, int, what, int, ph, int, p1, int, p2 ); +static inline _osi_call5( int, OSI_PromIface3, OSI_PROM_IFACE, int, what, int, ph, int, p1, int, p2, int, p3 ); +static inline _osi_call2( int, OSI_PromPathIface, OSI_PROM_PATH_IFACE, int, what, const char *, p ); + +/* emulation acceleration */ +static inline _osi_call1( int, OSI_MapinMregs, OSI_MAPIN_MREGS, ulong, mphys ); +static inline _osi_call3( int, OSI_EmuAccel, OSI_EMUACCEL, int, emuaccel_flags, int, param, int, inst_addr ); + +/* timer frequency */ +static inline _osi_call1( int, OSI_MticksToUsecs, OSI_MTICKS_TO_USECS, ulong, mticks ); +static inline _osi_call1( int, OSI_UsecsToMticks, OSI_USECS_TO_MTICKS, ulong, usecs ); + +/* fb info */ +struct osi_fb_info; +static inline _osi_call0_w5( int, OSI_GetFBInfo, OSI_GET_FB_INFO, struct osi_fb_info *, retinfo ); + +/* SCSI */ +static inline _osi_call0( int, OSI_SCSIAck, OSI_SCSI_ACK ); +static inline _osi_call1( int, OSI_SCSISubmit, OSI_SCSI_SUBMIT, int, req_mphys ); +static inline _osi_call2( int, OSI_SCSIControl, OSI_SCSI_CNTRL, int, sel, int, param ); + +/* TTY */ +static inline _osi_call0( int, OSI_TTYGetc, OSI_TTY_GETC ); +static inline _osi_call1( int, OSI_TTYPutc, OSI_TTY_PUTC, int, ch ); +static inline _osi_call0( int, OSI_TTYIRQAck, OSI_TTY_IRQ_ACK ); + +#endif /* _H_OSI_CALLS */ diff --git a/arch/ppc/pearpc/console.c b/arch/ppc/pearpc/console.c new file mode 100644 index 0000000..24b82a9 --- /dev/null +++ b/arch/ppc/pearpc/console.c @@ -0,0 +1,47 @@ + +/* + * + * + * Simple text console + * + * Copyright (C) 2005 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/diskio.h" +#include "ofmem.h" +#include "pearpc/pearpc.h" + + +typedef struct osi_fb_info { + unsigned long mphys; + int rb, w, h, depth; +} osi_fb_info_t; + + +int PearPC_GetFBInfo( osi_fb_info_t *fb ) +{ + + fb->w=1024; + fb->h=768; + fb->depth=15; + fb->rb=2048; + fb->mphys=0x84000000; + + return 0; +} + +#define openbios_GetFBInfo(x) PearPC_GetFBInfo(x) + +#include "../../../modules/video.c" + +#include "../../../modules/console.c" + + + diff --git a/arch/ppc/pearpc/init.c b/arch/ppc/pearpc/init.c new file mode 100644 index 0000000..b8ca34c --- /dev/null +++ b/arch/ppc/pearpc/init.c @@ -0,0 +1,137 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Initialization for pearpc + * + * Copyright (C) 2004 Greg Watson + * Copyright (C) 2005 Stefan Reinauer + * + * based on mol/init.c: + * + * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel & David Rydh + * (samuel@ibrium.se, dary@lindesign.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/nvram.h" +#include "pearpc/pearpc.h" +#include "ofmem.h" +#include "openbios-version.h" + +extern void unexpected_excep( int vector ); +extern void ob_ide_init( void ); +extern void ob_pci_init( void ); +extern void ob_adb_init( void ); +extern void setup_timers( void ); + +#if 0 +int +get_bool_res( const char *res ) +{ + char buf[8], *p; + + p = BootHGetStrRes( res, buf, sizeof(buf) ); + if( !p ) + return -1; + if( !strcasecmp(p,"true") || !strcasecmp(p,"yes") || !strcasecmp(p,"1") ) + return 1; + return 0; +} +#endif + +void +unexpected_excep( int vector ) +{ + printk("openbios panic: Unexpected exception %x\n", vector ); + for( ;; ) + ; +} + +void +entry( void ) +{ + printk("\n"); + printk("=============================================================\n"); + printk("OpenBIOS %s [%s]\n", OPENBIOS_RELEASE, OPENBIOS_BUILD_DATE ); + + ofmem_init(); + initialize_forth(); + /* won't return */ + + printk("of_startup returned!\n"); + for( ;; ) + ; +} + +static void +setenv( char *env, char *value ) +{ + push_str( value ); + push_str( env ); + fword("$setenv"); +} + +void +arch_of_init( void ) +{ +#if USE_RTAS + phandle_t ph; +#endif + int autoboot; + + devtree_init(); + nvram_init(); + modules_init(); +#ifdef CONFIG_DRIVER_PCI + ob_pci_init(); +#endif +#ifdef CONFIG_DRIVER_IDE + setup_timers(); + ob_ide_init(); +#endif +#ifdef CONFIG_DRIVER_ADB + ob_adb_init(); +#endif + + node_methods_init(); + init_video(); + +#if USE_RTAS + if( !(ph=find_dev("/rtas")) ) + printk("Warning: No /rtas node\n"); + else { + ulong size = 0x1000; + while( size < (ulong)of_rtas_end - (ulong)of_rtas_start ) + size *= 2; + set_property( ph, "rtas-size", (char*)&size, sizeof(size) ); + } +#endif + +#if 0 + /* tweak boot settings */ + autoboot = !!get_bool_res("autoboot"); +#endif + autoboot = 0; + if( !autoboot ) + printk("Autobooting disabled - dropping into OpenFirmware\n"); + setenv("auto-boot?", autoboot ? "true" : "false" ); + setenv("boot-command", "pearpcboot"); + +#if 0 + if( get_bool_res("tty-interface") == 1 ) +#endif + fword("activate-tty-interface"); + + /* hack */ + device_end(); + bind_func("pearpcboot", boot ); +} diff --git a/arch/ppc/pearpc/kernel.c b/arch/ppc/pearpc/kernel.c new file mode 100644 index 0000000..883813e --- /dev/null +++ b/arch/ppc/pearpc/kernel.c @@ -0,0 +1,17 @@ +/* + * Creation Date: <2004/08/28 18:03:25 stepan> + * Time-stamp: <2004/08/28 18:03:25 stepan> + * + * + * + * Copyright (C) 2005 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "pearpc-dict.h" +#include "../kernel.c" + diff --git a/arch/ppc/pearpc/main.c b/arch/ppc/pearpc/main.c new file mode 100644 index 0000000..960e0ef --- /dev/null +++ b/arch/ppc/pearpc/main.c @@ -0,0 +1,145 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Copyright (C) 2004 Greg Watson + * + * Based on MOL specific code which is + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/elfload.h" +#include "openbios/nvram.h" +#include "libc/diskio.h" +#include "libc/vsprintf.h" +#include "pearpc/pearpc.h" +#include "ofmem.h" + +static void +transfer_control_to_elf( ulong entry ) +{ + extern void call_elf( ulong entry ); + printk("Starting ELF image at 0x%08lX\n", entry); + call_elf( 0x400000 ); + //call_elf( entry ); + + fatal_error("call_elf returned unexpectedly\n"); +} + +static int +load_elf_rom( ulong *entry, int fd ) +{ + int i, lszz_offs, elf_offs; + char buf[128], *addr; + Elf_ehdr ehdr; + Elf_phdr *phdr; + size_t s; + + printk("Loading '%s'\n", get_file_path(fd)); + + /* the ELF-image (usually) starts at offset 0x4000 */ + if( (elf_offs=find_elf(fd)) < 0 ) { + printk("----> %s is not an ELF image\n", buf ); + exit(1); + } + if( !(phdr=elf_readhdrs(fd, elf_offs, &ehdr)) ) + fatal_error("elf_readhdrs failed\n"); + + *entry = ehdr.e_entry; + + /* load segments. Compressed ROM-image assumed to be located immediately + * after the last segment */ + lszz_offs = elf_offs; + for( i=0; i= phdr[i].p_vaddr && *entry < phdr[i].p_vaddr + s ) { + patch_newworld_rom( (char*)phdr[i].p_vaddr, s ); + newworld_timer_hack( (char*)phdr[i].p_vaddr, s ); + } +#endif + flush_icache_range( addr, addr+s ); + + /*printk("ELF ROM-section loaded at %08lX (size %08lX)\n", + (ulong)phdr[i].p_vaddr, (ulong)phdr[i].p_memsz );*/ + } + free( phdr ); + return lszz_offs; +} + + +static void +encode_bootpath( const char *spec, const char *args ) +{ + phandle_t chosen_ph = find_dev("/chosen"); + set_property( chosen_ph, "bootpath", spec, strlen(spec)+1 ); + set_property( chosen_ph, "bootargs", args, strlen(args)+1 ); +} + +/************************************************************************/ +/* pearpc booting */ +/************************************************************************/ + +static void +pearpc_startup( void ) +{ + const char *paths[] = { "hd:0,\\zImage.chrp", NULL }; + const char *args[] = { "root=/dev/hda2 console=ttyS0,115200", NULL }; + ulong entry; + int i, fd; + + for( i=0; paths[i]; i++ ) { + if( (fd=open_io(paths[i])) == -1 ) + continue; + (void) load_elf_rom( &entry, fd ); + close_io( fd ); + encode_bootpath( paths[i], args[i] ); + + update_nvram(); + transfer_control_to_elf( entry ); + /* won't come here */ + } + printk("*** Boot failure! No secondary bootloader specified ***\n"); +} + + +/************************************************************************/ +/* entry */ +/************************************************************************/ + +void +boot( void ) +{ + fword("update-chosen"); + pearpc_startup(); +} diff --git a/arch/ppc/pearpc/methods.c b/arch/ppc/pearpc/methods.c new file mode 100644 index 0000000..01724f9 --- /dev/null +++ b/arch/ppc/pearpc/methods.c @@ -0,0 +1,335 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Misc device node methods + * + * Copyright (C) 2004 Greg Watson + * + * Based on MOL specific code which is + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/string.h" +#include "pearpc/pearpc.h" +#include "ofmem.h" + +/************************************************************************/ +/* RTAS (run-time abstraction services) */ +/************************************************************************/ + +#ifdef USE_RTAS +DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" ); + +/* ( physbase -- rtas_callback ) */ +static void +rtas_instantiate( void ) +{ + int physbase = POP(); + int s=0x1000, size = (int)of_rtas_end - (int)of_rtas_start; + ulong virt; + + while( s < size ) + s += 0x1000; + virt = ofmem_claim_virt( 0, s, 0x1000 ); + ofmem_map( physbase, virt, s, -1 ); + memcpy( (char*)virt, of_rtas_start, size ); + + printk("RTAS instantiated at %08x\n", physbase ); + flush_icache_range( (char*)virt, (char*)virt + size ); + + PUSH( physbase ); +} + +NODE_METHODS( rtas ) = { + { "instantiate", rtas_instantiate }, + { "instantiate-rtas", rtas_instantiate }, +}; +#endif + + +/************************************************************************/ +/* stdout */ +/************************************************************************/ + +DECLARE_NODE( video_stdout, INSTALL_OPEN, 0, "Tdisplay" ); + +/* ( addr len -- actual ) */ +static void +stdout_write( void ) +{ + int len = POP(); + char *addr = (char*)POP(); + char *s = malloc( len + 1 ); + + strncpy_nopad( s, addr, len ); + s[len]=0; + + printk( "%s", s ); + //vfd_draw_str( s ); + console_draw_str( s ); + + free( s ); + + PUSH( len ); +} + +NODE_METHODS( video_stdout ) = { + { "write", stdout_write }, +}; + + +/************************************************************************/ +/* tty */ +/************************************************************************/ + +DECLARE_NODE( tty, INSTALL_OPEN, 0, "/packages/terminal-emulator" ); + +/* ( addr len -- actual ) */ +static void +tty_read( void ) +{ + int ch, len = POP(); + char *p = (char*)POP(); + int ret=0; + + if( len > 0 ) { + ret = 1; + ch = getchar(); + if( ch >= 0 ) { + *p = ch; + } else { + ret = 0; + } + } + PUSH( ret ); +} + +/* ( addr len -- actual ) */ +static void +tty_write( void ) +{ + int i, len = POP(); + char *p = (char*)POP(); + for( i=0; i + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Copyright (C) 2004, Greg Watson + * + * derived from mol.c + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/nvram.h" +#include "libc/vsprintf.h" +#include "libc/string.h" +#include "pearpc/pearpc.h" +#include + +#define UART_BASE 0x3f8 + +// FIXME +unsigned long virt_offset = 0; + + +void +exit( int status ) +{ + for (;;); +} + +void +fatal_error( const char *err ) +{ + printk("Fatal error: %s\n", err ); + exit(0); +} + +void +panic( const char *err ) +{ + printk("Panic: %s\n", err ); + exit(0); + + /* won't come here... this keeps the gcc happy */ + for( ;; ) + ; +} + + +/************************************************************************/ +/* print using OSI interface */ +/************************************************************************/ + +static int do_indent; + +int +printk( const char *fmt, ... ) +{ + char *p, buf[1024]; /* XXX: no buffer overflow protection... */ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + + for( p=buf; *p; p++ ) { + if( *p == '\n' ) + do_indent = 0; + if( do_indent++ == 1 ) { + putchar( '>' ); + putchar( '>' ); + putchar( ' ' ); + } + putchar( *p ); + } + return i; +} + + +/************************************************************************/ +/* TTY iface */ +/************************************************************************/ + +static int ttychar = -1; + +static int +tty_avail( void ) +{ + return 1; +} + +static int +tty_putchar( int c ) +{ + if( tty_avail() ) { + while (!(inb(UART_BASE + 0x05) & 0x20)) + ; + outb(c, UART_BASE); + while (!(inb(UART_BASE + 0x05) & 0x40)) + ; + } + return c; +} + +int +availchar( void ) +{ + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + ttychar = inb(UART_BASE); + return (ttychar >= 0); +} + +int +getchar( void ) +{ + int ch; + + if( !tty_avail() ) + return 0; + + if( ttychar < 0 ) + return inb(UART_BASE); + ch = ttychar; + ttychar = -1; + return ch; +} + +int +putchar( int c ) +{ + if (c == '\n') + tty_putchar('\r'); + return tty_putchar(c); +} + + +/************************************************************************/ +/* briQ specific stuff */ +/************************************************************************/ + +#define IO_NVRAM_PA_START 0x80860000 +#define IO_NVRAM_PA_END 0x80880000 + +static char *nvram=(char *)IO_NVRAM_PA_START; + +void +dump_nvram(void) +{ + static char hexdigit[] = "0123456789abcdef"; + int i; + for (i = 0; i < 16*4; i++) + { + printk ("%c", hexdigit[nvram[i<<4] >> 4]); + printk ("%c", hexdigit[nvram[i<<4] % 16]); + if (!((i + 1) % 16)) + { + printk ("\n"); + } + else + { + printk (" "); + } + } +} + + +int +arch_nvram_size( void ) +{ + return (IO_NVRAM_PA_END-IO_NVRAM_PA_START)>>4; +} + +void +arch_nvram_put( char *buf ) +{ + int i; + for (i=0; i<(IO_NVRAM_PA_END-IO_NVRAM_PA_START)>>4; i++) + nvram[i<<4]=buf[i]; + // memcpy(nvram, buf, IO_NVRAM_PA_END-IO_NVRAM_PA_START); + printk("new nvram:\n"); + dump_nvram(); +} + +void +arch_nvram_get( char *buf ) +{ + int i; + for (i=0; i<(IO_NVRAM_PA_END-IO_NVRAM_PA_START)>>4; i++) + buf[i]=nvram[i<<4]; + + //memcpy(buf, nvram, IO_NVRAM_PA_END-IO_NVRAM_PA_START); + printk("current nvram:\n"); + dump_nvram(); +} diff --git a/arch/ppc/pearpc/pearpc.fs b/arch/ppc/pearpc/pearpc.fs new file mode 100644 index 0000000..0d018b1 --- /dev/null +++ b/arch/ppc/pearpc/pearpc.fs @@ -0,0 +1,116 @@ +\ pearpc specific initialization code +\ +\ Copyright (C) 2005 Stefan Reinauer +\ +\ This program is free software; you can redistribute it and/or +\ modify it under the terms of the GNU General Public License +\ as published by the Free Software Foundation +\ + + +\ ------------------------------------------------------------------------- +\ initialization +\ ------------------------------------------------------------------------- + +: make-openable ( path ) + find-dev if + begin ?dup while + \ install trivial open and close methods + dup active-package! is-open + parent + repeat + then +; + +: preopen ( chosen-str node-path ) + 2dup make-openable + + " /chosen" find-device + open-dev ?dup if + encode-int 2swap property + else + 2drop + then +; + +\ preopen device nodes (and store the ihandles under /chosen) +:noname + " rtc" " /pci/isa/rtc" preopen + " memory" " /memory" preopen + " mmu" " /cpu@0" preopen + \ " stdout" " /packages/terminal-emulator" preopen + " stdout" " /pci/pci6666,6666" preopen + " stdin" " /pci/via-cuda/adb" preopen + +; SYSTEM-initializer + + +\ ------------------------------------------------------------------------- +\ device tree fixing +\ ------------------------------------------------------------------------- + +\ add decode-address methods +: (make-decodable) ( phandle -- ) + + dup " #address-cells" rot get-package-property 0= if + decode-int nip nip + over " decode-unit" rot find-method if 2drop else + ( save phandle ncells ) + + over active-package! + case + 1 of ['] parse-hex " decode-unit" is-xt-func endof + 3 of + " bus-range" active-package get-package-property 0= if + decode-int nip nip + ['] encode-unit-pci " encode-unit" is-xt-func + " decode-unit" is-func-begin + ['] (lit) , , + ['] decode-unit-pci-bus , + is-func-end + then + endof + endcase + then + then + drop +; + +: init-pearpc-tree ( -- ) + active-package + + iterate-tree-begin + begin ?dup while + + dup (make-decodable) + + iterate-tree + repeat + + active-package! +; + +\ use the tty interface if available +: activate-tty-interface + " /packages/terminal-emulator" find-dev if drop + " /pci/via-cuda/adb" " input-device" $setenv + " /pci/pci6666,6666" " output-device" $setenv + then +; + +:noname + " keyboard" input +; CONSOLE-IN-initializer + + +\ ------------------------------------------------------------------------- +\ pre-booting +\ ------------------------------------------------------------------------- + +: update-chosen + " /chosen" find-device + stdin @ encode-int " stdin" property + stdout @ encode-int " stdout" property + " /pci/isa/interrupt-controller" find-dev if encode-int " interrupt-controller" property then + device-end +; diff --git a/arch/ppc/pearpc/pearpc.h b/arch/ppc/pearpc/pearpc.h new file mode 100644 index 0000000..d3d6c5c --- /dev/null +++ b/arch/ppc/pearpc/pearpc.h @@ -0,0 +1,26 @@ +/* + * Creation Date: <2004/08/28 17:50:12 stepan> + * Time-stamp: <2004/08/28 17:50:12 stepan> + * + * + * + * Copyright (C) 2005 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_PEARPC +#define _H_PEARPC + +/* vfd.c */ +extern int vfd_draw_str( const char *str ); +extern void vfd_close( void ); + +extern int console_draw_str( const char *str ); + +#include "kernel.h" + +#endif /* _H_PEARPC */ diff --git a/arch/ppc/pearpc/tree.c b/arch/ppc/pearpc/tree.c new file mode 100644 index 0000000..8653de8 --- /dev/null +++ b/arch/ppc/pearpc/tree.c @@ -0,0 +1,23 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * device tree setup + * + * Copyright (C) 2004 Greg Watson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" + +void devtree_init( void ) +{ + fword("init-pearpc-tree"); +} diff --git a/arch/ppc/pearpc/tree.fs b/arch/ppc/pearpc/tree.fs new file mode 100644 index 0000000..52fd56a --- /dev/null +++ b/arch/ppc/pearpc/tree.fs @@ -0,0 +1,247 @@ +\ PearPC specific initialization code +\ +\ Copyright (C) 2005 Stefan Reinauer +\ +\ This program is free software; you can redistribute it and/or +\ modify it under the terms of the GNU General Public License +\ as published by the Free Software Foundation +\ + +\ ------------------------------------------------------------- +\ device-tree +\ ------------------------------------------------------------- + +" /" find-device + +" chrp" device-type +" OpenSource,PEARPC" model +h# 80000000 encode-int " isa-io-base" property +1 encode-int " #interrupt-cells" property +1 encode-int " #size-cells" property + +new-device + " memory" device-name + " memory" device-type + 0 encode-int h# 1E00000 encode-int encode+ + h# 2000000 encode-int encode+ h# 40000000 encode-int encode+ + " available" property + 0 h# 40000000 reg + external + : open true ; + : close ; +finish-device + +new-device + " cpu" device-name + " cpu" device-type + " " encode-string " translations" property + 0 encode-phys h# 8000000 encode-int encode+ " available" property + d# 32 encode-int " d-cache-block-size" property + 8 encode-int " d-cache-sets" property + d# 32768 encode-int " d-cache-size" property + d# 32 encode-int " i-cache-block-size" property + 8 encode-int " i-cache-sets" property + d# 32768 encode-int " i-cache-size" property + " " encode-string " cache-unified" property + 2 encode-int " i-tlb-sets" property + d# 128 encode-int " i-tlb-size" property + 2 encode-int " d-tlb-sets" property + d# 128 encode-int " d-tlb-size" property + " " encode-string " tlb-split" property + 2 encode-int " tlb-sets" property + d# 256 encode-int " tlb-size" property + " " encode-string " performance-monitor" property + " " encode-string " graphics" property + 4 encode-int " reservation-granule-size" property + d# 25000000 encode-int " timebase-frequency" property + d# 300000000 encode-int " clock-frequency" property + d# 66000000 encode-int " bus-frequency" property + h# 88201 encode-int " cpu-version" property + 0 encode-int " reg" property +finish-device + +" /pci" find-device + h# 01000000 encode-int 0 encode-int encode+ 0 encode-int encode+ + h# 80000000 encode-int encode+ 0 encode-int encode+ + h# 01000000 encode-int encode+ + h# 02000000 encode-int encode+ 0 encode-int encode+ 0 encode-int encode+ + h# C0000000 encode-int encode+ 0 encode-int encode+ + h# 08000000 encode-int encode+ + " ranges" property + " IBM,CPC710" model + h# FF5F7700 encode-int " 8259-interrupt-acknowledge" property + h# 0000F800 encode-int 0 encode-int encode+ 0 encode-int encode+ + 7 encode-int encode+ + " interrupt-map-mask" property + 1 encode-int " #interrupt-cells" property + h# 80000000 encode-int " system-dma-base" property + d# 33333333 encode-int " clock-frequency" property + " " encode-string " primary-bridge" property + 0 encode-int " pci-bridge-number" property + h# FEC00000 encode-int h# 100000 encode-int encode+ " reg" property + 0 encode-int 0 encode-int encode+ " bus-range" property + +new-device + " ide" device-name + " ide" device-type + " WINBOND,82C553" model + h# 28 encode-int " max-latency" property + h# 2 encode-int " min-grant" property + h# 1 encode-int " devsel-speed" property + h# 0 encode-int " subsystem-vendor-id" property + h# 0 encode-int " subsystem-id" property + h# 1018A encode-int " class-code" property + h# 5 encode-int " revision-id" property + h# 105 encode-int " device-id" property + h# 10AD encode-int " vendor-id" property + h# 1003110 encode-int 0 encode-int encode+ h# 10020 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003114 encode-int 0 encode-int encode+ h# 10030 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003118 encode-int 0 encode-int encode+ h# 10040 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 100311C encode-int 0 encode-int encode+ h# 10034 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003120 encode-int 0 encode-int encode+ h# 10050 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003124 encode-int 0 encode-int encode+ h# 10060 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + " assigned-addresses" property + h# 3100 encode-int 0 encode-int encode+ 0 encode-int encode+ + 0 encode-int encode+ 0 encode-int encode+ + h# 1003110 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003114 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003118 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 100311C encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 4 encode-int encode+ 0 encode-int encode+ + h# 1003120 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + h# 1003124 encode-int 0 encode-int encode+ h# 0 encode-int encode+ + h# 10 encode-int encode+ 0 encode-int encode+ + " reg" property +finish-device + +new-device + " ethernet" device-name + " network" device-type + " AMD,79C973" model + h# 3800 encode-int 0 encode-int encode+ 0 encode-int encode+ + 0 encode-int encode+ 0 encode-int encode+ + " reg" property +finish-device + +" /pci/isa" find-device + 0 0 " assigned-addresses" property + 0 0 " ranges" property + 0 encode-int " slot-names" property + d# 8333333 encode-int " clock-frequency" property + 0 encode-int " eisa-slots" property + 2 encode-int " #interrupt-cells" property + " W83C553F" encode-string " compatible" property + " WINBOND,82C553" model + 0 encode-int " max-latency" property + 0 encode-int " min-grant" property + 1 encode-int " devsel-speed" property + 0 encode-int " subsystem-vendor-id" property + 0 encode-int " subsystem-id" property + h# 60100 encode-int " class-code" property + h# 10 encode-int " revision-id" property + h# 565 encode-int " device-id" property + h# 10AD encode-int " vendor-id" property + h# 3000 encode-int 0 encode-int encode+ 0 encode-int encode+ + 0 encode-int encode+ 0 encode-int encode+ " reg" property + +new-device + " rtc" device-name + " rtc" device-type + " DS17285S" model + " MC146818" encode-string + " DS17285S" encode-string encode+ + " pnpPNP,b00" encode-string encode+ " compatible" property + 8 encode-int 0 encode-int encode+ " interrupts" property + h# 70 encode-int 1 encode-int encode+ + 2 encode-int encode+ " reg" property +finish-device + +new-device + " interrupt-controller" device-name + " interrupt-controller" device-type + " 8259" model + " " encode-string " interrupt-controller" property + 2 encode-int " #interrupt-cells" property + 1 encode-int + 2 encode-int encode+ + 3 encode-int encode+ + 6 encode-int encode+ + " reserved-interrupts" property + " 8259" encode-string + " chrp,iic" encode-string encode+ + " compatible" property + h# 20 encode-int 1 encode-int encode+ + 2 encode-int encode+ " reg" property +finish-device + +new-device + " serial" device-name + " serial" device-type + " no" encode-string " ctsrts" property + " no" encode-string " xon" property + " no" encode-string " parity" property + d# 115200 encode-int " bps" property + 1 encode-int " stop-bits" property + 8 encode-int " data-bits" property + h# 70800 encode-int " divisor" property + h# 708000 encode-int " clock-frequency" property + 4 encode-int 0 encode-int encode+ " interrupts" property + h# 3F8 encode-int 1 encode-int encode+ + 8 encode-int encode+ " reg" property +finish-device + +" /pci" find-device + " /pci/isa/interrupt-controller" find-dev if + encode-int " interrupt-parent" property + then + h# 3800 encode-int 0 encode-int encode+ + 0 encode-int encode+ 1 encode-int encode+ + " /pci/isa/interrupt-controller" find-dev if + encode-int encode+ + then + h# 0C encode-int encode+ 1 encode-int encode+ + " interrupt-map" property + +" /pci/isa" find-device + " /pci/isa/interrupt-controller" find-dev if + encode-int " interrupt-parent" property + then + +\ ------------------------------------------------------------- +\ /packages +\ ------------------------------------------------------------- + +" /packages" find-device + + " packages" device-name + external + \ allow packages to be opened with open-dev + : open true ; + : close ; + +\ /packages/terminal-emulator +new-device + " terminal-emulator" device-name + external + : open true ; + : close ; + \ : write ( addr len -- actual ) + \ dup -rot type + \ ; +finish-device + +\ ------------------------------------------------------------- +\ The END +\ ------------------------------------------------------------- +device-end + diff --git a/arch/ppc/pearpc/vfd.c b/arch/ppc/pearpc/vfd.c new file mode 100644 index 0000000..bb27cf1 --- /dev/null +++ b/arch/ppc/pearpc/vfd.c @@ -0,0 +1,42 @@ +/* + * Creation Date: <2004/08/28 17:29:43 greg> + * Time-stamp: <2004/08/28 17:29:43 greg> + * + * + * + * Simple text console + * + * Copyright (C) 2004 Greg Watson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "pearpc/pearpc.h" + +static int vfd_is_open; + +static int +vfd_init( void ) +{ + vfd_is_open = 1; + return 0; +} + +void +vfd_close( void ) +{ +} + +int +vfd_draw_str( const char *str ) +{ + if (!vfd_is_open) + vfd_init(); + + return 0; +} diff --git a/arch/ppc/ppc.fs b/arch/ppc/ppc.fs new file mode 100644 index 0000000..ae1f640 --- /dev/null +++ b/arch/ppc/ppc.fs @@ -0,0 +1,47 @@ + +0 value %cr +0 value %ctr +0 value %lr +0 value %msr +0 value %srr0 +0 value %srr1 +0 value %pc \ should be an alias for %srr0 + +0 value %r0 +0 value %r1 +0 value %r2 +0 value %r3 +0 value %r4 +0 value %r5 +0 value %r6 +0 value %r7 +0 value %r8 +0 value %r9 +0 value %r10 +0 value %r11 +0 value %r12 +0 value %r13 +0 value %r14 +0 value %r15 +0 value %r16 +0 value %r17 +0 value %r18 +0 value %r19 +0 value %r20 +0 value %r21 +0 value %r22 +0 value %r23 +0 value %r24 +0 value %r25 +0 value %r26 +0 value %r27 +0 value %r28 +0 value %r29 +0 value %r30 +0 value %r31 + +0 value %xer +0 value %sprg0 +0 value %sprg1 +0 value %sprg2 +0 value %sprg3 diff --git a/arch/ppc/start.S b/arch/ppc/start.S new file mode 100644 index 0000000..054b7f0 --- /dev/null +++ b/arch/ppc/start.S @@ -0,0 +1,324 @@ +/* + * Creation Date: <2001/06/16 21:30:18 samuel> + * Time-stamp: <2003/04/04 16:32:06 samuel> + * + * + * + * Asm glue for ELF images run inside MOL + * + * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +changequote([[[[[,]]]]]) [[[[[ /* shield includes from m4-expansion */ +#include "asm/asmdefs.h" +#include "asm/processor.h" +#include "osi.h" + +/************************************************************************/ +/* Macros */ +/************************************************************************/ + +#define ILLEGAL_VECTOR( v ) .org __vectors + v ; bl trap_error ; +#define VECTOR( v, dummystr ) .org __vectors + v ; vector__##v + +MACRO(EXCEPTION_PREAMBLE, [ + mtsprg1 r1 // scratch + mfsprg0 r1 // exception stack in sprg0 + addi r1,r1,-80 // push exception frame + + stw r0,0(r1) // save r0 + mfsprg1 r0 + stw r0,4(r1) // save r1 + stw r2,8(r1) // save r2 + stw r3,12(r1) // save r3 + stw r4,16(r1) + stw r5,20(r1) + stw r6,24(r1) + stw r7,28(r1) + stw r8,32(r1) + stw r9,36(r1) + stw r10,40(r1) + stw r11,44(r1) + stw r12,48(r1) + + mflr r0 + stw r0,52(r1) + mfcr r0 + stw r0,56(r1) + mfctr r0 + stw r0,60(r1) + mfxer r0 + stw r0,64(r1) + + // 76(r1) unused + addi r1,r1,-16 // call conventions uses 0(r1) and 4(r1)... +]) + + +/************************************************************************/ +/* stack space */ +/************************************************************************/ + + .section .bss + .balign 32 + .space 32*1024 // 32 K client stack +client_stack: + .space 128 + + .space 64*1024 // 64 K stack +stack: .space 64 + + .space 32*1024 // 32 K exception stack +estack: .space 128 + + +/************************************************************************/ +/* entry */ +/************************************************************************/ + + .text +GLOBL(_start): + li r0,0 + mtmsr r0 + + LOADI r1,estack + mtsprg0 r1 // setup exception stack + LOADI r1,stack + + // copy exception vectors + LOADI r3,__vectors + li r4,0 + li r5,__vectors_end - __vectors + 16 + rlwinm r5,r5,0,0,28 +1: lwz r6,0(r3) + lwz r7,4(r3) + lwz r8,8(r3) + lwz r9,12(r3) + stw r6,0(r4) + stw r7,4(r4) + stw r8,8(r4) + stw r9,12(r4) + dcbst 0,r4 + sync + icbi 0,r4 + sync + addi r5,r5,-16 + addi r3,r3,16 + addi r4,r4,16 + cmpwi r5,0 + bgt 1b + isync + + bl setup_mmu + bl entry +1: nop + b 1b + + + /* According to IEEE 1275, PPC bindings: + * + * MSR = FP, ME + (DR|IR) + * r1 = stack (32 K + 32 bytes link area above) + * r5 = clint interface handler + * r6 = address of client program arguments (unused) + * r7 = length of client program arguments (unsed) + */ +saved_stack: + .long 0 + /* void call_elf( entry ) */ +GLOBL(call_elf): + mflr r0 + stwu r1,-16(r1) + stw r0,20(r1) + mtlr r3 + LOADI r8,saved_stack // save our stack pointer + stw r1,0(r8) + LOADI r1,client_stack + LOADI r5,of_client_callback // r5 = callback + li r6,0 // r6 = address of client program arguments (unused) + li r7,0 // r7 = length of client program arguments (unused) + li r0,MSR_FP | MSR_ME | MSR_DR | MSR_IR + mtmsr r0 + blrl + + LOADI r8,saved_stack // restore stack pointer + mr r1,r8 + lwz r0,20(r1) + mtlr r0 + addi r1,r1,16 + // XXX: should restore r12-r31 etc.. + // we should not really come here though + blr + +GLOBL(of_client_callback): + LOADI r4,saved_stack + lwz r4,0(r4) + stwu r4,-32(r4) + mflr r5 + stw r5,32+4(r4) + stw r1,8(r4) // save caller stack + mr r1,r4 + stw r2,12(r1) + stw r0,16(r1) + mfctr r2 + stw r2,20(r1) + mfcr r2 + stw r2,24(r1) + mfxer r2 + stw r2,28(r1) + // do we need to save more registers? + bl of_client_interface + lwz r4,32+4(r1) + mtlr r4 + lwz r2,20(r1) + mtctr r2 + lwz r2,24(r1) + mtcr r2 + lwz r2,28(r1) + mtxer r2 + lwz r2,12(r1) + lwz r0,16(r1) + lwz r1,8(r1) // restore caller stack + blr + + /* rtas glue (must be reloctable) */ +GLOBL(of_rtas_start): + /* r3 = argument buffer, r4 = of_rtas_start */ + /* according to the CHRP standard, cr must be preserved (cr0/cr1 too?) */ + mr r6,r3 + LOADI r3,OSI_SC_MAGIC_R3 + LOADI r4,OSI_SC_MAGIC_R4 + li r5,OSI_OF_RTAS + sc + blr +GLOBL(of_rtas_end): + + + /* used in a hack to the newworld calibration */ +GLOBL(nw_dec_calibration): + .long 0 +GLOBL(timer_calib_start): + LOADI r3,nw_dec_calibration + lwz r3,0(r3) + blr +GLOBL(timer_calib_end): + + +/************************************************************************/ +/* vectors */ +/************************************************************************/ + +GLOBL(__vectors): + nop // NULL-jmp trap +1: nop // + b 1b + +exception_return: + addi r1,r1,16 // pop ABI frame + + lwz r0,52(r1) + mtlr r0 + lwz r0,56(r1) + mtcr r0 + lwz r0,60(r1) + mtctr r0 + lwz r0,64(r1) + mtxer r0 + + lwz r0,0(r1) // restore r0 + lwz r2,8(r1) // restore r2 + lwz r3,12(r1) // restore r3 + lwz r4,16(r1) + lwz r5,20(r1) + lwz r6,24(r1) + lwz r7,28(r1) + lwz r8,32(r1) + lwz r9,36(r1) + lwz r10,40(r1) + lwz r11,44(r1) + lwz r12,48(r1) + lwz r1,4(r1) // restore r1 + rfi + +trap_error: + mflr r3 + b unexpected_excep + +ILLEGAL_VECTOR( 0x100 ) +ILLEGAL_VECTOR( 0x200 ) + +VECTOR( 0x300, "DSI" ): + EXCEPTION_PREAMBLE + LOADI r3,dsi_exception + mtctr r3 + bctrl + b exception_return + +VECTOR( 0x400, "ISI" ): + EXCEPTION_PREAMBLE + LOADI r3,isi_exception + mtctr r3 + bctrl + b exception_return + + ILLEGAL_VECTOR( 0x500 ) + ILLEGAL_VECTOR( 0x600 ) + ILLEGAL_VECTOR( 0x700 ) + +VECTOR( 0x800, "FPU" ): + mtsprg1 r3 + mfsrr1 r3 + ori r3,r3,0x2000 + mtsrr1 r3 + mfsprg1 r3 + rfi + +ILLEGAL_VECTOR( 0x900 ) +ILLEGAL_VECTOR( 0xa00 ) +ILLEGAL_VECTOR( 0xb00 ) +ILLEGAL_VECTOR( 0xc00 ) +ILLEGAL_VECTOR( 0xd00 ) +ILLEGAL_VECTOR( 0xe00 ) +ILLEGAL_VECTOR( 0xf00 ) +ILLEGAL_VECTOR( 0xf20 ) +ILLEGAL_VECTOR( 0x1000 ) +ILLEGAL_VECTOR( 0x1100 ) +ILLEGAL_VECTOR( 0x1200 ) +ILLEGAL_VECTOR( 0x1300 ) +ILLEGAL_VECTOR( 0x1400 ) +ILLEGAL_VECTOR( 0x1500 ) +ILLEGAL_VECTOR( 0x1600 ) +ILLEGAL_VECTOR( 0x1700 ) + +GLOBL(__vectors_end): + + +#define CACHE_LINE_SIZE 32 +#define LG_CACHE_LINE_SIZE 5 + +/* flush_icache_range( ulong start, ulong stop) */ +GLOBL(flush_icache_range): + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + mr r6,r3 +1: dcbst 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + mtctr r4 +2: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 2b + sync /* additional sync needed on g4 */ + isync + blr diff --git a/arch/ppc/timebase.S b/arch/ppc/timebase.S new file mode 100644 index 0000000..dcd112b --- /dev/null +++ b/arch/ppc/timebase.S @@ -0,0 +1,35 @@ +changequote([[[[[,]]]]]) [[[[[ /* shield includes from m4-expansion */ +#include "asm/asmdefs.h" +#include "asm/processor.h" + +/* + * unsigned long long _get_ticks(void); + */ +GLOBL(_get_ticks): +1: mftbu r3 + mftb r4 + mftbu r5 + cmpw 0,r3,r5 + bne 1b + blr + +/* + * Delay for a number of ticks + */ +GLOBL(_wait_ticks): + mflr r8 /* save link register */ + mr r7, r3 /* save tick count */ + bl _get_ticks /* Get start time */ + + /* Calculate end time */ + addc r7, r4, r7 /* Compute end time lower */ + addze r6, r3 /* and end time upper */ + +1: bl _get_ticks /* Get current time */ + subfc r4, r4, r7 /* Subtract current time from end time */ + subfe. r3, r3, r6 + bge 1b /* Loop until time expired */ + + mtlr r8 /* restore link register */ + blr + diff --git a/arch/unix/Kconfig b/arch/unix/Kconfig new file mode 100644 index 0000000..8faafc0 --- /dev/null +++ b/arch/unix/Kconfig @@ -0,0 +1,18 @@ + +config HOST_UNIX + bool "Build Hosted Unix binary" + default y + help + Build a version of the OpenBIOS kernel that runs in a + Unix-like operating system. + +config UNIX_QT + depends HOST_UNIX + bool "QT frontend for Unix binary" + default n + help + Enable this option if you wish to add a graphical user + interface to the openbios hosted unix binary. This option + needs the QT library installed. + +source "arch/unix/plugins/Kconfig" diff --git a/arch/unix/Makefile b/arch/unix/Makefile new file mode 100644 index 0000000..a8c6565 --- /dev/null +++ b/arch/unix/Makefile @@ -0,0 +1,29 @@ +# + +include ../../config/Makefile.top + +SUBDIRS-$(CONFIG_PLUGINS) = plugins +SUBDIRS-$(CONFIG_UNIX_QT) = gui_qt + +DICTIONARIES = unix +unix-SRC = tree.fs $(ARCHDICT_SRC) + +PROGRAMS = unix + +unix-OBJS = $(unix-y) +unix-y += blk.o +unix-y += boot.o +unix-y += unix.o +unix-y += $(KOBJS) +unix-y += $(MODULE_LIBS) $(FS_LIBS) $(DRIVER_LIBS) $(LIBC_LIBS) +unix-$(CONFIG_PLUGINS) += plugins.o + +unix-LDFLAGS = $(unix-LDFLAGS-$(CONFIG_PLUGINS)) +unix-LDFLAGS-y = -rdynamic $(LIBDL_LDFLAGS) +unix-LDFLAGS-n = +unix-LDADD = + +INCLUDES = -I../../kernel -I../../kernel/include -DBOOTSTRAP + +include $(rules)/Rules.forth +include $(rules)/Rules.make diff --git a/arch/unix/blk.c b/arch/unix/blk.c new file mode 100644 index 0000000..28bcf15 --- /dev/null +++ b/arch/unix/blk.c @@ -0,0 +1,115 @@ +/* + * + * + * block device emulation for unix hosts + * + * Copyright (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "blk.h" + +typedef struct { + int unit; + int channel; +} blk_data_t; + + +DECLARE_NODE( blk, INSTALL_OPEN, sizeof(blk_data_t), "+/unix/block/disk" ); + +static void +blk_open( blk_data_t *pb ) +{ + phandle_t ph; + + fword("my-unit"); + + pb->unit = POP(); + pb->channel = 0; /* FIXME */ + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + /* printk("osi-blk: open %d\n", pb->unit ); */ + + PUSH( -1 ); +} + +static void +blk_close( blk_data_t *pb ) +{ + selfword("close-deblocker"); +} + + +/* ( buf blk nblks -- actual ) */ +static void +blk_read_blocks( blk_data_t *pb ) +{ + cell i, n = POP(); + cell blk = POP(); + char *dest = (char*)POP(); + + // printk("blk_read_blocks %x block=%d n=%d\n", (ucell)dest, blk, n ); + + for( i=0; ichannel, pb->unit, blk+i, (ucell)buf, m*512) < 0 ) { + printk("read_from_disk: error\n"); + RET(0); + } + memcpy( dest, buf, m * 512 ); + i += m; + dest += m * 512; + } + PUSH( n ); +} + +/* ( -- bs ) */ +static void +blk_block_size( blk_data_t *pb ) +{ + PUSH( 512 ); +} + +/* ( -- maxbytes ) */ +static void +blk_max_transfer( blk_data_t *pb ) +{ + PUSH( 1024*1024 ); +} + +static void +blk_initialize( blk_data_t *pb ) +{ + fword("is-deblocker"); +} + + +NODE_METHODS( blk ) = { + { NULL, blk_initialize }, + { "open", blk_open }, + { "close", blk_close }, + { "read-blocks", blk_read_blocks }, + { "block-size", blk_block_size }, + { "max-transfer", blk_max_transfer}, +}; + +void +blk_init( void ) +{ + REGISTER_NODE( blk ); +} diff --git a/arch/unix/blk.h b/arch/unix/blk.h new file mode 100644 index 0000000..aa3b965 --- /dev/null +++ b/arch/unix/blk.h @@ -0,0 +1,8 @@ + +#ifndef _H_BLK +#define _H_BLK + +extern void blk_init( void ); +extern int read_from_disk( int channel, int unit, int blk, unsigned long mphys, int size ); + +#endif /* _H_BLK */ diff --git a/arch/unix/boot.c b/arch/unix/boot.c new file mode 100644 index 0000000..7d15d84 --- /dev/null +++ b/arch/unix/boot.c @@ -0,0 +1,80 @@ +/* + * + */ +#undef BOOTSTRAP +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/elfload.h" +#include "openbios/nvram.h" +#include "libc/diskio.h" + +void boot(void); +void *load_elf(char *spec); + +void +*load_elf(char *spec) +{ +#if 0 + int fd; + void *entry=NULL; + int i, lszz_offs, elf_offs; + char buf[128]; // , *addr; + Elf_ehdr ehdr; + Elf_phdr *phdr; + size_t s; + + if( (fd=open_io(spec)) == -1 ) + return NULL; + + if( (elf_offs=find_elf(fd)) < 0 ) { + printk("----> %s is not an ELF image\n", buf ); + return NULL; + } + + if( !(phdr=elf_readhdrs(fd, 0, &ehdr)) ) { + printk("elf32_readhdrs failed\n"); + return NULL; + } + + (ullong *)entry = ehdr.e_entry; + + lszz_offs = elf_offs; + for( i=0; i + + + + + + + + $(CC) $(CFLAGS) -rdynamic $(LIBDL_LDFLAGS) -o $@ $^ + + + + + + + + + + + + + diff --git a/arch/unix/gui_qt/Makefile b/arch/unix/gui_qt/Makefile new file mode 100644 index 0000000..20eb158 --- /dev/null +++ b/arch/unix/gui_qt/Makefile @@ -0,0 +1,42 @@ +# +# Makefile of QT user interface for OpenBIOS +# +# (C) 2004 Stefan Reinauer +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# version 2 +# + +include ../../../config/Makefile.top + +XTARGETS = qt + +qt-OBJS = $(obj-y) +obj-y += gui_qt.o + +QMAKE = qmake +UIDIR = $(shell pwd ) +TOPDIR = $(shell cd $(top_srcdir) ; pwd) +ABSOINC = $(shell cd $(ARCHINCLUDES) 2> /dev/null ; pwd ) + +export UIDIR TOPDIR ABSOINC + +$(ODIR)/makefile.qmake: gui-qt.pro Makefile + @echo "ODIR: $(ODIR)" + @test -d $(ODIR) || $(INSTALL) -d $(ODIR) + @test -d $(ODIR)/qbuild || $(INSTALL) -d $(ODIR)/qbuild + @install -m 644 gui-qt.pro $(ODIR)/ + cd $(ODIR) ; $(QMAKE) -o makefile.qmake + +$(ODIR)/libgui_qt.a: $(ODIR)/makefile.qmake $(wildcard *.cpp) + cd $(ODIR) ; $(MAKE) -f makefile.qmake + @ln -f $(ODIR)/qbuild/libgui_qt.a $@ + +clean-local: + @rm -f $(ODIR)/makefile.qmake + @rm -rf $(QBUILDDIR) + +INCLUDES = -I$(top_srcdir)/include -DBOOTSTRAP + +include $(rules)/Rules.make diff --git a/arch/unix/gui_qt/gui-qt.cpp b/arch/unix/gui_qt/gui-qt.cpp new file mode 100644 index 0000000..7c21ecb --- /dev/null +++ b/arch/unix/gui_qt/gui-qt.cpp @@ -0,0 +1,129 @@ +/* tag: qt user interface fb class + * + * Copyright (C) 2003-2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "gui-qt.h" +#include "logo.xpm" + +#include + +static const int sizex=640; +static const int sizey=480; +static const int depth=8; + +static unsigned char color[256][3]={ + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0xaa }, + { 0x00, 0xaa, 0x00 }, + { 0x00, 0xaa, 0xaa }, + { 0xaa, 0x00, 0x00 }, + { 0xaa, 0x00, 0xaa }, + { 0xaa, 0x55, 0x00 }, + { 0xaa, 0xaa, 0xaa }, + { 0x55, 0x55, 0x55 }, + { 0x55, 0x55, 0xff }, + { 0x55, 0xff, 0x55 }, + { 0x55, 0xff, 0xff }, + { 0xff, 0x55, 0x55 }, + { 0xff, 0x55, 0xff }, + { 0xff, 0xff, 0x55 }, + { 0xff, 0xff, 0xff }, +}; + +FrameBufferWidget::FrameBufferWidget(QWidget *parent, const char * name) +: QWidget(parent, name, Qt::WType_TopLevel) +{ + setCaption ("OpenBIOS"); + setIcon(QPixmap(logo)); + + QPopupMenu *file = new QPopupMenu (this); + + file->insertItem( "E&xit", this, SLOT(quit()), CTRL+Key_Q ); + + QPopupMenu *help = new QPopupMenu( this ); + help->insertItem("&About OpenBIOS", this, SLOT(about()), CTRL+Key_H ); + help->insertItem( "About &Qt", this, SLOT(aboutQt()) ); + + menu = new QMenuBar( this ); + Q_CHECK_PTR( menu ); + menu->insertItem( "&File", file ); + menu->insertSeparator(); + menu->insertItem( "&Help", help ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + + setFixedSize(sizex,sizey+menu->heightForWidth(sizex)); + + buffer.create(sizex, sizey, depth, 256); + + for (int i=16; i < 256; i++) { + color[i][0]=i; + color[i][1]=i; + color[i][2]=i; + } + + for (int i=0; i< 256; i++) + buffer.setColor(i, qRgb(color[i][0], color[i][1], color[i][2])); + + buffer.fill( 0 ); + + updatetimer=new QTimer(this); + connect( updatetimer, SIGNAL(timeout()), this, SLOT(update()) ); + updatetimer->start(200,FALSE); + + setMouseTracking( TRUE ); +} + +unsigned char * FrameBufferWidget::getFrameBuffer(void) +{ + return buffer.bits(); +} + +void FrameBufferWidget::paintEvent ( QPaintEvent * ) +{ + QPainter p( this ); + p.drawImage(0,menu->heightForWidth(sizex),buffer, 0,0, sizex, sizey); +} + +void FrameBufferWidget::about() +{ + QMessageBox::about( this, "About OpenBIOS", + " Welcome to OpenBIOS 1.01\n" + " IEEE 1275-1994 Open Firmware implementation\n\n" + "written by Stefan Reinauer \n\n" + " http://www.openbios.org/\n"); +} + +void FrameBufferWidget::aboutQt() +{ + QMessageBox::aboutQt( this, "OpenBIOS" ); +} + +void FrameBufferWidget::quit() +{ + extern volatile int gui_running; + extern volatile int runforth; + + gui_running=0; + runforth=0; + + qApp->quit(); +} + +void FrameBufferWidget::update() +{ + QPainter p( this ); + p.drawImage(0,menu->heightForWidth(sizex),buffer, 0,0, sizex, sizey); +} + +void FrameBufferWidget::keyPressEvent(QKeyEvent * e) +{ + int a=e->ascii(); + if (a) { + std::cout << " key '" << e->text() << "' pressed" << std::endl; + } +} + diff --git a/arch/unix/gui_qt/gui-qt.h b/arch/unix/gui_qt/gui-qt.h new file mode 100644 index 0000000..59e8916 --- /dev/null +++ b/arch/unix/gui_qt/gui-qt.h @@ -0,0 +1,44 @@ +/* tag: qt user interface fb class description + * + * Copyright (C) 2003-2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __framebufferwidget_h +#define __framebufferwidget_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class FrameBufferWidget : public QWidget { + Q_OBJECT + public: + FrameBufferWidget(QWidget *parent=0, const char *name=0); + unsigned char *getFrameBuffer(void); + + public slots: + void quit(); + void about(); + void aboutQt(); + void update(); + + private: + QImage buffer; + QMenuBar *menu; + QStatusBar *status; + QTimer *updatetimer; + void paintEvent ( QPaintEvent * ); + protected: + void keyPressEvent(QKeyEvent * e); +}; + +#endif diff --git a/arch/unix/gui_qt/gui-qt.pro b/arch/unix/gui_qt/gui-qt.pro new file mode 100644 index 0000000..b96bb0a --- /dev/null +++ b/arch/unix/gui_qt/gui-qt.pro @@ -0,0 +1,19 @@ +# tag: qmake project file for OpenBIOS QT user interface +# +# Copyright (C) 2003-2004 Stefan Reinauer +# +# See the file "COPYING" for further information about +# the copyright and warranty status of this work. +# + +TEMPLATE = lib +CONFIG += qt thread warn_on release staticlib +LIBS = +INCLUDEPATH = qbuild $(ABSOINC) $(TOPDIR)/include +DESTDIR = qbuild +OBJECTS_DIR = qbuild +MOC_DIR = qbuild +TARGET = gui_qt +HEADERS = $(UIDIR)/gui-qt.h +SOURCES = $(UIDIR)/gui-qt.cpp $(UIDIR)/qt-main.cpp + diff --git a/arch/unix/gui_qt/logo.xpm b/arch/unix/gui_qt/logo.xpm new file mode 100644 index 0000000..9e2ac60 --- /dev/null +++ b/arch/unix/gui_qt/logo.xpm @@ -0,0 +1,132 @@ +/* This logo was created by Stephan Lau, + * created to xpm by Stefan Reinauer + */ +static char *logo[] = { +/* columns rows colors chars-per-pixel */ +"300 80 44 1", +" c #010101", +". c #070709", +"X c #0B0B0B", +"o c #0F0F11", +"O c #121212", +"+ c #1B1B1B", +"@ c #1F1F21", +"# c #232323", +"$ c #262628", +"% c #2B2B2C", +"& c #2E2E30", +"* c #333333", +"= c #373739", +"- c #3B3B3B", +"; c #434343", +": c #464648", +"> c #4B4B4B", +", c #4E4E50", +"< c #535353", +"1 c #5B5B5B", +"2 c #5E5E60", +"3 c #646464", +"4 c #666668", +"5 c #6B6B6B", +"6 c #747474", +"7 c #767678", +"8 c #7B7B7B", +"9 c #838383", +"0 c #8A8A8A", +"q c #939394", +"w c #979799", +"e c #9B9B9B", +"r c #A3A3A3", +"t c #ABABAB", +"y c #B4B4B4", +"u c #BBBBBB", +"i c #C3C3C3", +"p c #CBCBCB", +"a c #D3D3D3", +"s c #DBDBDB", +"d c #E3E3E3", +"f c #EBEBEB", +"g c #F3F3F3", +"h c #FEFEFE", +/* pixels */ +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgfdssaapuuuytteeewq0009998867666555555555555565666778899000qwwerttyyuuppassdfghhhhhhhhhhgfgggghhhgfgfghhhhggffghhhhggffghhhhgfggghhhhgfggghhhhgfgfghhhhfgfgghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdsapuytrwq0986555554455555555555555555555555555555555555555555555555555555555555555555555555556790qertyiuuuafhhhfpiishhhhfipidhhhhfiiidhhhhdiiifhhhhsiiifhhhhsiipghhhhaiipghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgfdaiuttq0976555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555558iuue5579wuuuuiasfduuishhhhduuudhhhhduuudhhhhsuuufhhhhauuughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdaittw086555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555558yuur55549uuiw55569uuutyiadsuuudhhhhsuuudhhhhsuuufhhhhauuughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgfapyrw975555555555555555555555555555555555555555555555555555555555555555555555555555555554555555555555555555554455555555555555555555558uuue54559uuuw55559uuuq55550uiutypafduuufhhhhsuuufhhhhsuuufhhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdautw965555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555679qqerttuuppaasdddffgghghhhhhhhhhghhggfduuupaappuuuuyeq090uuuq55559uyi05555quuuuadghsuuufhhhhauuufhhhhauuighhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfsite0655555555555555555555555555555555555555555555555555555555555555555555555455555555555555555690wrtiiaddghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfuuuahhhhfuuushhhhfuuuaaiittuuuq55550uuu95560tuuudhhhhsuuughhhhauuufhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhgsite955555555555555555555555555455555555555555555555555555555555555555555555555545555555555570wryiadfhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhguuuahhhhfuuuahhhhfuuushhhhduuudfsaiuuuuq5555qiuu99etipuuifhhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgaut0655555555555555555555555555555555555555555555556555555555555555555555555555555555554559qruisfhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdsdfhhhhgdddfhhhhfddsfhhhhgdddfhhhhfddsffspyteeq755559qetisfhgfdddghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgsir065555555555555555555555555555455555555555555555554555555555555555555555555555555555580rupsghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhsuudhhhhhhhhhhhhfuuphhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgspyt085555560tudghhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgaue9555555555555555554<----=---=---==-==<555555---:3:--=--=-*--==--<55555545<;------==->135890phhhhhy009tfq0009009090909wshhhhhhg<;;:;;;:<9fhhhhhhhf$ rhhhhhs3# ;phhhhhhhf0# Owghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhdpue0655559wuaghhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgsue855555455555555555555:O. *5455- *. &44555>O 6ghhh+ 5O ehghhh9 . Xighhhhh9 -gfggf3 +sddffd8O rddffffffffgffffgffffffffggffffffffgffffgffdaute09868eusghhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfpr955555555555555555555555% .%=************& +2555o +=************% +3343% X-<3568888787884. ;dggq. O19888888888888, 8fgghsO . 1fggghsO ysdfiO 9ttuu> . 1rtuyuuuuuuuuuuuuiuuuuuuuuuuuuuuuuuuuuuuuuuuuiiuuuut06449rpdhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhduw85555555555555555555555555* .,111<1111111111< #113- #<<111111111111< #123- Xtssaaaaaaaaaaaaa <<<<1,,<<<<<& ;7e8 9apiiiiiipiiiiii6 0ia9 8uuuiipipiiiiiii> oyisdt X%% 2iadgy Xrty6 @69& X90e; *3% 49wttuuuuuuuuuuuuuuuuuuuuuuuuuuuyuyyyuuyuuuuuuuuuuihhhhhhgayw86eifhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhar8555555555555555555555555555543. +<,>>>,>><>>>>,,:. O;:<& -:;>>><>,,<><>,:. $eytO -puuyuuuuuuuuuiutX %rytO *ytrtyuuiuuuuuuu9 1ruis%. 108- . 8tisd% *59, -86* O47qetuuuuuuuuuuuuuuuuuuuuuuuuuuuiasddsaiuuuuuuuuuuighhhhhhhhhgatq9tahhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhgiq55555555555555555555555555555555- ;>:>:,<<<,<<<<<<# . %-;: . O:;;;>>,<<>,,<38; 5qr3 eutttuuiiiipiiii1 5wr< qreeryuiipiiipii$ X0wru8 O976& +9wya0 O999O qeq9O >3< +751. &159wtyuuuuuuuuuuuuuuuuuuuuuuuuisfhhhhhhgdpuuuuuiuuihhhhhhhhhhhhhhdierighhhhhhh", +"hhhhhhhhhhhhhhhhhfi05555555555555555555555555555555552 #>;;:,,<<<11<11<> +--;+ ;;--;><<1116qtpy -009 ,ttrrtuppaaaaaaay -q09 ;ewqrtupaaaaaaap9 10qrtX .3754X . >60tuX 387% 3w09: +3<<112311212+ .---& $;-;;><138eusddd- X000% oerrrtuaadsdddddd- o090$ Xwqqetypadddsddsao .%q9qr3 $856- +160t5 $761 X9097X ;1& &54< *;159wtyuuuuuuuuuuuuuuuuuuuuuushhhhhhhhhhhhhhdpyuuuuihhhhhhhhhhhhhhhhhhhhgsdhhhh", +"hhhhhhhhhhhhhhsr555555545555555555555555555555555555, %;;-:><123333535> %---O .;--;;<5wifgfgfgt 1w04 2ewerupsffgffggft 1w05 1wqqeyasffgfgggg9 7q0wq 6665 ,360w 666O <999= %32. . <31+. +>>160rtuuuuuuuuuuuuuuuuuuuuuyshhhhhhhhhhhhhhhhfuuuuuighhhhhhhhhhhhhhhhhhhhhhhghh", +"hhhhhhhhhhhhhi05555555555555555555555555555555555555o .X;;-::<1335555454X X:--$ &:--,6rsfghhghgh# Orq0O <<<<156999090999# +rqqO +qqqetisgghhghhha >rqqe* >867# *358e* >76; #9994 . .44- o2<>++++O>><48qrtuuuuuuuuuuuuiuuuuuuuuphhhhhhhhhhhhhhhhhhsyuiuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhu65555555555555555555555555555555555555- *;-->>1355555554- *;--. O;-<5rpdfhhhhhhh9 7rq< 6eq, 5w0wtisdgghhhhhh< Oqwqw8 X7773 X45608 X666. 3779% ;55X. %<1356651<<369etyuuuuuuuuuuuuuuuuuuuuudhhhhhhhhhhhhhhhhhhgpyuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhi755555555555555555555555555555555555553. +;--;><2555555553. O:--$ *16qtiafhghhhhhgO *rq9X @,>:><356787888787653rq9X %wqqryadfghhhhhhy 3rqqrO <669O >569q+ <66* =8781 O953 &<24698533359qryuuuuuuuuuuuiuuuuuuuuuphhhhhhhhhhhhhhhhhhhhsyuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhs955555555555555555555555555555555555555% -;;;><1335555555$ -;;* %9wweypdfhhhhhhh4 eeq- 90990rtupaaaaaaaapiutee- 9qqerusfhhhhhhhh# +twqr1 @868= $867q1 @873 o5689O 166; &<36999865690etyyuuuuuuuuuuuuuuuuuuuudhhhhhhhhhhhhhhhhhhhhfiuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhy55555555555555555555555555555555555555< #;--:,<3355555551 #;;-+ Xqwqetisfhghhhhhp 1eq7 >q999qrtuuipipuippuytrr8 :wqqruadfhhhhhhh9 6ewweX 363% #6689qX 276# >769, $867* +13800q9999qrtyuuuuuuuuuuuuuuuuuuuuuufhhhhhhhhhhhhhhhhhhhhhpuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhh955555555555555555555555555555555555555@ .:-;;:<1335555554+ .;:-* 1wqqrupfghhhhhhh; Oeeq$ ..q0990qrtuuuuuuuuuuuuttr& XqqqetpdfghhhhhhfO *tewe> %8869q< *76< O6687X 4669$ .X159qeeeqqqrryuuuuuuuuuuuuuuuuuuuiuuighhhhhhhhhhhhhhhhhhhhhpyuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhh55555555555555555555555555555555555555: $;-;;,<335555554: $:-2+ +qqqeyidgghhhhhhr 1rq3 1q000rryuipiiipiiiiiuuu7 1wqwtuadghhhhhhh6 qwww0 =20979q9 X566X <679= . -8680- . >69errtrrrtyyuuuuuuuuuuuuuuuuuuuuuuihhhhhhhhhhhhhhhhhhhhhhpyuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhh95555555555555555555555555555555555555O X:--;><2355555553O O:162 3eqerusdghhhhhhf# $tqqO +qqqwrtipaaaaaaaaaaaaapp+ Oeqqetpsgghhhhhhs >ewqr&. ;q0998qe* >86; #7685 O6680e1 *50ettyyyyyuuuuuuuuuuuuuuuuuuuuuuuuuhhhhhhhhhhhhhhhhhhhhhhpuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhht655555555555555555555555555555555555: %;-;:<1335555555& .:500X +eqerypsghhhhhhh6 Oqeq3 1qqwryiasddddddddddddsd7 8wqqtuafghhhhhhh; Oreqw7 -999qw7. +665X 4679@ :789wt6 O50etyyuuuuuuuuuuuuuuuuuuuuuuuuuiuuughhhhhhhhhhhhhhhhhhhhhpyuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhs955555555555555555555555555555555555% --;;>1135555553- ,0eq> =wqerisfghhhhhf9 8rwq- 9qqetpsdffgfgffgfdttgfa *rqqryadghhhhhhhq 4rqwrO *-@ 79qeu+ ,76* . *7681 O8680ruy X49etyuuuuuuuuuuuuuuuuuuuuiuuuuuuuuudhhhhhhhhhhhhhhhhhhhhgiuuuhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhu65555555555555555555555555555555554# .4eew9 X Oqteww= #dgg; 9wqwtisfghhhhhhfX Xewqe3 %63< @70ey5 #961 X6678X 3679ruip& 48wryuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuphhhhhhhhhhhhhhhhhhhhduuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhu7555555555555555554555555555555545,@X . .+>qyrre& X8O O-7utreer9=X ufg5 +ewqruadghhhhhhf; >eqweX . 451> -6qyyO 366# ;769< $769wtpaa3 O36qrtuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuighhhhhhhhhhhhhhhhhhhpyuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhp95455555555555555555555555555555331:;---;><1111111117tutre8 1q999wtipaaasssaaaiutrrrruyrq09qruiasasasasassssddddaitrwetisfhghhhhhhgfautewr; -654% o56eu< =86: . O8687 6669ruada4 @160ryuuuuuuuuuuuuuuuuuuiuuuuuuuuuuuuahhhhhhhhhhhhhhhhhhsuuuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhde555555555555555555555555555555331,;---;;,<<<<<1<<8tutrtt+ Or099qwtuipppppppiiuytrtyiiiteq0qryupppppppppppppssdspurreriafghhhhhhhhgdaueee8 X665< ;38e9 X765X 1679% >669wyadfd5 *150rtuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuushhghhhhhhhhhhhhhgiyuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhiq555555555555555555555555555533<<:;-;;>>,>,>,,,6ttyttt3 5q9990rttuuuuuuyuuyyttyupaapurewertyyuuuuuuuuuuuipasaputttypsgghhhhhhhggsautrt* ,667# .+159e* >86;. $6695 .8680tisfgd3 X:160rtuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuudhhhhhhhhhhhhhhgiuiuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhfi055555555555555555555555555332<>>:;:>>>,<>,>6tuuuiiuX *eq00wrryyuuuuyuuuuuyuiiasdsaputrtttuuyuyuuuuyyuupaassaiuyupsfghhhhhhhhhgdaiuy6 O967< 146q3 O865 5679O ,769wuafggfX #:150rtuuuuuuuuuuuuuuuuuuuuuuiuuuuuuuuuuushhhhhhhhhhhhfiuuuuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhfiq5555555555555555555554555431<<<,<<<<<<<15tippppa<. 0wqqetyippppppppppippaasdfgfdsapiipipppppppppppppaadddsaapasfghhhhhhhhhggfsapi+ 1678O -5589+ 176% -679, +85O rgg0 X-,36qrtuuuuuuuuuuuuiuuuuuuuuuuuuuuuuiuuuuupfghhhhhhhfauuuuuuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhat85555555555555555555555433221111111113tsssssdr >eqqetupaasaaasaasssasddfgggggfdssasassaassasaasssddffffddddfgghhhhhhhhhhhgfdd8 $878> X55601 $761 X5788o 37- -dfd@ &>,39qryuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuypsdffdspuuuuuuuuuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhfiw6555555555555555555555333332322331efffdffs+ qqwetiadfffdfddfffdfffffgghhhgggfffdfdffdfdfdfdfdfffggfggfggghhhhhhhhhhhhggggp 6666 >6699 676+ >679- =73 .yss8 .O,,159etyuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuyuyuuuuuuuuuuuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhfiw7545555555555555555555545353350dgggghg4 -rqqruadfggghghhggghgghhhhhhhhhhghghhghgghghghghghghhhhhhhhghghhhhhhhhhhhhhhhg< ;669& +666q* -76, . O8686 X66$ <57qryuuuuuuuuuuuuuuuuuuuuuuuuuiuuuuuuuuiuuuuuuuuuuuuuuuuuuuuuughhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhdir955555555555555555555555555uhhhhhhhgfsuteqrtpdfhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhu X7764 . 15696 .766# . <679$. <7< oqty- %<<149etyuuuuuuuuuuuuuiuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuiuuuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhsue85555455555555555555559dhhhhhhhgfauteeriadghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh* >865X -667q# >765 668= =86% -0q1 +4357qtiasdddddddddddddddsdddddddsddddddsddddddddddddsddddddddddddshhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfaue755555555555555555ehhhhhhhhgdautrtuadghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhq ;-% +76703 O868: . >>% +975 %2* X6669wuadghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhsit06553555555555phhhhhhhggfaiuuupsfghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfO . +76680X 3869- . %986> . . X5877qtpsgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgaur065455555dhhhhhhhhgfdaapadfghghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh6 . -8767q> *7699* . . -0989; +98669qusfggfffghhhhgfffghhhhgfffghhhhgdfdghhhhgfffghhhhgfffghhhhdfffghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgspte955fhhhhhhhhggfddddfghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhs . O3987800 5760e4 O3099997 X;996136qpdfhfuuuahhhhduuushhhhduuudhhhhduuufhhhhsuuufhhhhauuughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfahhhhhhhhhhggffggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh- X%>688780r& ,869qry< #;89999qwr3o O=58887559rdghhguuushhhhfuuishhhhduuudhhhhduuufhhhhsuuufhhhhauuufhhhhauuighhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdauq841<15566890ryupute9880ruuur3<;1156889qrtyyr41>,145670979qyfgghfuuuahhhhfuuushhhhdiuudhhhhduuudhhhhsuuufhhhhauiughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggdptq8433356789qrupaaite990ruppitq85345790wtypiitw84335680qe0qrugghhfuuushhhhfuuushhhhduuudhhhhsuuudhhhhauuufhhhhsuuufhhhhpuuighhhhhhhhhhhhhghhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhg7-&508666880qrtipssaiyeqqrtpsspue076699qetipsaaurq866790ettwrtphhhhfuuuahhhhfuuudhhhhduuudhhhhduuidhhhhsuuufhhhhauuifsfhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhg9O550eqq0qwertuisdffsauyttupsddsayrqqqqrtupaddfdpureq0qeryiprtyahhhhfuuushhhhfuuushhhhfuuudhhhhduuudhhhhsuuufhhhhauuug;0hhauuighhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh;8saiuuttuyuipaddgggfsaiiiasffgfaaiytyuupaddgggfdpuuyyuupadauuuahhhhfiuiahhhhfiuudhhhhduuidhhhhduuufhhhhsiiufhhhhauuug>0hhpiuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhO ysaaaOt3 4dggp% %usssu& *ifssaaaasdffghOpggsOtaat- -ufggXahhpOfggOp7 .5fgfgghhhgggf9 6gggOphhhXigg9 6gggX 9gggi* *pghhO; 4@+dhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhp*4tgffdf %&er phh+;yu&&gfg+:uu*%hgffddfffghhh uhgd tdd@%yy:+hhh uhhu hhh **tr ahhhhhhhhhhh 0uut;* hhh uu h>9hhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 0hhhhhhhhhhhhhhh 0hhhhhhhhhhhhhhh 0hhhhhhhhhhhhhh;0hhhhhh uhhhhhhh 40900hhh 40900hhhhhhhhhhhhhh@0r fhhh uhhu hhh;0hht hhh uhhhhhhhhhhhhhhhhhhhs<#hhhh#0t fhhhhhhs<#hhhh;0hhuhhh 39000hhh uy h9>hhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh00phhhhhhhhhhhhhhh90phhhhhhhhhhhhhhh00phhhhhhhhhhhhhh;9hhhhhh uhhhhhhh@ Ohhhhhhhhhhhhhhg3 shhhhp; ;ahhha+ ;wOhhhXahhhhhhhhhhhhhhhh6 Owhhhhf4 shhhh6 Oqhhhhp$ 6hhhs; OhhhXpaOh0 +#include +#include "unix/plugins.h" +#include "unix/plugin_pci.h" +} +#include "gui-qt.h" + +#define DEBUG + +volatile unsigned char * fb=0; +volatile int gui_running=0; + +typedef struct { + int argc; + char **argv; +} threaddata; + +void *gui_thread(void *ptr) +{ + threaddata *td=(threaddata *)ptr; + + QApplication a(td->argc, td->argv); + FrameBufferWidget w; + + a.setMainWidget(&w); + w.show(); + + fb=w.getFrameBuffer(); + + gui_running=-1; + a.exec(); + gui_running=0; + + return 0; +} + +extern "C" { +extern int plugin_qt_init(void); +int plugin_qt_init(void) +{ + pthread_t mythread; + char *args[]={ "plugin_qt" }; + threaddata mytd = { 1, args }; + +#ifdef DEBUG + printf("Initializing \"framebuffer\" plugin..."); +#endif + pthread_create(&mythread, NULL, gui_thread, &mytd); + while (!fb) + usleep(20); + +#if 0 + + /* now we have the framebuffer start address. + * updating pci config space to reflect this + */ +#if (BITS > 32) + *(u32 *)(pci_config_space+0x14)=(u32)((unsigned long)fb>>32); +#else + *(u32 *)(pci_config_space+0x14)=0; +#endif + *(u32 *)(pci_config_space+0x10)=(u32)((unsigned long)fb&0xffffffff); + + /* next is to write the rom address. We write that at a random + * address in pci config space for now. + */ +#if (BITS > 32) + *(u32 *)(pci_config_space+0x34)=(u32)((unsigned long)qt_fcode>>32); +#else + *(u32 *)(pci_config_space+0x34)=0; +#endif + *(u32 *)(pci_config_space+0x30)=(u32)((unsigned long)qt_fcode&0xffffffff); + + /* FIXME: we need to put the fcode image for this + * device to the rom resource, once it exists + */ + + /* register pci device to be available to beginagain */ + pci_register_device(0, 2, 0, pci_config_space); +#endif +#ifdef DEBUG + printf("done.\n"); +#endif + return 0; +} + +} + diff --git a/arch/unix/plugins.c b/arch/unix/plugins.c new file mode 100644 index 0000000..54a0797 --- /dev/null +++ b/arch/unix/plugins.c @@ -0,0 +1,198 @@ +/* tag: plugin interface for openbios forth kernel + * + * Copyright (C) 2003, 2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/sysinclude.h" +#include +#include +#include +#include + +#include "unix/plugins.h" + +unsigned char *plugindir = "/usr/share/OpenBIOS/plugins"; +#define PLUGINDIR plugindir +#define PATHSIZE 256 + +#define CONFIG_DEBUG_PLUGINS + +typedef struct iorange iorange_t; +struct iorange { + const char *name; + unsigned int start; + unsigned int end; + io_ops_t *ops; + iorange_t *next; +}; + +static iorange_t *ioranges = NULL; + +typedef struct plugin plugin_t; +struct plugin { + const char *name; + plugin_t *next; +}; + +static plugin_t *plugins = NULL; + +io_ops_t *find_iorange(u32 reg) +{ + iorange_t *range = ioranges; + while (range) { + if (range->start <= reg && range->end >= reg) + return range->ops; + range = range->next; + } + return NULL; +} + +int register_iorange(const char *name, io_ops_t * ops, unsigned int rstart, + unsigned int rend) +{ + iorange_t *newrange; + + /* intersection check */ + newrange = ioranges; + while (newrange) { + int fail = 0; + /* new section swallows old section */ + if (newrange->start >= rstart && newrange->end <= rend) + fail = -1; + /* new section start or end point are within range */ + if (newrange->start <= rstart && newrange->end >= rstart) + fail = -1; + if (newrange->start <= rend && newrange->end >= rend) + fail = -1; + if (fail) { + printf("Error: overlapping IO regions: %s and %s\n", + newrange->name, name); + return -1; + } + newrange = newrange->next; + } + + newrange = malloc(sizeof(iorange_t)); + + newrange->name = name; + newrange->ops = ops; + newrange->start = rstart; + newrange->end = rend; + newrange->next = ioranges; + + ioranges = newrange; + + return 0; +} + +int is_loaded(const char *plugin_name) +{ + plugin_t *p = plugins; + while (p) { + if (!strcmp(plugin_name, p->name)) + return -1; + p = p->next; + } + return 0; +} + +int load_plugin(const char *plugin_name) +{ + void *handle; + char *error; + char path[PATHSIZE]; + + int (*init_plugin) (void); + char **deps; + char **plugin_info; + plugin_t *p; + + if (is_loaded(plugin_name)) { + printf("Plugin %s already loaded.\n", plugin_name); + return 0; + } + + strncpy(path, PLUGINDIR, PATHSIZE); + strncat(path, "/plugin_", PATHSIZE); + strncat(path, plugin_name, PATHSIZE); + strncat(path, ".so", PATHSIZE); + +#if DEBUG + printf("Opening plugin %s\n", path); +#endif + + handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + error = dlerror(); + printf("Error: Could not open plugin \"%s\": %s\n", + plugin_name, error); + exit(1); + } +#ifdef CONFIG_DEBUG_PLUGINS + plugin_info = dlsym(handle, "plugin_author"); + if ((error = dlerror()) == NULL) + printf("Plugin %s author: %s\n", plugin_name, *plugin_info); + plugin_info = dlsym(handle, "plugin_license"); + if ((error = dlerror()) == NULL) + printf("Plugin %s license: %s\n", plugin_name, *plugin_info); + plugin_info = dlsym(handle, "plugin_description"); + if ((error = dlerror()) == NULL) + printf("Plugin %s descr.: %s\n", plugin_name, *plugin_info); +#endif + p = malloc(sizeof(plugin_t)); + p->next = plugins; + p->name = plugin_name; + plugins = p; + + deps = dlsym(handle, "plugin_deps"); + if ((error = dlerror()) != NULL) + deps = NULL; + + + strncpy(path, "plugin_", PATHSIZE); + strncat(path, plugin_name, PATHSIZE); + strncat(path, "_init", PATHSIZE); + + init_plugin = dlsym(handle, path); + if ((error = dlerror()) != NULL) { + printf("error: %s\n", error); + exit(1); + } + + if (deps) { + int i = 0; + char *walk = deps[0]; +#ifdef CONFIG_DEBUG_PLUGINS + printf("\nPlugin %s dependencies:", plugin_name); +#endif + while (walk) { + printf(" %s", walk); + if (!is_loaded(walk)) { +#ifdef CONFIG_DEBUG_PLUGINS + printf("(loading)\n"); +#endif + load_plugin(walk); + } +#ifdef CONFIG_DEBUG_PLUGINS + else { + printf("(loaded)"); + } +#endif + walk = deps[++i]; + } + } + + printf("\n"); +#if DEBUG + printf("Initializing module:\n"); +#endif + + return init_plugin(); + + // We don't dlclose the handle here since + // we want to keep our symbols for later use. +} + diff --git a/arch/unix/plugins/Kconfig b/arch/unix/plugins/Kconfig new file mode 100644 index 0000000..06bfcaa --- /dev/null +++ b/arch/unix/plugins/Kconfig @@ -0,0 +1,17 @@ +config PLUGINS + depends HOST_UNIX + bool "Plugin system (obsolete)" + default n + +config PLUGIN_PCI + depends HOST_UNIX && PLUGINS + bool "PCI Emulation" + default n + +config PLUGIN_QT + bool "QT Display Emulation" + depends HOST_UNIX && PLUGINS && PLUGIN_PCI + default n + help + This plugin needs qt installed. Disable if you don't have qt. + diff --git a/arch/unix/plugins/Makefile b/arch/unix/plugins/Makefile new file mode 100644 index 0000000..c6b9a65 --- /dev/null +++ b/arch/unix/plugins/Makefile @@ -0,0 +1,13 @@ + +include ../../../config/Makefile.top + +SUBDIRS-$(CONFIG_PLUGIN_PCI) += plugin_pci +SUBDIRS-$(CONFIG_PLUGIN_QT) += plugin_qt + +PROGRAMS = # loader +loader-OBJS = loader.o +loader-LDFLAGS = -dynamic $(LIBDL_LDFLAGS) + +INCLUDES = -DBOOTSTRAP + +include $(rules)/Rules.make diff --git a/arch/unix/plugins/Rules.plugin b/arch/unix/plugins/Rules.plugin new file mode 100644 index 0000000..9e9b625 --- /dev/null +++ b/arch/unix/plugins/Rules.plugin @@ -0,0 +1,15 @@ +# -*- makefile -*- + +INCLUDES = -I$(top_srcdir)/include -DBOOTSTRAP +CFLAGS = -fPIC + +%.so: %.o + $(CC) -shared $(CFLAGS) $(filter %.o,$^) -o $@ + +THISDIR := $(notdir $(shell pwd)) + +all-local: $(addprefix $(ODIR)/../,$(PLUGINS)) + +$(ODIR)/../%.so: $(ODIR)/%.so + install -d ../$(ODIR) + ln -f "../$(THISDIR)"/$< $@ diff --git a/arch/unix/plugins/loader.c b/arch/unix/plugins/loader.c new file mode 100644 index 0000000..d3781de --- /dev/null +++ b/arch/unix/plugins/loader.c @@ -0,0 +1,209 @@ +/* tag: openbios plugin loader + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +/* This is a simple plugin loader. OpenBIOS duplicates some + * of this code in kernel/arch/unix/plugins.c. This code is + * here for reference and simple testing. + */ + +#include +#include +#include +#include +#include // sleep + +#include "unix/plugins.h" + +#define PLUGINDIR "/usr/share/OpenBIOS/plugins" +#define PATHSIZE 256 + +#define DEBUG_PLUGINS + +typedef struct iorange iorange_t; +struct iorange { + const char *name; + unsigned int start; + unsigned int end; + io_ops_t *ops; + iorange_t *next; +}; + +iorange_t *ioranges = NULL; + +typedef struct plugin plugin_t; +struct plugin { + const char *name; + plugin_t *next; +}; + +plugin_t *plugins = NULL; + +int register_iorange(const char *name, io_ops_t * ops, unsigned int rstart, + unsigned int rend) +{ + iorange_t *newrange; + + /* intersection check */ + newrange = ioranges; + while (newrange) { + int fail = 0; + /* new section swallows old section */ + if (newrange->start >= rstart && newrange->end <= rend) + fail = -1; + /* new section start or end point are within range */ + if (newrange->start <= rstart && newrange->end >= rstart) + fail = -1; + if (newrange->start <= rend && newrange->end >= rend) + fail = -1; + if (fail) { + printf("Error: overlapping IO regions: %s and %s\n", + newrange->name, name); + return -1; + } + newrange = newrange->next; + } + + newrange = malloc(sizeof(iorange_t)); + + newrange->name = name; + newrange->ops = ops; + newrange->start = rstart; + newrange->end = rend; + newrange->next = ioranges; + + ioranges = newrange; + + return 0; +} + +int is_loaded(const char *plugin_name) +{ + plugin_t *p = plugins; + while (p) { + if (!strcmp(plugin_name, p->name)) + return -1; + p = p->next; + } + return 0; +} + +int load_plugin(const char *plugin_name) +{ + void *handle; + char *error; + char path[PATHSIZE]; + + int (*init_plugin) (void); + char **deps; + char **plugin_info; + plugin_t *p; + + if (is_loaded(plugin_name)) { + printf("Plugin %s already loaded.\n", plugin_name); + return 0; + } + + strncpy(path, PLUGINDIR, PATHSIZE); + strncat(path, "/plugin_", PATHSIZE); + strncat(path, plugin_name, PATHSIZE); + strncat(path, ".so", PATHSIZE); + +#if DEBUG + printf("Opening plugin %s\n", path); +#endif + + handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + error = dlerror(); + printf("Error: Could not open plugin \"%s\": %s\n", + plugin_name, error); + exit(1); + } +#ifdef DEBUG_PLUGINS + plugin_info = dlsym(handle, "plugin_author"); + if ((error = dlerror()) == NULL) + printf("Plugin %s author: %s\n", plugin_name, *plugin_info); + plugin_info = dlsym(handle, "plugin_license"); + if ((error = dlerror()) == NULL) + printf("Plugin %s license: %s\n", plugin_name, *plugin_info); + plugin_info = dlsym(handle, "plugin_description"); + if ((error = dlerror()) == NULL) + printf("Plugin %s descr.: %s\n", plugin_name, *plugin_info); +#endif + p = malloc(sizeof(plugin_t)); + p->next = plugins; + p->name = plugin_name; + plugins = p; + + deps = dlsym(handle, "plugin_deps"); + if ((error = dlerror()) != NULL) + deps = NULL; + + + strncpy(path, "plugin_", PATHSIZE); + strncat(path, plugin_name, PATHSIZE); + strncat(path, "_init", PATHSIZE); + + init_plugin = dlsym(handle, path); + if ((error = dlerror()) != NULL) { + printf("error: %s\n", error); + exit(1); + } + + if (deps) { + int i = 0; + char *walk = deps[0]; +#ifdef DEBUG_PLUGINS + printf("\nPlugin %s dependencies:", plugin_name); +#endif + while (walk) { + printf(" %s", walk); + if (!is_loaded(walk)) { +#ifdef DEBUG_PLUGINS + printf("(loading)\n"); +#endif + load_plugin(walk); + } +#ifdef DEBUG_PLUGINS + else { + printf("(loaded)"); + } +#endif + walk = deps[++i]; + } + } + + printf("\n"); +#if DEBUG + printf("Initializing module:\n"); +#endif + + return init_plugin(); + + // We don't dlclose the handle here since + // we want to keep our symbols for later use. +} + +int main(void) +{ + iorange_t *r; + + // load_plugin("kbd"); + // load_plugin("pci"); + load_plugin("qt"); + + printf("\nRegistered IO Ranges:\n"); + r = ioranges; + while (r) { + printf(" %s: %x-%x\n", r->name, r->start, r->end); + r = r->next; + } + + sleep(10); + return 0; +} diff --git a/arch/unix/plugins/plugin_pci/Makefile b/arch/unix/plugins/plugin_pci/Makefile new file mode 100644 index 0000000..e46a6cd --- /dev/null +++ b/arch/unix/plugins/plugin_pci/Makefile @@ -0,0 +1,7 @@ + +include ../../../../config/Makefile.top + +PLUGINS = plugin_pci.so + +include ../Rules.plugin +include $(rules)/Rules.make diff --git a/arch/unix/plugins/plugin_pci/Makefile.old b/arch/unix/plugins/plugin_pci/Makefile.old new file mode 100644 index 0000000..10d0555 --- /dev/null +++ b/arch/unix/plugins/plugin_pci/Makefile.old @@ -0,0 +1,21 @@ +# tag: Makefile for OpenBIOS PCI plugin +# +# Copyright (C) 2003 Stefan Reinauer +# +# See the file "COPYING" for further information about +# the copyright and warranty status of this work. +# + +PLUGIN_SOURCES = plugin_pci.c +PLUGIN_NAME = plugin_pci.so + +INCLUDES := -I$(TOPDIR)/include -I$(BUILDDIR) -I.. +VPATH := $(VPATH):. + +all: $(PLUGIN_NAME) + +$(PLUGIN_NAME): $(PLUGIN_SOURCES) + $(CC) -shared -Wall -Os -fPIC $(INCLUDES) $< -o $(BUILDDIR)/$@ + +clean: + rm -f plugin_*.so diff --git a/arch/unix/plugins/plugin_pci/plugin_pci.c b/arch/unix/plugins/plugin_pci/plugin_pci.c new file mode 100644 index 0000000..0e62246 --- /dev/null +++ b/arch/unix/plugins/plugin_pci/plugin_pci.c @@ -0,0 +1,221 @@ +/* tag: openbios pci plugin + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include +#include +#include "unix/plugins.h" +#include "unix/plugin_pci.h" + +#define DEBUG + +u32 pci_conf_addr = 0; +pci_dev_t *pci_devices = NULL; + +static pci_dev_t *find_device(u32 conf_addr) +{ + pci_dev_t *devs = pci_devices; + unsigned bus = (conf_addr >> 16) & 0xff; + unsigned dev = (conf_addr >> 11) & 0x1f; + unsigned fn = (conf_addr >> 8) & 0x7; + + // printf("Looking for device %x\n",conf_addr); + + while (devs) { + if (devs->bus == bus && devs->dev == dev && devs->fn == fn) + return devs; + devs = devs->next; + } + return NULL; +} + +/* + * IO functions. These manage all the magic of providing a PCI + * compatible interface to OpenBIOS' unix version of the kernel. + */ + +static u8 pci_inb(u32 reg) +{ + u32 basereg = (reg & 0xfffc); + u32 basepos = (reg & 0x03); + pci_dev_t *dev; + + if (basereg == 0xcf8) { + return (pci_conf_addr >> (basepos << 3)); + } + + /* still here? so we're 0xCFC */ + dev = find_device(pci_conf_addr); + if (!dev || !dev->config) + return 0xff; + + return dev->config[(pci_conf_addr + basepos) & 0xff]; +} + +static u16 pci_inw(u32 reg) +{ + u32 basereg = (reg & 0xfffc); + u32 basepos = (reg & 0x02); + pci_dev_t *dev; + + if (basereg == 0xcf8) { + return (pci_conf_addr >> (basepos << 3)); + } + + /* still here? so we're 0xCFC */ + dev = find_device(pci_conf_addr); + if (!dev || !dev->config) + return 0xffff; + + return *(u16 *) (dev->config + ((pci_conf_addr + basepos) & 0xff)); +} + +static u32 pci_inl(u32 reg) +{ + u32 basereg = (reg & 0xfffc); + pci_dev_t *dev; + + if (basereg == 0xcf8) { + return pci_conf_addr; + } + + /* still here? so we're 0xCFC */ + dev = find_device(pci_conf_addr); + if (!dev || !dev->config) + return 0xffffffff; + + return *(u32 *) (dev->config + (pci_conf_addr & 0xff)); +} + +static void pci_outb(u32 reg, u8 val) +{ + u32 basereg = (reg & 0xfffc); + u32 basepos = (reg & 0x03); + pci_dev_t *dev; + + if (basereg == 0xcf8) { + pci_conf_addr &= (~(0xff << (basepos << 3))); + pci_conf_addr |= (val << (basepos << 3)); + return; + } + + /* still here? so we're 0xCFC */ + dev = find_device(pci_conf_addr); + if (!dev || !dev->config) + return; + + dev->config[pci_conf_addr & 0xff] = val; +} + +static void pci_outw(u32 reg, u16 val) +{ + u32 basereg = (reg & 0xfffc); + u32 basepos = (reg & 0x02); + pci_dev_t *dev; + + if (basereg == 0xcf8) { + pci_conf_addr &= (~(0xffff << (basepos << 3))); + pci_conf_addr |= (val << (basepos << 3)); + return; + } + + /* still here? so we're 0xCFC */ + dev = find_device(pci_conf_addr); + if (!dev || !dev->config) + return; + + *(u16 *) (dev->config + (pci_conf_addr & 0xff)) = val; +} + +static void pci_outl(u32 reg, u32 val) +{ + u32 basereg = (reg & 0xfffc); + pci_dev_t *dev; + + if (basereg == 0xcf8) { + pci_conf_addr = val; + return; + } + + /* still here? so we're 0xCFC */ + dev = find_device(pci_conf_addr); + if (!dev || !dev->config) + return; + + *(u32 *) (dev->config + (pci_conf_addr & 0xff)) = val; +} + +static io_ops_t pci_io_ops = { + inb:pci_inb, + inw:pci_inw, + inl:pci_inl, + outb:pci_outb, + outw:pci_outw, + outl:pci_outl +}; + +/* + * Functions visible to modules depending on this module. + */ + +int pci_register_device(unsigned bus, unsigned dev, unsigned fn, + u8 * config) +{ + pci_dev_t *newdev; + u32 caddr = (1 << 31) | (bus << 16) | (dev << 11) | (fn << 8); + + if (find_device(caddr)) { + printf("Error: pci device %02x:%02x.%01x already exists\n", + bus, dev, fn); + return -1; + } + + newdev = malloc(sizeof(pci_dev_t)); + + if (!newdev) { + printf("Out of memory\n"); + return -1; + } + + newdev->bus = bus; + newdev->dev = dev; + newdev->fn = fn; + newdev->config = config; + newdev->next = pci_devices; + + pci_devices = newdev; + + return 0; +} + +/* + * Initialization is really simple. We just grab the + * PCI conf1 io range for our emulation functions. + */ +extern int plugin_pci_init( void ); + +int plugin_pci_init(void) +{ +#ifdef DEBUG + printf("Plugin \"pci\" initializing... "); +#endif + register_iorange("pci", &pci_io_ops, 0xcf8, 0xcff); +#ifdef DEBUG + printf("done.\n"); +#endif + return 0; +} + +/* plugin meta information available for the plugin loader */ +PLUGIN_AUTHOR ("Stefan Reinauer ") +PLUGIN_DESCRIPTION ("Generic PCI Device Emulation") +PLUGIN_LICENSE ("GPL v2") + +/* This plugin has no dependencies. Otherwise the following + * macro would be uncommented: + * PLUGIN_DEPENDENCIES ("this", "that") + */ diff --git a/arch/unix/plugins/plugin_qt/Makefile b/arch/unix/plugins/plugin_qt/Makefile new file mode 100644 index 0000000..371dc2f --- /dev/null +++ b/arch/unix/plugins/plugin_qt/Makefile @@ -0,0 +1,37 @@ + +include ../../../../config/Makefile.top + +PLUGINS = plugin_qt.so + +QMAKE = qmake +PLUGINDIR = $(shell cd .. ; pwd ) +TOPDIR = $(shell cd $(top_srcdir) ; pwd) +ABSOINC = $(shell cd $(ARCHINCLUDES) 2> /dev/null ; pwd ) + +export PLUGINDIR TOPDIR ABSOINC + +qt_rom.fc: qt_rom.fs + $(TOKE) -v qt_rom.fs + +fcode.h: qt_rom.fc + @echo "static const u8 qt_fcode[] = {" > $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@ + +$(ODIR)/makefile.qmake: plugin_qt.pro Makefile + @test -d $(ODIR) || $(INSTALL) -d $(ODIR) + @test -d $(ODIR)/qbuild || $(INSTALL) -d $(ODIR)/qbuild + @cp plugin_qt.pro $(ODIR)/ + cd $(ODIR) ; $(QMAKE) -o makefile.qmake + +$(ODIR)/plugin_qt.so: fcode.h $(ODIR)/makefile.qmake $(wildcard *.cpp) + cd $(ODIR) ; $(MAKE) -f makefile.qmake + @ln -f $(ODIR)/qbuild/plugin_qt.so $@ + +clean-local: + @rm -f $(ODIR)/makefile.qmake + @rm -rf $(QBUILDDIR) $(ODIR)/*.fc $(ODIR)/fcode.h + +include ../Rules.plugin +include $(rules)/Rules.make diff --git a/arch/unix/plugins/plugin_qt/logo.xpm b/arch/unix/plugins/plugin_qt/logo.xpm new file mode 100644 index 0000000..9e2ac60 --- /dev/null +++ b/arch/unix/plugins/plugin_qt/logo.xpm @@ -0,0 +1,132 @@ +/* This logo was created by Stephan Lau, + * created to xpm by Stefan Reinauer + */ +static char *logo[] = { +/* columns rows colors chars-per-pixel */ +"300 80 44 1", +" c #010101", +". c #070709", +"X c #0B0B0B", +"o c #0F0F11", +"O c #121212", +"+ c #1B1B1B", +"@ c #1F1F21", +"# c #232323", +"$ c #262628", +"% c #2B2B2C", +"& c #2E2E30", +"* c #333333", +"= c #373739", +"- c #3B3B3B", +"; c #434343", +": c #464648", +"> c #4B4B4B", +", c #4E4E50", +"< c #535353", +"1 c #5B5B5B", +"2 c #5E5E60", +"3 c #646464", +"4 c #666668", +"5 c #6B6B6B", +"6 c #747474", +"7 c #767678", +"8 c #7B7B7B", +"9 c #838383", +"0 c #8A8A8A", +"q c #939394", +"w c #979799", +"e c #9B9B9B", +"r c #A3A3A3", +"t c #ABABAB", +"y c #B4B4B4", +"u c #BBBBBB", +"i c #C3C3C3", +"p c #CBCBCB", +"a c #D3D3D3", +"s c #DBDBDB", +"d c #E3E3E3", +"f c #EBEBEB", +"g c #F3F3F3", +"h c #FEFEFE", +/* pixels */ +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgfdssaapuuuytteeewq0009998867666555555555555565666778899000qwwerttyyuuppassdfghhhhhhhhhhgfgggghhhgfgfghhhhggffghhhhggffghhhhgfggghhhhgfggghhhhgfgfghhhhfgfgghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdsapuytrwq0986555554455555555555555555555555555555555555555555555555555555555555555555555555556790qertyiuuuafhhhfpiishhhhfipidhhhhfiiidhhhhdiiifhhhhsiiifhhhhsiipghhhhaiipghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgfdaiuttq0976555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555558iuue5579wuuuuiasfduuishhhhduuudhhhhduuudhhhhsuuufhhhhauuughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdaittw086555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555558yuur55549uuiw55569uuutyiadsuuudhhhhsuuudhhhhsuuufhhhhauuughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgfapyrw975555555555555555555555555555555555555555555555555555555555555555555555555555555554555555555555555555554455555555555555555555558uuue54559uuuw55559uuuq55550uiutypafduuufhhhhsuuufhhhhsuuufhhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdautw965555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555679qqerttuuppaasdddffgghghhhhhhhhhghhggfduuupaappuuuuyeq090uuuq55559uyi05555quuuuadghsuuufhhhhauuufhhhhauuighhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfsite0655555555555555555555555555555555555555555555555555555555555555555555555455555555555555555690wrtiiaddghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfuuuahhhhfuuushhhhfuuuaaiittuuuq55550uuu95560tuuudhhhhsuuughhhhauuufhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhgsite955555555555555555555555555455555555555555555555555555555555555555555555555545555555555570wryiadfhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhguuuahhhhfuuuahhhhfuuushhhhduuudfsaiuuuuq5555qiuu99etipuuifhhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgaut0655555555555555555555555555555555555555555555556555555555555555555555555555555555554559qruisfhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdsdfhhhhgdddfhhhhfddsfhhhhgdddfhhhhfddsffspyteeq755559qetisfhgfdddghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgsir065555555555555555555555555555455555555555555555554555555555555555555555555555555555580rupsghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhsuudhhhhhhhhhhhhfuuphhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgspyt085555560tudghhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgaue9555555555555555554<----=---=---==-==<555555---:3:--=--=-*--==--<55555545<;------==->135890phhhhhy009tfq0009009090909wshhhhhhg<;;:;;;:<9fhhhhhhhf$ rhhhhhs3# ;phhhhhhhf0# Owghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhdpue0655559wuaghhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgsue855555455555555555555:O. *5455- *. &44555>O 6ghhh+ 5O ehghhh9 . Xighhhhh9 -gfggf3 +sddffd8O rddffffffffgffffgffffffffggffffffffgffffgffdaute09868eusghhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfpr955555555555555555555555% .%=************& +2555o +=************% +3343% X-<3568888787884. ;dggq. O19888888888888, 8fgghsO . 1fggghsO ysdfiO 9ttuu> . 1rtuyuuuuuuuuuuuuiuuuuuuuuuuuuuuuuuuuuuuuuuuuiiuuuut06449rpdhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhduw85555555555555555555555555* .,111<1111111111< #113- #<<111111111111< #123- Xtssaaaaaaaaaaaaa <<<<1,,<<<<<& ;7e8 9apiiiiiipiiiiii6 0ia9 8uuuiipipiiiiiii> oyisdt X%% 2iadgy Xrty6 @69& X90e; *3% 49wttuuuuuuuuuuuuuuuuuuuuuuuuuuuyuyyyuuyuuuuuuuuuuihhhhhhgayw86eifhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhar8555555555555555555555555555543. +<,>>>,>><>>>>,,:. O;:<& -:;>>><>,,<><>,:. $eytO -puuyuuuuuuuuuiutX %rytO *ytrtyuuiuuuuuuu9 1ruis%. 108- . 8tisd% *59, -86* O47qetuuuuuuuuuuuuuuuuuuuuuuuuuuuiasddsaiuuuuuuuuuuighhhhhhhhhgatq9tahhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhgiq55555555555555555555555555555555- ;>:>:,<<<,<<<<<<# . %-;: . O:;;;>>,<<>,,<38; 5qr3 eutttuuiiiipiiii1 5wr< qreeryuiipiiipii$ X0wru8 O976& +9wya0 O999O qeq9O >3< +751. &159wtyuuuuuuuuuuuuuuuuuuuuuuuuisfhhhhhhgdpuuuuuiuuihhhhhhhhhhhhhhdierighhhhhhh", +"hhhhhhhhhhhhhhhhhfi05555555555555555555555555555555552 #>;;:,,<<<11<11<> +--;+ ;;--;><<1116qtpy -009 ,ttrrtuppaaaaaaay -q09 ;ewqrtupaaaaaaap9 10qrtX .3754X . >60tuX 387% 3w09: +3<<112311212+ .---& $;-;;><138eusddd- X000% oerrrtuaadsdddddd- o090$ Xwqqetypadddsddsao .%q9qr3 $856- +160t5 $761 X9097X ;1& &54< *;159wtyuuuuuuuuuuuuuuuuuuuuuushhhhhhhhhhhhhhdpyuuuuihhhhhhhhhhhhhhhhhhhhgsdhhhh", +"hhhhhhhhhhhhhhsr555555545555555555555555555555555555, %;;-:><123333535> %---O .;--;;<5wifgfgfgt 1w04 2ewerupsffgffggft 1w05 1wqqeyasffgfgggg9 7q0wq 6665 ,360w 666O <999= %32. . <31+. +>>160rtuuuuuuuuuuuuuuuuuuuuuyshhhhhhhhhhhhhhhhfuuuuuighhhhhhhhhhhhhhhhhhhhhhhghh", +"hhhhhhhhhhhhhi05555555555555555555555555555555555555o .X;;-::<1335555454X X:--$ &:--,6rsfghhghgh# Orq0O <<<<156999090999# +rqqO +qqqetisgghhghhha >rqqe* >867# *358e* >76; #9994 . .44- o2<>++++O>><48qrtuuuuuuuuuuuuiuuuuuuuuphhhhhhhhhhhhhhhhhhsyuiuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhu65555555555555555555555555555555555555- *;-->>1355555554- *;--. O;-<5rpdfhhhhhhh9 7rq< 6eq, 5w0wtisdgghhhhhh< Oqwqw8 X7773 X45608 X666. 3779% ;55X. %<1356651<<369etyuuuuuuuuuuuuuuuuuuuuudhhhhhhhhhhhhhhhhhhgpyuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhi755555555555555555555555555555555555553. +;--;><2555555553. O:--$ *16qtiafhghhhhhgO *rq9X @,>:><356787888787653rq9X %wqqryadfghhhhhhy 3rqqrO <669O >569q+ <66* =8781 O953 &<24698533359qryuuuuuuuuuuuiuuuuuuuuuphhhhhhhhhhhhhhhhhhhhsyuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhs955555555555555555555555555555555555555% -;;;><1335555555$ -;;* %9wweypdfhhhhhhh4 eeq- 90990rtupaaaaaaaapiutee- 9qqerusfhhhhhhhh# +twqr1 @868= $867q1 @873 o5689O 166; &<36999865690etyyuuuuuuuuuuuuuuuuuuuudhhhhhhhhhhhhhhhhhhhhfiuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhy55555555555555555555555555555555555555< #;--:,<3355555551 #;;-+ Xqwqetisfhghhhhhp 1eq7 >q999qrtuuipipuippuytrr8 :wqqruadfhhhhhhh9 6ewweX 363% #6689qX 276# >769, $867* +13800q9999qrtyuuuuuuuuuuuuuuuuuuuuuufhhhhhhhhhhhhhhhhhhhhhpuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhh955555555555555555555555555555555555555@ .:-;;:<1335555554+ .;:-* 1wqqrupfghhhhhhh; Oeeq$ ..q0990qrtuuuuuuuuuuuuttr& XqqqetpdfghhhhhhfO *tewe> %8869q< *76< O6687X 4669$ .X159qeeeqqqrryuuuuuuuuuuuuuuuuuuuiuuighhhhhhhhhhhhhhhhhhhhhpyuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhh55555555555555555555555555555555555555: $;-;;,<335555554: $:-2+ +qqqeyidgghhhhhhr 1rq3 1q000rryuipiiipiiiiiuuu7 1wqwtuadghhhhhhh6 qwww0 =20979q9 X566X <679= . -8680- . >69errtrrrtyyuuuuuuuuuuuuuuuuuuuuuuihhhhhhhhhhhhhhhhhhhhhhpyuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhh95555555555555555555555555555555555555O X:--;><2355555553O O:162 3eqerusdghhhhhhf# $tqqO +qqqwrtipaaaaaaaaaaaaapp+ Oeqqetpsgghhhhhhs >ewqr&. ;q0998qe* >86; #7685 O6680e1 *50ettyyyyyuuuuuuuuuuuuuuuuuuuuuuuuuhhhhhhhhhhhhhhhhhhhhhhpuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhht655555555555555555555555555555555555: %;-;:<1335555555& .:500X +eqerypsghhhhhhh6 Oqeq3 1qqwryiasddddddddddddsd7 8wqqtuafghhhhhhh; Oreqw7 -999qw7. +665X 4679@ :789wt6 O50etyyuuuuuuuuuuuuuuuuuuuuuuuuuiuuughhhhhhhhhhhhhhhhhhhhhpyuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhs955555555555555555555555555555555555% --;;>1135555553- ,0eq> =wqerisfghhhhhf9 8rwq- 9qqetpsdffgfgffgfdttgfa *rqqryadghhhhhhhq 4rqwrO *-@ 79qeu+ ,76* . *7681 O8680ruy X49etyuuuuuuuuuuuuuuuuuuuuiuuuuuuuuudhhhhhhhhhhhhhhhhhhhhgiuuuhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhu65555555555555555555555555555555554# .4eew9 X Oqteww= #dgg; 9wqwtisfghhhhhhfX Xewqe3 %63< @70ey5 #961 X6678X 3679ruip& 48wryuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuphhhhhhhhhhhhhhhhhhhhduuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhu7555555555555555554555555555555545,@X . .+>qyrre& X8O O-7utreer9=X ufg5 +ewqruadghhhhhhf; >eqweX . 451> -6qyyO 366# ;769< $769wtpaa3 O36qrtuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuighhhhhhhhhhhhhhhhhhhpyuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhp95455555555555555555555555555555331:;---;><1111111117tutre8 1q999wtipaaasssaaaiutrrrruyrq09qruiasasasasassssddddaitrwetisfhghhhhhhgfautewr; -654% o56eu< =86: . O8687 6669ruada4 @160ryuuuuuuuuuuuuuuuuuuiuuuuuuuuuuuuahhhhhhhhhhhhhhhhhhsuuuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhde555555555555555555555555555555331,;---;;,<<<<<1<<8tutrtt+ Or099qwtuipppppppiiuytrtyiiiteq0qryupppppppppppppssdspurreriafghhhhhhhhgdaueee8 X665< ;38e9 X765X 1679% >669wyadfd5 *150rtuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuushhghhhhhhhhhhhhhgiyuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhiq555555555555555555555555555533<<:;-;;>>,>,>,,,6ttyttt3 5q9990rttuuuuuuyuuyyttyupaapurewertyyuuuuuuuuuuuipasaputttypsgghhhhhhhggsautrt* ,667# .+159e* >86;. $6695 .8680tisfgd3 X:160rtuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuudhhhhhhhhhhhhhhgiuiuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhfi055555555555555555555555555332<>>:;:>>>,<>,>6tuuuiiuX *eq00wrryyuuuuyuuuuuyuiiasdsaputrtttuuyuyuuuuyyuupaassaiuyupsfghhhhhhhhhgdaiuy6 O967< 146q3 O865 5679O ,769wuafggfX #:150rtuuuuuuuuuuuuuuuuuuuuuuiuuuuuuuuuuushhhhhhhhhhhhfiuuuuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhfiq5555555555555555555554555431<<<,<<<<<<<15tippppa<. 0wqqetyippppppppppippaasdfgfdsapiipipppppppppppppaadddsaapasfghhhhhhhhhggfsapi+ 1678O -5589+ 176% -679, +85O rgg0 X-,36qrtuuuuuuuuuuuuiuuuuuuuuuuuuuuuuiuuuuupfghhhhhhhfauuuuuuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhat85555555555555555555555433221111111113tsssssdr >eqqetupaasaaasaasssasddfgggggfdssasassaassasaasssddffffddddfgghhhhhhhhhhhgfdd8 $878> X55601 $761 X5788o 37- -dfd@ &>,39qryuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuypsdffdspuuuuuuuuuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhfiw6555555555555555555555333332322331efffdffs+ qqwetiadfffdfddfffdfffffgghhhgggfffdfdffdfdfdfdfdfffggfggfggghhhhhhhhhhhhggggp 6666 >6699 676+ >679- =73 .yss8 .O,,159etyuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuyuyuuuuuuuuuuuuihhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhfiw7545555555555555555555545353350dgggghg4 -rqqruadfggghghhggghgghhhhhhhhhhghghhghgghghghghghghhhhhhhhghghhhhhhhhhhhhhhhg< ;669& +666q* -76, . O8686 X66$ <57qryuuuuuuuuuuuuuuuuuuuuuuuuuiuuuuuuuuiuuuuuuuuuuuuuuuuuuuuuughhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhdir955555555555555555555555555uhhhhhhhgfsuteqrtpdfhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhu X7764 . 15696 .766# . <679$. <7< oqty- %<<149etyuuuuuuuuuuuuuiuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuiuuuuuighhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhsue85555455555555555555559dhhhhhhhgfauteeriadghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh* >865X -667q# >765 668= =86% -0q1 +4357qtiasdddddddddddddddsdddddddsddddddsddddddddddddsddddddddddddshhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfaue755555555555555555ehhhhhhhhgdautrtuadghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhq ;-% +76703 O868: . >>% +975 %2* X6669wuadghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhsit06553555555555phhhhhhhggfaiuuupsfghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfO . +76680X 3869- . %986> . . X5877qtpsgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgaur065455555dhhhhhhhhgfdaapadfghghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh6 . -8767q> *7699* . . -0989; +98669qusfggfffghhhhgfffghhhhgfffghhhhgdfdghhhhgfffghhhhgfffghhhhdfffghhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgspte955fhhhhhhhhggfddddfghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhs . O3987800 5760e4 O3099997 X;996136qpdfhfuuuahhhhduuushhhhduuudhhhhduuufhhhhsuuufhhhhauuughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfahhhhhhhhhhggffggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh- X%>688780r& ,869qry< #;89999qwr3o O=58887559rdghhguuushhhhfuuishhhhduuudhhhhduuufhhhhsuuufhhhhauuufhhhhauuighhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdauq841<15566890ryupute9880ruuur3<;1156889qrtyyr41>,145670979qyfgghfuuuahhhhfuuushhhhdiuudhhhhduuudhhhhsuuufhhhhauiughhhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggdptq8433356789qrupaaite990ruppitq85345790wtypiitw84335680qe0qrugghhfuuushhhhfuuushhhhduuudhhhhsuuudhhhhauuufhhhhsuuufhhhhpuuighhhhhhhhhhhhhghhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhg7-&508666880qrtipssaiyeqqrtpsspue076699qetipsaaurq866790ettwrtphhhhfuuuahhhhfuuudhhhhduuudhhhhduuidhhhhsuuufhhhhauuifsfhhauuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhg9O550eqq0qwertuisdffsauyttupsddsayrqqqqrtupaddfdpureq0qeryiprtyahhhhfuuushhhhfuuushhhhfuuudhhhhduuudhhhhsuuufhhhhauuug;0hhauuighhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh;8saiuuttuyuipaddgggfsaiiiasffgfaaiytyuupaddgggfdpuuyyuupadauuuahhhhfiuiahhhhfiuudhhhhduuidhhhhduuufhhhhsiiufhhhhauuug>0hhpiuughhhhhhhhhhhhhhhhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhO ysaaaOt3 4dggp% %usssu& *ifssaaaasdffghOpggsOtaat- -ufggXahhpOfggOp7 .5fgfgghhhgggf9 6gggOphhhXigg9 6gggX 9gggi* *pghhO; 4@+dhhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhp*4tgffdf %&er phh+;yu&&gfg+:uu*%hgffddfffghhh uhgd tdd@%yy:+hhh uhhu hhh **tr ahhhhhhhhhhh 0uut;* hhh uu h>9hhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 0hhhhhhhhhhhhhhh 0hhhhhhhhhhhhhhh 0hhhhhhhhhhhhhh;0hhhhhh uhhhhhhh 40900hhh 40900hhhhhhhhhhhhhh@0r fhhh uhhu hhh;0hht hhh uhhhhhhhhhhhhhhhhhhhs<#hhhh#0t fhhhhhhs<#hhhh;0hhuhhh 39000hhh uy h9>hhhhhhhhhhhh", +"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh00phhhhhhhhhhhhhhh90phhhhhhhhhhhhhhh00phhhhhhhhhhhhhh;9hhhhhh uhhhhhhh@ Ohhhhhhhhhhhhhhg3 shhhhp; ;ahhha+ ;wOhhhXahhhhhhhhhhhhhhhh6 Owhhhhf4 shhhh6 Oqhhhhp$ 6hhhs; OhhhXpaOh0 + +static const int sizex=640; +static const int sizey=480; +static const int depth=8; + +static unsigned char color[256][3]={ + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0xaa }, + { 0x00, 0xaa, 0x00 }, + { 0x00, 0xaa, 0xaa }, + { 0xaa, 0x00, 0x00 }, + { 0xaa, 0x00, 0xaa }, + { 0xaa, 0x55, 0x00 }, + { 0xaa, 0xaa, 0xaa }, + { 0x55, 0x55, 0x55 }, + { 0x55, 0x55, 0xff }, + { 0x55, 0xff, 0x55 }, + { 0x55, 0xff, 0xff }, + { 0xff, 0x55, 0x55 }, + { 0xff, 0x55, 0xff }, + { 0xff, 0xff, 0x55 }, + { 0xff, 0xff, 0xff }, +}; + +FrameBufferWidget::FrameBufferWidget(QWidget *parent, const char * name) +: QWidget(parent, name, Qt::WType_TopLevel) +{ + setCaption ("OpenBIOS"); + setIcon(QPixmap(logo)); + + QPopupMenu *file = new QPopupMenu (this); + + file->insertItem( "E&xit", this, SLOT(quit()), CTRL+Key_Q ); + + QPopupMenu *help = new QPopupMenu( this ); + help->insertItem("&About OpenBIOS", this, SLOT(about()), CTRL+Key_H ); + help->insertItem( "About &Qt", this, SLOT(aboutQt()) ); + + menu = new QMenuBar( this ); + Q_CHECK_PTR( menu ); + menu->insertItem( "&File", file ); + menu->insertSeparator(); + menu->insertItem( "&Help", help ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + + setFixedSize(sizex,sizey+menu->heightForWidth(sizex)); + + buffer.create(sizex, sizey, depth, 256); + + for (int i=16; i < 256; i++) { + color[i][0]=i; + color[i][1]=i; + color[i][2]=i; + } + + for (int i=0; i< 256; i++) + buffer.setColor(i, qRgb(color[i][0], color[i][1], color[i][2])); + + buffer.fill( 0 ); + + updatetimer=new QTimer(this); + connect( updatetimer, SIGNAL(timeout()), this, SLOT(update()) ); + updatetimer->start(200,FALSE); + + setMouseTracking( TRUE ); +} + +unsigned char * FrameBufferWidget::getFrameBuffer(void) +{ + return buffer.bits(); +} + +void FrameBufferWidget::paintEvent ( QPaintEvent * ) +{ + QPainter p( this ); + p.drawImage(0,menu->heightForWidth(sizex),buffer, 0,0, sizex, sizey); +} + +void FrameBufferWidget::about() +{ + QMessageBox::about( this, "About OpenBIOS", + " Welcome to OpenBIOS 1.01\n" + " IEEE 1275-1994 Open Firmware implementation\n\n" + "written by Stefan Reinauer \n\n" + " http://www.openbios.org/\n"); +} + +void FrameBufferWidget::aboutQt() +{ + QMessageBox::aboutQt( this, "OpenBIOS" ); +} + +void FrameBufferWidget::quit() +{ + extern volatile int gui_running; + extern volatile int runforth; + + gui_running=0; + runforth=0; + + qApp->quit(); +} + +void FrameBufferWidget::update() +{ + QPainter p( this ); + p.drawImage(0,menu->heightForWidth(sizex),buffer, 0,0, sizex, sizey); +} + +void FrameBufferWidget::keyPressEvent(QKeyEvent * e) +{ + int a=e->ascii(); + if (a) { + std::cout << " key '" << e->text() << "' pressed" << std::endl; + } +} + diff --git a/arch/unix/plugins/plugin_qt/plugin_qt.h b/arch/unix/plugins/plugin_qt/plugin_qt.h new file mode 100644 index 0000000..d1a8c3a --- /dev/null +++ b/arch/unix/plugins/plugin_qt/plugin_qt.h @@ -0,0 +1,44 @@ +/* tag: qt plugin framebuffer class description + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __framebufferwidget_h +#define __framebufferwidget_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class FrameBufferWidget : public QWidget { + Q_OBJECT + public: + FrameBufferWidget(QWidget *parent=0, const char *name=0); + unsigned char *getFrameBuffer(void); + + public slots: + void quit(); + void about(); + void aboutQt(); + void update(); + + private: + QImage buffer; + QMenuBar *menu; + QStatusBar *status; + QTimer *updatetimer; + void paintEvent ( QPaintEvent * ); + protected: + void keyPressEvent(QKeyEvent * e); +}; + +#endif diff --git a/arch/unix/plugins/plugin_qt/plugin_qt.pro b/arch/unix/plugins/plugin_qt/plugin_qt.pro new file mode 100644 index 0000000..95183a8 --- /dev/null +++ b/arch/unix/plugins/plugin_qt/plugin_qt.pro @@ -0,0 +1,19 @@ +# tag: qmake project file for OpenBIOS QT plugin +# +# Copyright (C) 2003 Stefan Reinauer +# +# See the file "COPYING" for further information about +# the copyright and warranty status of this work. +# + +TEMPLATE = app +CONFIG += qt thread warn_on release +LIBS = -shared +INCLUDEPATH = qbuild $(ABSOINC) $(TOPDIR)/include $(PLUGINDIR)/plugin_pci +DESTDIR = qbuild +OBJECTS_DIR = qbuild +MOC_DIR = qbuild +TARGET = plugin_qt.so +HEADERS = $(PLUGINDIR)/plugin_qt/plugin_qt.h +SOURCES = $(PLUGINDIR)/plugin_qt/plugin_qt.cpp $(PLUGINDIR)/plugin_qt/qt_main.cpp + diff --git a/arch/unix/plugins/plugin_qt/qt_main.cpp b/arch/unix/plugins/plugin_qt/qt_main.cpp new file mode 100644 index 0000000..519c567 --- /dev/null +++ b/arch/unix/plugins/plugin_qt/qt_main.cpp @@ -0,0 +1,103 @@ +/* tag: openbios qt plugin skeleton + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + + +extern "C" { +#include +#include +#include "unix/plugins.h" +#include "unix/plugin_pci.h" +} +#include "plugin_qt.h" +#include "pciconfig.h" +#include "fcode.h" + +#define DEBUG + +volatile unsigned char * fb=0; +volatile int gui_running=0; + +typedef struct { + int argc; + char **argv; +} threaddata; + +void *gui_thread(void *ptr) +{ + threaddata *td=(threaddata *)ptr; + + QApplication a(td->argc, td->argv); + FrameBufferWidget w; + + a.setMainWidget(&w); + w.show(); + + fb=w.getFrameBuffer(); + + gui_running=-1; + a.exec(); + gui_running=0; + + return 0; +} + +extern "C" { +extern int plugin_qt_init(void); +int plugin_qt_init(void) +{ + pthread_t mythread; + char *args[]={ "plugin_qt" }; + threaddata mytd = { 1, args }; + +#ifdef DEBUG + printf("Initializing \"framebuffer\" plugin..."); +#endif + pthread_create(&mythread, NULL, gui_thread, &mytd); + while (!fb) + usleep(20); + + /* now we have the framebuffer start address. + * updating pci config space to reflect this + */ +#if (BITS > 32) + *(u32 *)(pci_config_space+0x14)=(u32)((unsigned long)fb>>32); +#else + *(u32 *)(pci_config_space+0x14)=0; +#endif + *(u32 *)(pci_config_space+0x10)=(u32)((unsigned long)fb&0xffffffff); + + /* next is to write the rom address. We write that at a random + * address in pci config space for now. + */ +#if (BITS > 32) + *(u32 *)(pci_config_space+0x34)=(u32)((unsigned long)qt_fcode>>32); +#else + *(u32 *)(pci_config_space+0x34)=0; +#endif + *(u32 *)(pci_config_space+0x30)=(u32)((unsigned long)qt_fcode&0xffffffff); + + /* FIXME: we need to put the fcode image for this + * device to the rom resource, once it exists + */ + + /* register pci device to be available to beginagain */ + pci_register_device(0, 2, 0, pci_config_space); + +#ifdef DEBUG + printf("done.\n"); +#endif + return 0; +} + +PLUGIN_AUTHOR("Stefan Reinauer ") +PLUGIN_DESCRIPTION("QT gui plugin emulating framebuffer device") +PLUGIN_LICENSE("GPL v2") +PLUGIN_DEPENDENCIES("pci") + +} + diff --git a/arch/unix/plugins/plugin_qt/qt_rom.fs b/arch/unix/plugins/plugin_qt/qt_rom.fs new file mode 100644 index 0000000..1879c36 --- /dev/null +++ b/arch/unix/plugins/plugin_qt/qt_rom.fs @@ -0,0 +1,85 @@ +\ tag: Property management +\ +\ this code implements an IEEE 1275-1994 fcode driver +\ for the OpenBIOS qt interface +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +hex + +tokenizer[ 1002 4336 0300 23 ]tokenizer ( -- vid did classid revision ) + +pci-revision + +pci-header + +fcode-version2 +headers + +" dev /pci" evaluate +new-device + + " ATY,QTEMU" device-name + " display" device-type + + " iso8859-1" encode-string + " character-set" property + + true encode-int + " iso6429-1983-colors" property + + : qt-open + \ [..] + ." opening framebuffer device." cr + 10 10 " pci-l@" evaluate + /n 8 = if + 10 14 " pci-l@" evaluate + 20 << or + then + ." framebuffer pointer is at 0x" dup . cr + to frame-buffer-adr + default-font set-font + d# 640 d# 480 d# 80 d# 30 fb8-install + true + ; + + : qt-close + ." QT Interface closed." cr + 0 to frame-buffer-adr + ; + + : qt-selftest + ." QT Interface selftest" cr + 0 + ; + + ['] qt-open is-install + ['] qt-close is-remove + ['] qt-selftest is-selftest + + external + +\ the following words will be defined by fb8-install +\ + +\ : open ( -- true ) +\ ; + +\ : write ( addr len -- actual ) +\ ; + +\ : draw-logo ( line# addr width height -- ) +\ ; + +\ : restore ( -- ) +\ ; + +finish-device + +fcode-end + +pci-end diff --git a/arch/unix/tree.fs b/arch/unix/tree.fs new file mode 100644 index 0000000..a7529b0 --- /dev/null +++ b/arch/unix/tree.fs @@ -0,0 +1,116 @@ +:noname + ." Type 'help' for detailed information" cr + ; DIAG-initializer + +" /" find-device + +new-device + " memory" device-name + \ 12230 encode-int " reg" property + external + : open true ; + : close ; + \ claim ( phys size align -- base ) + \ release ( phys size -- ) +finish-device + +new-device + " cpus" device-name + 1 " #address-cells" int-property + 0 " #size-cells" int-property + + external + : open true ; + : close ; + : decode-unit parse-hex ; + +finish-device + +: make-openable ( path ) + find-dev if + begin ?dup while + \ install trivial open and close methods + dup active-package! is-open + parent + repeat + then +; + +: preopen ( chosen-str node-path ) + 2dup make-openable + + " /chosen" find-device + open-dev ?dup if + encode-int 2swap property + else + 2drop + then +; + +:noname + set-defaults +; SYSTEM-initializer + + +\ preopen device nodes (and store the ihandles under /chosen) +:noname + " memory" " /memory" preopen + " mmu" " /cpus/@0" preopen + " stdout" " /builtin/console" preopen + " stdin" " /builtin/console" preopen + device-end +; SYSTEM-initializer + +\ use the tty interface if available +:noname + " /builtin/console" find-dev if drop + " /builtin/console" " input-device" $setenv + " /builtin/console" " output-device" $setenv + then +; SYSTEM-initializer + +:noname + " keyboard" input +; CONSOLE-IN-initializer + +dev / + +\ node suitable for non-PCI devices +new-device + " unix" device-name + 0 encode-int " #address-cells" property + 0 encode-int " #size-cells" property + + external + : open true ; + : close ; + +\ block device node +new-device + " block" device-name + " unix-block" device-type + 1 " #address-cells" int-property + 0 " #size-cells" int-property + + external + : open true ; + : close ; + : decode-unit parse-hex ; + +\ testnode +\ new-device +\ " kappa" device-name +\ +\ 1 encode-int " reg" property +\ external +\ : open true ; +\ : close ; +\ finish-device + +finish-device +finish-device + +dev /aliases +" /unix/block/disk" encode-string " hd" property + +device-end diff --git a/arch/unix/unix.c b/arch/unix/unix.c new file mode 100644 index 0000000..609f0a2 --- /dev/null +++ b/arch/unix/unix.c @@ -0,0 +1,517 @@ +/* tag: hosted forth environment, executable code + * + * Copyright (C) 2003-2005 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include +#include +#include +#include +#include +#define __USE_LARGEFILE64 +#include +#include +#include +#include +#include +#include + +#ifdef __GLIBC__ +#define _GNU_SOURCE +#include +#endif + +#include "openbios/sysinclude.h" +#include "mconfig.h" +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "dict.h" +#include "openbios/stack.h" +#include "unix/plugins.h" +#include "openbios/bindings.h" + +#include "blk.h" + +#define MEMORY_SIZE (4*1024*1024) /* 4M ram for hosted system */ +#define DICTIONARY_SIZE (256*1024) /* 256k for the dictionary */ + +#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64) +#define lseek lseek64 +#define __LFS O_LARGEFILE +#else +#define __LFS 0 +#endif + +/* prototypes */ +static void exit_terminal(void); +void boot(void); + +/* local variables */ + +ucell *latest, *state; +ucell *memory; + +int diskemu; + +static int segfault = 0; +int verbose = 0; + +int errno_int; /* implement for fs drivers, needed to build on Mac OS X */ + +#if 0 +static void write_dictionary(char *filename) +{ + FILE *f; + xt_t initxt; + + initxt = findword("initialize-of"); + if (!initxt) + printk("warning: dictionary needs word called initialize-of\n"); + + f = fopen(filename, "w"); + if (!f) { + printk("panic: can't open dictionary.\n"); + exit_terminal(); + exit(1); + } + + fwrite(DICTID, 16, 1, f); + fwrite(dict, dicthead, 1, f); + + /* Write start address and last to relocate on load */ + fwrite(&dict, sizeof(ucell), 1, f); + fwrite(&last, sizeof(ucell), 1, f); + + fclose(f); + +#ifdef CONFIG_DEBUG_DICTIONARY + printk("wrote dictionary to file %s.\n", filename); +#endif +} +#endif + +static ucell read_dictionary(char *fil) +{ + int ilen; + ucell ret; + char *mem; + FILE *f; + struct stat finfo; + + if (stat(fil, &finfo)) + return 0; + + ilen = finfo.st_size; + + if ((mem = malloc(ilen)) == NULL) { + printk("panic: not enough memory.\n"); + exit_terminal(); + exit(1); + } + + f = fopen(fil, "r"); + if (!f) { + printk("panic: can't open dictionary.\n"); + exit_terminal(); + exit(1); + } + + if (fread(mem, ilen, 1, f) != 1) { + printk("panic: can't read dictionary.\n"); + fclose(f); + exit_terminal(); + exit(1); + } + fclose(f); + + ret = load_dictionary(mem, ilen); + + free(mem); + return ret; +} + + +/* + * functions used by primitives + */ + +int availchar(void) +{ + int tmp = getc(stdin); + if (tmp != EOF) { + ungetc(tmp, stdin); + return -1; + } + return 0; +} + +u8 inb(u32 reg) +{ +#ifdef CONFIG_PLUGINS + io_ops_t *ior = find_iorange(reg); + if (ior) + return ior->inb(reg); +#endif + + printk("TRAP: io byte read @0x%x", reg); + return 0xff; +} + +u16 inw(u32 reg) +{ +#ifdef CONFIG_PLUGINS + io_ops_t *ior = find_iorange(reg); + if (ior) + return ior->inw(reg); +#endif + + printk("TRAP: io word read @0x%x", reg); + return 0xffff; +} + +u32 inl(u32 reg) +{ +#ifdef CONFIG_PLUGINS + io_ops_t *ior = find_iorange(reg); + if (ior) + return ior->inl(reg); +#endif + + printk("TRAP: io long read @0x%x", reg); + return 0xffffffff; +} + +void outb(u32 reg, u8 val) +{ +#ifdef CONFIG_PLUGINS + io_ops_t *ior = find_iorange(reg); + if (ior) { + ior->outb(reg, val); + return; + } +#endif + + printk("TRAP: io byte write 0x%x -> 0x%x", val, reg); +} + +void outw(u32 reg, u16 val) +{ +#ifdef CONFIG_PLUGINS + io_ops_t *ior = find_iorange(reg); + if (ior) { + ior->outw(reg, val); + return; + } +#endif + printk("TRAP: io word write 0x%x -> 0x%x", val, reg); +} + +void outl(u32 reg, u32 val) +{ +#ifdef CONFIG_PLUGINS + io_ops_t *ior = find_iorange(reg); + if (ior) { + ior->outl(reg, val); + return; + } +#endif + printk("TRAP: io long write 0x%x -> 0x%x", val, reg); +} + +/* + * terminal initialization and cleanup. + */ + +static void init_terminal(void) +{ + struct termios termios; + + tcgetattr(0, &termios); + termios.c_lflag &= ~(ICANON | ECHO); + tcsetattr(0, 0, &termios); +} + +static void exit_terminal(void) +{ + struct termios termios; + + tcgetattr(0, &termios); + termios.c_lflag |= (ICANON | ECHO); + tcsetattr(0, 0, &termios); +} + +/* + * segmentation fault handler. linux specific? + */ + +static void +segv_handler(int signo __attribute__ ((unused)), + siginfo_t * si, void *context __attribute__ ((unused))) +{ + static int count = 0; + ucell addr = 0xdeadbeef; + + if (count) { + printk("Died while dumping forth dictionary core.\n"); + goto out; + } + + count++; + + if (PC >= (ucell) dict && PC <= (ucell) dict + dicthead) + addr = *(ucell *) PC; + + printk("panic: segmentation violation at %x\n", (ucell)si->si_addr); + printk("dict=0x%x here=0x%x(dict+0x%x) pc=0x%x(dict+0x%x)\n", + (ucell)dict, (ucell)dict + dicthead, dicthead, PC, PC - (ucell) dict); + printk("dstackcnt=%d rstackcnt=%d instruction=%x\n", + dstackcnt, rstackcnt, addr); + +#ifdef CONFIG_DEBUG_DSTACK + printdstack(); +#endif +#ifdef CONFIG_DEBUG_RSTACK + printrstack(); +#endif +#if 0 + printk("Writing dictionary core file\n"); + write_dictionary("forth.dict.core"); +#endif + + out: + exit_terminal(); + exit(1); +} + +/* + * allocate memory and prepare engine for memory management. + */ + +static void init_memory(void) +{ + memory = malloc(MEMORY_SIZE); + if (!memory) { + printk("panic: not enough memory on host system.\n"); + exit_terminal(); + exit(1); + } + + memset (memory, 0, MEMORY_SIZE); + /* we push start and end of memory to the stack + * so that it can be used by the forth word QUIT + * to initialize the memory allocator + */ + + PUSH((ucell) memory); + PUSH((ucell) memory + MEMORY_SIZE); +} + +void exception(cell no) +{ + /* + * this is a noop since the dictionary has to take care + * itself of errors it generates outside of the bootstrap + */ +} + +static void +arch_init( void ) +{ + modules_init(); + if(diskemu!=-1) + blk_init(); + + device_end(); + bind_func("platform-boot", boot); +} + +int +read_from_disk( int channel, int unit, int blk, unsigned long mphys, int size ) +{ + // channels and units not supported yet. + unsigned char *buf=(unsigned char *)mphys; + + if(diskemu==-1) + return -1; + + //printk("read: ch=%d, unit=%d, blk=%ld, phys=%lx, size=%d\n", + // channel, unit, blk, mphys, size); + + lseek(diskemu, (ducell)blk*512, SEEK_SET); + read(diskemu, buf, size); + + return 0; +} + +/* + * main loop + */ + +#define BANNER "OpenBIOS core. (C) 2003-2005 Patrick Mauritz, Stefan Reinauer\n"\ + "This software comes with absolutely no warranty. "\ + "All rights reserved.\n\n" + + +#define USAGE "usage: %s [options] [dictionary file|source file]\n\n" + +int main(int argc, char *argv[]) +{ + struct sigaction sa; +#if 0 + unsigned char *dictname = NULL; +#endif + int c; + + const char *optstring = "VvhsD:P:p:f:?"; + + while (1) { +#ifdef __GLIBC__ + int option_index = 0; + static struct option long_options[] = { + {"version", 0, NULL, 'V'}, + {"verbose", 0, NULL, 'v'}, + {"help", 0, NULL, 'h'}, +// {"dictionary", 1, NULL, 'D'}, + {"segfault", 0, NULL, 's'}, +#ifdef CONFIG_PLUGINS + {"plugin-path", 1, NULL, 'P'}, + {"plugin", 1, NULL, 'p'}, +#endif + {"file", 1, NULL, 'f'} + }; + + c = getopt_long(argc, argv, optstring, long_options, + &option_index); +#else + c = getopt(argc, argv, optstring); +#endif + if (c == -1) + break; + + switch (c) { + case 'V': + printk(BANNER "Version " VERSION "\n"); + return 0; + case 'h': + case '?': + printk(BANNER "Version " VERSION "\n" USAGE, argv[0]); + return 0; + case 'v': + verbose = 1; + break; + case 's': + segfault = 1; + break; +#if 0 + case 'D': + printk("Dumping final dictionary to '%s'\n", optarg); + dictname = optarg; + break; +#endif +#ifdef CONFIG_PLUGINS + case 'P': + printk("Plugin search path is now '%s'\n", optarg); + plugindir = optarg; + break; + case 'p': + printk("Loading plugin %s\n", optarg); + load_plugin(optarg); + break; +#endif + case 'f': + diskemu=open(optarg, O_RDONLY|__LFS); + if(diskemu!=-1) + printk("Using %s as harddisk.\n", optarg); + else + printk("%s not found. no harddisk node.\n", + optarg); + break; + default: + return 1; + } + } + + if (argc < optind + 1) { + printk(USAGE, argv[0]); + return 1; + } + + if ((dict = (unsigned char *) malloc(DICTIONARY_SIZE)) == NULL) { + printk("panic: not enough memory.\n"); + return 1; + } + + memset(dict, 0, DICTIONARY_SIZE); + + if (!segfault) { + if (verbose) + printk("Installing SIGSEGV handler..."); + + sa.sa_sigaction = segv_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_NODEFER; + sigaction(SIGSEGV, &sa, 0); + + if (verbose) + printk("done.\n"); + } + + /* set terminal to do non blocking reads */ + init_terminal(); + read_dictionary(argv[optind]); + + PUSH_xt( bind_noname_func(arch_init) ); + fword("PREPOST-initializer"); + + PC = (cell)findword("initialize-of"); + if (PC) { + if (verbose) { + if (optind + 1 != argc) + printk("Warning: only first dictionary used.\n"); + + printk("dictionary loaded (%d bytes).\n", dicthead); + printk("Initializing memory..."); + } + init_memory(); + + if (verbose) { + printk("done\n"); + + printk("Jumping to dictionary..."); + } + + enterforth((xt_t)PC); +#if 0 + if (dictname != NULL) + write_dictionary(dictname); +#endif + + free(memory); + + } else { /* input file is not a dictionary */ + printk("not supported.\n"); + } + + exit_terminal(); + if (diskemu!=-1) + close(diskemu); + + free(dict); + return 0; +} + +#undef printk +int +printk( const char *fmt, ... ) +{ + int i; + + va_list args; + va_start( args, fmt ); + i = vprintf(fmt, args ); + va_end( args ); + return i; +} diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig new file mode 100644 index 0000000..6e733cb --- /dev/null +++ b/arch/x86/Kconfig @@ -0,0 +1,49 @@ +mainmenu "OpenBIOS Configuration" + +config X86 + bool + default y + help + Building for X86 hardware. + +config LITTLE_ENDIAN + bool + default y + help + X86 is little endian + +menu "Kernel binaries (x86)" + +config IMAGE_ELF + bool "ELF image (for LinuxBIOS)" + default y + help + Build a simple elf image that can be used with LinuxBIOS + This image will be called openbios.elf + +config IMAGE_ELF_EMBEDDED + bool "ELF image with embedded dictionary" + default y + help + Build an elf image with embedded dictionary. This image + can easily be used with etherboot. + The image filename is openbios.full + +config IMAGE_ELF_MULTIBOOT + bool "Multiboot image" + default y + help + Build a multiboot image for booting with grub + +endmenu + +menu "Build hosted UNIX Binary" +source "arch/unix/Kconfig" +endmenu + +source "kernel/Kconfig" +source "forth/Kconfig" +source "modules/Kconfig" +source "drivers/Kconfig" + + diff --git a/arch/x86/boot.c b/arch/x86/boot.c new file mode 100644 index 0000000..3c5cad4 --- /dev/null +++ b/arch/x86/boot.c @@ -0,0 +1,53 @@ +/* tag: openbios boot command for x86 + * + * Copyright (C) 2003-2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#undef BOOTSTRAP +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/elfload.h" +#include "openbios/nvram.h" +#include "libc/diskio.h" +#include "sys_info.h" +#include "boot.h" + +int elf_load(struct sys_info *, const char *filename, const char *cmdline); +int linux_load(struct sys_info *, const char *filename, const char *cmdline); + +void boot(void); + +struct sys_info sys_info; + +void boot(void) +{ + char *path=pop_fstr_copy(), *param; + + if(!path) { + printk("[x86] Booting default not supported.\n"); + return; + } + + param = strchr(path, ' '); + if(param) { + *param = '\0'; + param++; + } + + printk("[x86] Booting file '%s' with parameters '%s'\n",path, param); + + if (elf_load(&sys_info, path, param) != LOADER_NOT_SUPPORT) + goto loaded; + if (linux_load(&sys_info, path, param) != LOADER_NOT_SUPPORT) + goto loaded; + if (forth_load(&sys_info, path, param) != LOADER_NOT_SUPPORT) + goto loaded; + + printk("Unsupported image format\n"); + +loaded: + free(path); +} diff --git a/arch/x86/boot.h b/arch/x86/boot.h new file mode 100644 index 0000000..ce823be --- /dev/null +++ b/arch/x86/boot.h @@ -0,0 +1,14 @@ +/* tag: openbios loader prototypes for x86 + * + * Copyright (C) 2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +int forth_load(struct sys_info *info, const char *filename, const char *cmdline); +int elf_load(struct sys_info *info, const char *filename, const char *cmdline); +int linux_load(struct sys_info *info, const char *file, const char *cmdline); + +unsigned int start_elf(unsigned long entry_point, unsigned long param); + diff --git a/arch/x86/build.xml b/arch/x86/build.xml new file mode 100644 index 0000000..f25841c --- /dev/null +++ b/arch/x86/build.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + $(LD) -N -T arch/x86/ldscript -o $@.nostrip $^ \ + $(shell $(CC) -print-libgcc-file-name) + $(NM) $@.nostrip | sort > $(ODIR)/openbios-multiboot.syms + cp $@.nostrip $@ + $(STRIP) $@ + + + + + + + + + + + + + + $(LD) -N -T arch/x86/ldscript -o $@.nostrip $^ \ + $(shell $(CC) -print-libgcc-file-name) + $(NM) $@.nostrip | sort > $(ODIR)/openbios-plain.syms + cp $@.nostrip $@ + $(STRIP) $@ + + + + + + + + + + + + + + + $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@ + ]]> + + + + + + + + + + + + + $(LD) -N -T arch/x86/ldscript -o $@.nostrip $^ \ + $(shell $(CC) -print-libgcc-file-name) + $(NM) $@.nostrip | sort > $(ODIR)/openbios-builtin.syms + cp $@.nostrip $@ + $(STRIP) $@ + + + + + + + + + + + + diff --git a/arch/x86/builtin.c b/arch/x86/builtin.c new file mode 100644 index 0000000..384ed8d --- /dev/null +++ b/arch/x86/builtin.c @@ -0,0 +1,25 @@ +/* tag: openbios forth starter for builtin dictionary + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "sys_info.h" + +/* + * wrap an array around the hex'ed dictionary file + */ + +#include "static-dict.h" + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ + info->dict_start=(unsigned long *)forth_dictionary; + info->dict_end=(unsigned long *)((ucell)forth_dictionary + + sizeof(forth_dictionary)); +} + diff --git a/arch/x86/console.c b/arch/x86/console.c new file mode 100644 index 0000000..346e659 --- /dev/null +++ b/arch/x86/console.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2003, 2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios.h" + +#ifdef CONFIG_DEBUG_CONSOLE + +/* ****************************************************************** + * serial console functions + * ****************************************************************** */ + +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + +#define RBR(x) x==2?0x2f8:0x3f8 +#define THR(x) x==2?0x2f8:0x3f8 +#define IER(x) x==2?0x2f9:0x3f9 +#define IIR(x) x==2?0x2fa:0x3fa +#define LCR(x) x==2?0x2fb:0x3fb +#define MCR(x) x==2?0x2fc:0x3fc +#define LSR(x) x==2?0x2fd:0x3fd +#define MSR(x) x==2?0x2fe:0x3fe +#define SCR(x) x==2?0x2ff:0x3ff +#define DLL(x) x==2?0x2f8:0x3f8 +#define DLM(x) x==2?0x2f9:0x3f9 + +static int uart_charav(int port) +{ + if (!port) + return -1; + return ((inb(LSR(port)) & 1) != 0); +} + +static char uart_getchar(int port) +{ + if (!port) + return -1; + while (!uart_charav(port)); + return ((char) inb(RBR(port)) & 0177); +} + +static void uart_putchar(int port, unsigned char c) +{ + if (!port) + return; + if (c == '\n') + uart_putchar(port, '\r'); + while (!(inb(LSR(port)) & 0x20)); + outb(c, THR(port)); +} + +static void uart_init_line(int port, unsigned long baud) +{ + int i, baudconst; + + if (!port) + return; + + switch (baud) { + case 115200: + baudconst = 1; + break; + case 57600: + baudconst = 2; + break; + case 38400: + baudconst = 3; + break; + case 19200: + baudconst = 6; + break; + case 9600: + default: + baudconst = 12; + break; + } + + outb(0x87, LCR(port)); + outb(0x00, DLM(port)); + outb(baudconst, DLL(port)); + outb(0x07, LCR(port)); + outb(0x0f, MCR(port)); + + for (i = 10; i > 0; i--) { + if (inb(LSR(port)) == (unsigned int) 0) + break; + inb(RBR(port)); + } +} + +int uart_init(int port, unsigned long speed) +{ + if (port) + uart_init_line(port, speed); + return -1; +} + +static void serial_putchar(int c) +{ + uart_putchar(CONFIG_SERIAL_PORT, (unsigned char) (c & 0xff)); +} + +static void serial_cls(void) +{ + serial_putchar(27); + serial_putchar('['); + serial_putchar('H'); + serial_putchar(27); + serial_putchar('['); + serial_putchar('J'); +} + +#endif + +/* ****************************************************************** + * simple polling video/keyboard console functions + * ****************************************************************** */ + +#ifdef CONFIG_DEBUG_CONSOLE_VGA + +/* raw vga text mode */ +#define COLUMNS 80 /* The number of columns. */ +#define LINES 25 /* The number of lines. */ +#define ATTRIBUTE 7 /* The attribute of an character. */ + +#define VGA_BASE 0xB8000 /* The video memory address. */ + +/* VGA Index and Data Registers */ +#define VGA_REG_INDEX 0x03D4 /* VGA index register */ +#define VGA_REG_DATA 0x03D5 /* VGA data register */ + +#define VGA_IDX_CURMSL 0x09 /* cursor maximum scan line */ +#define VGA_IDX_CURSTART 0x0A /* cursor start */ +#define VGA_IDX_CUREND 0x0B /* cursor end */ +#define VGA_IDX_CURLO 0x0F /* cursor position (low 8 bits) */ +#define VGA_IDX_CURHI 0x0E /* cursor position (high 8 bits) */ + +/* Save the X and Y position. */ +static int xpos, ypos; +/* Point to the video memory. */ +static volatile unsigned char *video = (unsigned char *) VGA_BASE; + +static void video_initcursor(void) +{ + u8 val; + outb(VGA_IDX_CURMSL, VGA_REG_INDEX); + val = inb(VGA_REG_DATA) & 0x1f; /* maximum scan line -1 */ + + outb(VGA_IDX_CURSTART, VGA_REG_INDEX); + outb(0, VGA_REG_DATA); + + outb(VGA_IDX_CUREND, VGA_REG_INDEX); + outb(val, VGA_REG_DATA); +} + + + +static void video_poscursor(unsigned int x, unsigned int y) +{ + unsigned short pos; + + /* Calculate new cursor position as a function of x and y */ + pos = (y * COLUMNS) + x; + + /* Output the new position to VGA card */ + outb(VGA_IDX_CURLO, VGA_REG_INDEX); /* output low 8 bits */ + outb((u8) (pos), VGA_REG_DATA); + outb(VGA_IDX_CURHI, VGA_REG_INDEX); /* output high 8 bits */ + outb((u8) (pos >> 8), VGA_REG_DATA); + +}; + + +static void video_newline(void) +{ + xpos = 0; + + if (ypos < LINES - 1) { + ypos++; + } else { + int i; + memmove((void *) video, (void *) (video + 2 * COLUMNS), + (LINES - 1) * COLUMNS * 2); + + for (i = ((LINES - 1) * 2 * COLUMNS); + i < 2 * COLUMNS * LINES;) { + video[i++] = 0; + video[i++] = ATTRIBUTE; + } + } + +} + +/* Put the character C on the screen. */ +static void video_putchar(int c) +{ + int p=1; + + if (c == '\n' || c == '\r') { + video_newline(); + return; + } + + if (c == '\b') { + if (xpos) xpos--; + c=' '; + p=0; + } + + + if (xpos >= COLUMNS) + video_newline(); + + *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF; + *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE; + + if (p) + xpos++; + + video_poscursor(xpos, ypos); +} + +static void video_cls(void) +{ + int i; + + for (i = 0; i < 2 * COLUMNS * LINES;) { + video[i++] = 0; + video[i++] = ATTRIBUTE; + } + + + xpos = 0; + ypos = 0; + + video_initcursor(); + video_poscursor(xpos, ypos); +} + +void video_init(void) +{ + video=phys_to_virt((unsigned char*)VGA_BASE); +} + +/* + * keyboard driver + */ + +static char normal[] = { + 0x0, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', + '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', + 'p', '[', ']', 0xa, 0x0, 'a', 's', 'd', 'f', 'g', 'h', 'j', + 'k', 'l', ';', 0x27, 0x60, 0x0, 0x5c, 'z', 'x', 'c', 'v', 'b', + 'n', 'm', ',', '.', '/', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '0', 0x7f +}; + +static char shifted[] = { + 0x0, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', + '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', + 'P', '{', '}', 0xa, 0x0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', + 'K', 'L', ':', 0x22, '~', 0x0, '|', 'Z', 'X', 'C', 'V', 'B', + 'N', 'M', '<', '>', '?', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '7', '8', + '9', 0x0, '4', '5', '6', 0x0, '1', '2', '3', '0', 0x7f +}; + +static int key_ext; +static int key_lshift = 0, key_rshift = 0, key_caps = 0; + +static char last_key; + +static void keyboard_cmd(unsigned char cmd, unsigned char val) +{ + outb(cmd, 0x60); + /* wait until keyboard controller accepts cmds: */ + while (inb(0x64) & 2); + outb(val, 0x60); + while (inb(0x64) & 2); +} + +static char keyboard_poll(void) +{ + unsigned int c; + if (inb(0x64) & 1) { + c = inb(0x60); + switch (c) { + case 0xe0: + key_ext = 1; + return 0; + case 0x2a: + key_lshift = 1; + return 0; + case 0x36: + key_rshift = 1; + return 0; + case 0xaa: + key_lshift = 0; + return 0; + case 0xb6: + key_rshift = 0; + return 0; + case 0x3a: + if (key_caps) { + key_caps = 0; + keyboard_cmd(0xed, 0); + } else { + key_caps = 1; + keyboard_cmd(0xed, 4); /* set caps led */ + } + return 0; + } + + if (key_ext) { + // void printk(const char *format, ...); + printk("extended keycode: %x\n", c); + + key_ext = 0; + return 0; + } + + if (c & 0x80) /* unhandled key release */ + return 0; + + if (key_lshift || key_rshift) + return key_caps ? normal[c] : shifted[c]; + else + return key_caps ? shifted[c] : normal[c]; + } + return 0; +} + +static int keyboard_dataready(void) +{ + if (last_key) + return 1; + + last_key = keyboard_poll(); + + return (last_key != 0); +} + +static unsigned char keyboard_readdata(void) +{ + char tmp; + while (!keyboard_dataready()); + tmp = last_key; + last_key = 0; + return tmp; +} +#endif + + +/* ****************************************************************** + * common functions, implementing simple concurrent console + * ****************************************************************** */ + +int putchar(int c) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + serial_putchar(c); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + video_putchar(c); +#endif + return c; +} + +int availchar(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + if (uart_charav(CONFIG_SERIAL_PORT)) + return 1; +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + if (keyboard_dataready()) + return 1; +#endif + return 0; +} + +int getchar(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + if (uart_charav(CONFIG_SERIAL_PORT)) + return (uart_getchar(CONFIG_SERIAL_PORT)); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + if (keyboard_dataready()) + return (keyboard_readdata()); +#endif + return 0; +} + +void cls(void) +{ +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + serial_cls(); +#endif +#ifdef CONFIG_DEBUG_CONSOLE_VGA + video_cls(); +#endif +} + + +#endif // CONFIG_DEBUG_CONSOLE diff --git a/arch/x86/context.c b/arch/x86/context.c new file mode 100644 index 0000000..62d816a --- /dev/null +++ b/arch/x86/context.c @@ -0,0 +1,131 @@ +/* tag: x86 context switching + * + * 2003-10 by SONE Takeshi + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "segment.h" +#include "context.h" +#include "sys_info.h" +#include "boot.h" + +#define MAIN_STACK_SIZE 16384 +#define IMAGE_STACK_SIZE 4096 + +#define debug printk + +static void start_main(void); /* forward decl. */ +void __exit_context(void); /* assembly routine */ + +/* + * Main context structure + * It is placed at the bottom of our stack, and loaded by assembly routine + * to start us up. + */ +struct context main_ctx __attribute__((section (".initctx"))) = { + .gdt_base = (uint32_t) gdt, + .gdt_limit = GDT_LIMIT, + .cs = FLAT_CS, + .ds = FLAT_DS, + .es = FLAT_DS, + .fs = FLAT_DS, + .gs = FLAT_DS, + .ss = FLAT_DS, + .esp = (uint32_t) ESP_LOC(&main_ctx), + .eip = (uint32_t) start_main, + .return_addr = (uint32_t) __exit_context, +}; + +/* This is used by assembly routine to load/store the context which + * it is to switch/switched. */ +struct context *__context = &main_ctx; + +/* Stack for loaded ELF image */ +static uint8_t image_stack[IMAGE_STACK_SIZE]; + +/* Pointer to startup context (physical address) */ +unsigned long __boot_ctx; + +/* + * Main starter + * This is the C function that runs first. + */ +static void start_main(void) +{ + int retval; + extern int openbios(void); + extern void init_exceptions(void); + + /* Save startup context, so we can refer to it later. + * We have to keep it in physical address since we will relocate. */ + __boot_ctx = virt_to_phys(__context); + + init_exceptions(); + /* Start the real fun */ + retval = openbios(); + + /* Pass return value to startup context. Bootloader may see it. */ + boot_ctx->eax = retval; + + /* Returning from here should jump to __exit_context */ + __context = boot_ctx; +} + +/* Setup a new context using the given stack. + */ +struct context * +init_context(uint8_t *stack, uint32_t stack_size, int num_params) +{ + struct context *ctx; + + ctx = (struct context *) + (stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t))); + memset(ctx, 0, sizeof(*ctx)); + + /* Fill in reasonable default for flat memory model */ + ctx->gdt_base = virt_to_phys(gdt); + ctx->gdt_limit = GDT_LIMIT; + ctx->cs = FLAT_CS; + ctx->ds = FLAT_DS; + ctx->es = FLAT_DS; + ctx->fs = FLAT_DS; + ctx->gs = FLAT_DS; + ctx->ss = FLAT_DS; + ctx->esp = virt_to_phys(ESP_LOC(ctx)); + ctx->return_addr = virt_to_phys(__exit_context); + + return ctx; +} + +/* Switch to another context. */ +struct context *switch_to(struct context *ctx) +{ + struct context *save, *ret; + + debug("switching to new context:\n"); + save = __context; + __context = ctx; + asm ("pushl %cs; call __switch_context"); + ret = __context; + __context = save; + return ret; +} + +/* Start ELF Boot image */ +unsigned int start_elf(unsigned long entry_point, unsigned long param) +{ + struct context *ctx; + + ctx = init_context(image_stack, sizeof image_stack, 1); + ctx->eip = entry_point; + ctx->param[0] = param; + ctx->eax = 0xe1fb007; + ctx->ebx = param; + + ctx = switch_to(ctx); + return ctx->eax; +} diff --git a/arch/x86/context.h b/arch/x86/context.h new file mode 100644 index 0000000..6a1c5ad --- /dev/null +++ b/arch/x86/context.h @@ -0,0 +1,48 @@ +#ifndef i386_CONTEXT_H +#define i386_CONTEXT_H + +struct context { + /* Stack Segment, placed here because of the alignment issue... */ + uint16_t ss; + /* Used with sgdt/lgdt */ + uint16_t gdt_limit; + uint32_t gdt_base; + /* General registers, accessed with pushal/popal */ + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; /* points just below eax */ + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; +#define ESP_LOC(ctx) (&(ctx)->gs) + /* Segment registers */ + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + /* Flags */ + uint32_t eflags; + /* Code segment:offset */ + uint32_t eip; + uint32_t cs; + /* Optional stack contents */ + uint32_t return_addr; + uint32_t param[0]; +}; + +/* Create a new context in the given stack */ +struct context * +init_context(uint8_t *stack, uint32_t stack_size, int num_param); + +/* Switch context */ +struct context *switch_to(struct context *); + +/* Holds physical address of boot context */ +extern unsigned long __boot_ctx; + +/* This can always be safely used to refer to the boot context */ +#define boot_ctx ((struct context *) phys_to_virt(__boot_ctx)) + +#endif /* i386_CONTEXT_H */ diff --git a/arch/x86/defconfig b/arch/x86/defconfig new file mode 100644 index 0000000..b0a02ab --- /dev/null +++ b/arch/x86/defconfig @@ -0,0 +1,65 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_X86=y +CONFIG_LITTLE_ENDIAN=y + +# +# Kernel binaries (x86) +# +CONFIG_IMAGE_ELF=y +CONFIG_IMAGE_ELF_EMBEDDED=y +CONFIG_IMAGE_ELF_MULTIBOOT=y + +# +# Build hosted UNIX Binary +# +CONFIG_HOST_UNIX=y +# CONFIG_PLUGIN_PCI is not set + +# +# Kernel Debugging +# +# CONFIG_DEBUG is not set +CONFIG_DEBUG_CONSOLE=y +CONFIG_DEBUG_CONSOLE_SERIAL=y +CONFIG_SERIAL_PORT=1 +CONFIG_SERIAL_SPEED=115200 +CONFIG_DEBUG_CONSOLE_VGA=y + +# +# Module Configuration +# +CONFIG_CMDLINE=y +CONFIG_DEBLOCKER=y + +# +# Filesystem Configuration +# +CONFIG_DISK_LABEL=y +CONFIG_PART_SUPPORT=y +CONFIG_PC_PARTS=y +CONFIG_FS=y +CONFIG_GRUBFS=y +CONFIG_FSYS_EXT2FS=y +CONFIG_FSYS_FAT=y +CONFIG_FSYS_JFS=y +# CONFIG_FSYS_MINIX is not set +CONFIG_FSYS_REISERFS=y +CONFIG_FSYS_XFS=y +CONFIG_FSYS_ISO9660=y +# CONFIG_FSYS_FFS is not set +# CONFIG_FSYS_VSTAFS is not set +# CONFIG_DEBUG_FS is not set + +# +# Miscellaneous +# +CONFIG_LINUXBIOS=y + +# +# Drivers +# +CONFIG_DRIVER_PCI=y +CONFIG_DRIVER_IDE=y +# CONFIG_DEBUG_IDE is not set diff --git a/arch/x86/elfload.c b/arch/x86/elfload.c new file mode 100644 index 0000000..717a90d --- /dev/null +++ b/arch/x86/elfload.c @@ -0,0 +1,393 @@ +/* ELF Boot loader + * As we have seek, this implementation can be straightforward. + * 2003-07 by SONE Takeshi + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/elf.h" +#include "asm/elf.h" +#include "elf_boot.h" +#include "sys_info.h" +#include "ipchecksum.h" +#include "loadfs.h" +#include "boot.h" + +#define debug printk + +/* FreeBSD and possibly others mask the high 8 bits */ +#define ADDRMASK 0x00ffffff +/* #define ADDRMASK 0xffffffff // old behavior */ + +extern unsigned int start_elf(unsigned long entry_point, unsigned long param); +extern char _start, _end; + +static char *image_name, *image_version; + +static void *calloc(size_t nmemb, size_t size) +{ + size_t alloc_size = nmemb * size; + void *mem; + + if (alloc_size < nmemb || alloc_size < size) { + printk("calloc overflow: %u, %u\n", nmemb, size); + return 0; + } + + mem = malloc(alloc_size); + memset(mem, 0, alloc_size); + + return mem; +} + + +static int check_mem_ranges(struct sys_info *info, + Elf_phdr *phdr, int phnum) +{ + int i, j; + unsigned long start, end; + unsigned long prog_start, prog_end; + struct memrange *mem; + + prog_start = virt_to_phys(&_start); + prog_end = virt_to_phys(&_end); + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + start = phdr[i].p_paddr; + end = start + phdr[i].p_memsz; + if ((start & ADDRMASK ) < prog_start && (end & ADDRMASK) > prog_start) + goto conflict; + if ((start & ADDRMASK) < prog_end && (end & ADDRMASK) > prog_end) + goto conflict; + mem=info->memrange; + for (j = 0; j < info->n_memranges; j++) { + if (mem[j].base <= (start & ADDRMASK) && + mem[j].base + mem[j].size >= (end & ADDRMASK) ) + break; + } + if (j >= info->n_memranges) + goto badseg; + } + return 1; + +conflict: + printk("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end); + +badseg: + printk("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1); + return 0; +} + +static unsigned long process_image_notes(Elf_phdr *phdr, int phnum, + unsigned short *sum_ptr) +{ + int i; + char *buf = NULL; + int retval = 0; + unsigned long addr, end; + Elf_Nhdr *nhdr; + const char *name; + void *desc; + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_NOTE) + continue; + buf = malloc(phdr[i].p_filesz); + file_seek(phdr[i].p_offset); + if (lfile_read(buf, phdr[i].p_filesz) != phdr[i].p_filesz) { + printk("Can't read note segment\n"); + goto out; + } + addr = (unsigned long) buf; + end = addr + phdr[i].p_filesz; + while (addr < end) { + nhdr = (Elf_Nhdr *) addr; + addr += sizeof(Elf_Nhdr); + name = (const char *) addr; + addr += (nhdr->n_namesz+3) & ~3; + desc = (void *) addr; + addr += (nhdr->n_descsz+3) & ~3; + + if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT) + && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) { + if (nhdr->n_type == EIN_PROGRAM_NAME) { + image_name = calloc(1, nhdr->n_descsz + 1); + memcpy(image_name, desc, nhdr->n_descsz); + } + if (nhdr->n_type == EIN_PROGRAM_VERSION) { + image_version = calloc(1, nhdr->n_descsz + 1); + memcpy(image_version, desc, nhdr->n_descsz); + } + if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) { + *sum_ptr = *(unsigned short *) desc; + debug("Image checksum: %#04x\n", *sum_ptr); + /* Where in the file */ + retval = phdr[i].p_offset + + (unsigned long) desc - (unsigned long) buf; + } + } + } + } +out: + if (buf) + free(buf); + return retval; +} + +static int load_segments(Elf_phdr *phdr, int phnum, + unsigned long checksum_offset) +{ + unsigned long bytes; + //unsigned int start_time, time; + int i; + + bytes = 0; + // start_time = currticks(); + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + debug("segment %d addr:%#x file:%#x mem:%#x ", + i, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz); + file_seek(phdr[i].p_offset); + debug("loading... "); + if (lfile_read(phys_to_virt(phdr[i].p_paddr & ADDRMASK), phdr[i].p_filesz) + != phdr[i].p_filesz) { + printk("Can't read program segment %d\n", i); + return 0; + } + bytes += phdr[i].p_filesz; + debug("clearing... "); + memset(phys_to_virt(phdr[i].p_paddr + phdr[i].p_filesz), 0, + phdr[i].p_memsz - phdr[i].p_filesz); + if (phdr[i].p_offset <= checksum_offset + && phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) { + debug("clearing checksum... "); + memset(phys_to_virt((phdr[i].p_paddr & ADDRMASK) + checksum_offset + - phdr[i].p_offset), 0, 2); + } + debug("ok\n"); + + } + // time = currticks() - start_time; + //debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time, + // time? bytes/time : 0); + debug("Loaded %lu bytes \n", bytes); + + return 1; +} + +static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum, + unsigned short image_sum) +{ + unsigned short sum, part_sum; + unsigned long offset; + int i; + + sum = 0; + offset = 0; + + part_sum = ipchksum(ehdr, sizeof *ehdr); + sum = add_ipchksums(offset, sum, part_sum); + offset += sizeof *ehdr; + + part_sum = ipchksum(phdr, phnum * sizeof(*phdr)); + sum = add_ipchksums(offset, sum, part_sum); + offset += phnum * sizeof(*phdr); + + for (i = 0; i < phnum; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + part_sum = ipchksum(phys_to_virt(phdr[i].p_paddr), phdr[i].p_memsz); + sum = add_ipchksums(offset, sum, part_sum); + offset += phdr[i].p_memsz; + } + + if (sum != image_sum) { + printk("Verify FAILED (image:%#04x vs computed:%#04x)\n", + image_sum, sum); + return 0; + } + return 1; +} + +static inline unsigned const padded(unsigned s) +{ + return (s + 3) & ~3; +} + +static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name, + unsigned type, const char *desc, unsigned descsz) +{ + Elf_Nhdr nhdr; + unsigned ent_size, new_size, pad; + char *addr; + + if (!bhdr) + return NULL; + + nhdr.n_namesz = name? strlen(name)+1 : 0; + nhdr.n_descsz = descsz; + nhdr.n_type = type; + ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz); + if (bhdr->b_size + ent_size > 0xffff) { + printk("Boot notes too big\n"); + free(bhdr); + return NULL; + } + if (bhdr->b_size + ent_size > bhdr->b_checksum) { + do { + new_size = bhdr->b_checksum * 2; + } while (new_size < bhdr->b_size + ent_size); + if (new_size > 0xffff) + new_size = 0xffff; + debug("expanding boot note size to %u\n", new_size); +#ifdef HAVE_REALLOC + bhdr = realloc(bhdr, new_size); + bhdr->b_checksum = new_size; +#else + printk("Boot notes too big\n"); + free(bhdr); + return NULL; +#endif + } + + addr = (char *) bhdr; + addr += bhdr->b_size; + memcpy(addr, &nhdr, sizeof(nhdr)); + addr += sizeof(nhdr); + + memcpy(addr, name, nhdr.n_namesz); + addr += nhdr.n_namesz; + pad = padded(nhdr.n_namesz) - nhdr.n_namesz; + memset(addr, 0, pad); + addr += pad; + + memcpy(addr, desc, nhdr.n_descsz); + addr += nhdr.n_descsz; + pad = padded(nhdr.n_descsz) - nhdr.n_descsz; + memset(addr, 0, pad); + addr += pad; + + bhdr->b_size += ent_size; + bhdr->b_records++; + return bhdr; +} + +static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name, + unsigned type, const char *desc) +{ + return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1); +} + +static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline) +{ + Elf_Bhdr *bhdr; + + bhdr = malloc(256); + bhdr->b_signature = ELF_BHDR_MAGIC; + bhdr->b_size = sizeof *bhdr; + bhdr->b_checksum = 256; /* XXX cache the current buffer size here */ + bhdr->b_records = 0; + + if (info->firmware) + bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, info->firmware); + bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name); + bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version); + if (cmdline) + bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline); + if (!bhdr) + return bhdr; + bhdr->b_checksum = 0; + bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size); + return bhdr; +} + +int elf_load(struct sys_info *info, const char *filename, const char *cmdline) +{ + Elf_ehdr ehdr; + Elf_phdr *phdr = NULL; + unsigned long phdr_size; + unsigned long checksum_offset; + unsigned short checksum; + Elf_Bhdr *boot_notes = NULL; + int retval = -1; + int image_retval; + + image_name = image_version = 0; + + if (!file_open(filename)) + goto out; + + if (lfile_read(&ehdr, sizeof ehdr) != sizeof ehdr) { + debug("Can't read ELF header\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 + || ehdr.e_ident[EI_MAG1] != ELFMAG1 + || ehdr.e_ident[EI_MAG2] != ELFMAG2 + || ehdr.e_ident[EI_MAG3] != ELFMAG3 + || ehdr.e_ident[EI_CLASS] != ARCH_ELF_CLASS + || ehdr.e_ident[EI_DATA] != ARCH_ELF_DATA + || ehdr.e_ident[EI_VERSION] != EV_CURRENT + || ehdr.e_type != ET_EXEC + || !ARCH_ELF_MACHINE_OK(ehdr.e_machine) + || ehdr.e_version != EV_CURRENT + || ehdr.e_phentsize != sizeof(Elf_phdr)) { + debug("Not a bootable ELF image\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + phdr_size = ehdr.e_phnum * sizeof *phdr; + phdr = malloc(phdr_size); + file_seek(ehdr.e_phoff); + if (lfile_read(phdr, phdr_size) != phdr_size) { + printk("Can't read program header\n"); + goto out; + } + + if (!check_mem_ranges(info, phdr, ehdr.e_phnum)) + goto out; + + checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum); + + printk("Loading %s", image_name ? image_name : "image"); + if (image_version) + printk(" version %s", image_version); + printk("...\n"); + + if (!load_segments(phdr, ehdr.e_phnum, checksum_offset)) + goto out; + + if (checksum_offset) { + if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum)) + goto out; + } + + boot_notes = build_boot_notes(info, cmdline); + + //debug("current time: %lu\n", currticks()); + + debug("entry point is %#x\n", ehdr.e_entry); + printk("Jumping to entry point...\n"); + image_retval = start_elf(ehdr.e_entry & ADDRMASK, virt_to_phys(boot_notes)); + + // console_init(); FIXME + printk("Image returned with return value %#x\n", image_retval); + retval = 0; + +out: + if (phdr) + free(phdr); + if (boot_notes) + free(boot_notes); + if (image_name) + free(image_name); + if (image_version) + free(image_version); + return retval; +} diff --git a/arch/x86/entry.S b/arch/x86/entry.S new file mode 100644 index 0000000..cbafe88 --- /dev/null +++ b/arch/x86/entry.S @@ -0,0 +1,300 @@ + .globl entry, __switch_context, __exit_context, halt, init_exceptions + + .text + .align 4 + +/* + * Entry point + * We start execution from here. + * It is assumed that CPU is in 32-bit protected mode and + * all segments are 4GB and base zero (flat model). + */ +entry: + /* Save boot context and switch to our main context. + * Main context is statically defined in C. + */ + pushl %cs + call __switch_context + + /* We get here when the main context switches back to + * the boot context. + * Return to previous bootloader. + */ + ret + +/* + * Switch execution context + * This saves registers, segments, and GDT in the stack, then + * switches the stack, and restores everything from the new stack. + * This function takes no argument. New stack pointer is + * taken from global variable __context, and old stack pointer + * is also saved to __context. This way we can just jump to + * this routine to get back to the original context. + * + * Call this routine with lcall or pushl %cs; call. + */ +__switch_context: + /* Save everything in current stack */ + pushfl /* 56 */ + pushl %ds /* 52 */ + pushl %es /* 48 */ + pushl %fs /* 44 */ + pushl %gs /* 40 */ + pushal /* 8 */ + subl $8, %esp + movw %ss, (%esp) /* 0 */ + sgdt 2(%esp) /* 2 */ + +#if 0 + /* Swap %cs and %eip on the stack, so lret will work */ + movl 60(%esp), %eax + xchgl %eax, 64(%esp) + movl %eax, 60(%esp) +#endif + + /* At this point we don't know if we are on flat segment + * or relocated. So compute the address offset from %eip. + * Assuming CS.base==DS.base==SS.base. + */ + call 1f +1: popl %ebx + subl $1b, %ebx + + /* Interrupts are not allowed... */ + cli + + /* Current context pointer is our stack pointer */ + movl %esp, %esi + + /* Normalize the ctx pointer */ + subl %ebx, %esi + + /* Swap it with new value */ + xchgl %esi, __context(%ebx) + + /* Adjust new ctx pointer for current address offset */ + addl %ebx, %esi + + /* Load new %ss and %esp to temporary */ + movzwl (%esi), %edx + movl 20(%esi), %eax + + /* Load new GDT */ + lgdt 2(%esi) + + /* Load new stack segment with new GDT */ + movl %edx, %ss + + /* Set new stack pointer, but we have to adjust it because + * pushal saves %esp value before pushal, and we want the value + * after pushal. + */ + leal -32(%eax), %esp + + /* Load the rest from new stack */ + popal + popl %gs + popl %fs + popl %es + popl %ds + popfl + + /* Finally, load new %cs and %eip */ + lret + +__exit_context: + /* Get back to the original context */ + pushl %cs + call __switch_context + + /* We get here if the other context attempt to switch to this + * dead context. This should not happen. */ + +halt: + cli + hlt + jmp halt + +/* + * initialize exception handler. All exceptions end up in the same + * C function. + */ + +init_exceptions: + pushl %ebx + pushl %edi + + /* Initialize the Interrupt Descriptor table */ + leal _idt, %edi + leal vec0, %ebx + movl $(0x08 << 16), %eax /* cs selector */ + +1: movw %bx, %ax + movl %ebx, %edx + movw $0x8E00, %dx /* Interrupt gate - dpl=0, present */ + movl %eax, 0(%edi) + movl %edx, 4(%edi) + addl $6, %ebx + addl $8, %edi + cmpl $_idt_end, %edi + jne 1b + + /* Load the Interrupt descriptor table */ + lidt idtarg + + movl $0, %eax + popl %edi + popl %ebx + ret + +vec0: + pushl $0 /* error code */ + pushl $0 /* vector */ + jmp int_hand +vec1: + pushl $0 /* error code */ + pushl $1 /* vector */ + jmp int_hand + +vec2: + pushl $0 /* error code */ + pushl $2 /* vector */ + jmp int_hand + +vec3: + pushl $0 /* error code */ + pushl $3 /* vector */ + jmp int_hand + +vec4: + pushl $0 /* error code */ + pushl $4 /* vector */ + jmp int_hand + +vec5: + pushl $0 /* error code */ + pushl $5 /* vector */ + jmp int_hand + +vec6: + pushl $0 /* error code */ + pushl $6 /* vector */ + jmp int_hand +vec7: + pushl $0 /* error code */ + pushl $7 /* vector */ + jmp int_hand + +vec8: + /* error code */ + pushl $8 /* vector */ + jmp int_hand + .word 0x9090 + +vec9: + pushl $0 /* error code */ + pushl $9 /* vector */ + jmp int_hand + +vec10: + /* error code */ + pushl $10 /* vector */ + jmp int_hand + .word 0x9090 + +vec11: + /* error code */ + pushl $11 /* vector */ + jmp int_hand + .word 0x9090 + +vec12: + /* error code */ + pushl $12 /* vector */ + jmp int_hand + .word 0x9090 + +vec13: + /* error code */ + pushl $13 /* vector */ + jmp int_hand + .word 0x9090 + +vec14: + /* error code */ + pushl $14 /* vector */ + jmp int_hand + .word 0x9090 + +vec15: + pushl $0 /* error code */ + pushl $15 /* vector */ + jmp int_hand + +vec16: + pushl $0 /* error code */ + pushl $16 /* vector */ + jmp int_hand + +vec17: + /* error code */ + pushl $17 /* vector */ + jmp int_hand + .word 0x9090 + +vec18: + pushl $0 /* error code */ + pushl $18 /* vector */ + jmp int_hand + +vec19: + pushl $0 /* error code */ + pushl $19 /* vector */ + jmp int_hand + +int_hand: + /* At this point on the stack there is: + * 0(%esp) vector + * 4(%esp) error code + * 8(%esp) eip + * 12(%esp) cs + * 16(%esp) eflags + */ + pushl %edi + pushl %esi + pushl %ebp + /* Original stack pointer */ + leal 32(%esp), %ebp + pushl %ebp + pushl %ebx + pushl %edx + pushl %ecx + pushl %eax + + pushl %esp /* Pointer to structure on the stack */ + + call x86_exception + pop %eax /* Drop the pointer */ + + popl %eax + popl %ecx + popl %edx + popl %ebx + popl %ebp /* Ignore saved %esp value */ + popl %ebp + popl %esi + popl %edi + + addl $8, %esp /* pop of the vector and error code */ + + iret + +idtarg: + .word _idt_end - _idt - 1 /* limit */ + .long _idt + .word 0 +_idt: + .fill 20, 8, 0 # idt is unitiailzed +_idt_end: + + diff --git a/arch/x86/exception.c b/arch/x86/exception.c new file mode 100644 index 0000000..4b05780 --- /dev/null +++ b/arch/x86/exception.c @@ -0,0 +1,92 @@ +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "asm/types.h" + + + +/* program counter */ +extern ucell PC; + +extern unsigned char *dict; +extern cell dicthead; +extern ucell *last; + + + +struct eregs { + uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi; + uint32_t vector; + uint32_t error_code; + uint32_t eip; + uint32_t cs; + uint32_t eflags; +}; + +static char *exception_names[]= { + "division by zero", + "single step", + "NMI", + "breakpoint", + "interrupt overflow", + "bound range exceeded", + "invalid opcode", + "device unavailable", + "double fault", + "FPU segment overrun", + "invalid TSS", + "segment not present", + "stack exception", + "general protection fault", + "page fault", + "reserved", + "floating point exception", + "alignment check", + "machine check exception", +}; + +void do_nothing(void); +void do_nothing(void) +{ + printk("Doing nothing\n"); +} + +void x86_exception(struct eregs *info); +void x86_exception(struct eregs *info) +{ + if(info->vector <= 18) { + printk("\nUnexpected Exception: %s", + exception_names[info->vector]); + } else { + printk("\nUnexpected Exception: %d", info->vector); + } + + printk( + " @ %02x:%08lx - Halting\n" + "Code: %d eflags: %08lx\n" + "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n" + "edi: %08lx esi: %08lx ebp: %08lx esp: %08lx\n", + info->cs, (unsigned long)info->eip, + info->error_code, (unsigned long)info->eflags, + (unsigned long)info->eax, (unsigned long)info->ebx, + (unsigned long)info->ecx, (unsigned long)info->edx, + (unsigned long)info->edi, (unsigned long)info->esi, + (unsigned long)info->ebp, (unsigned long)info->esp); + + printk("\ndict=0x%x here=0x%x(dict+0x%x) pc=0x%x(dict+0x%x)\n", + (ucell)dict, (ucell)dict + dicthead, dicthead, PC, PC - (ucell) dict); + printk("dstackcnt=%d rstackcnt=%d\n", + dstackcnt, rstackcnt); + + rstackcnt=0; + dstackcnt=0; + + PC=findword("outer-interpreter"); + + info->eip=(uint32_t)&do_nothing; + +/* + for (;;) + asm("hlt;"); + ; +*/ +} diff --git a/arch/x86/forthload.c b/arch/x86/forthload.c new file mode 100644 index 0000000..8758f87 --- /dev/null +++ b/arch/x86/forthload.c @@ -0,0 +1,62 @@ +/* tag: forth source loader + * + * Copyright (C) 2004 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/bindings.h" +#include "sys_info.h" +#include "loadfs.h" +#include "boot.h" +#define printk printk +#define debug printk + +static char *forthtext=NULL; +int forth_load(struct sys_info *info, const char *filename, const char *cmdline) +{ + char magic[2]; + unsigned long forthsize; + int retval = -1; + + if (!file_open(filename)) + goto out; + + if (lfile_read(magic, 2) != 2) { + debug("Can't read magic header\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + if (magic[0] != '\\' || magic[1] != ' ') { + debug("No forth source image\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + forthsize = file_size(); + + forthtext = malloc(forthsize+1); + file_seek(0); + + printk("Loading forth source ..."); + if (lfile_read(forthtext, forthsize) != forthsize) { + printk("Can't read forth text\n"); + goto out; + } + forthtext[forthsize]=0; + printk("ok\n"); + + PUSH ( (ucell)forthtext ); + PUSH ( (ucell)forthsize ); + fword("eval2"); + retval=0; + +out: + //if (forthtext) + // free(forthtext); + return retval; +} diff --git a/arch/x86/init.fs b/arch/x86/init.fs new file mode 100644 index 0000000..8f045be --- /dev/null +++ b/arch/x86/init.fs @@ -0,0 +1,78 @@ +:noname + ." Type 'help' for detailed information" cr + \ ." boot secondary slave cdrom: " cr + \ ." 0 > boot hd:2,\boot\vmlinuz root=/dev/hda2" cr + ; DIAG-initializer + +" /" find-device + +new-device + " memory" device-name + \ 12230 encode-int " reg" property + external + : open true ; + : close ; + \ claim ( phys size align -- base ) + \ release ( phys size -- ) +finish-device + +new-device + " cpus" device-name + 1 " #address-cells" int-property + 0 " #size-cells" int-property + + external + : open true ; + : close ; + : decode-unit parse-hex ; + +finish-device + +: make-openable ( path ) + find-dev if + begin ?dup while + \ install trivial open and close methods + dup active-package! is-open + parent + repeat + then +; + +: preopen ( chosen-str node-path ) + 2dup make-openable + + " /chosen" find-device + open-dev ?dup if + encode-int 2swap property + else + 2drop + then + device-end +; + +:noname + set-defaults +; SYSTEM-initializer + +\ preopen device nodes (and store the ihandles under /chosen) +:noname + " memory" " /memory" preopen + " mmu" " /cpus/@0" preopen + " stdout" " /builtin/console" preopen + " stdin" " /builtin/console" preopen + +; SYSTEM-initializer + +\ use the tty interface if available +:noname + " /builtin/console" find-dev if drop + " /builtin/console" " input-device" $setenv + " /builtin/console" " output-device" $setenv + then +; SYSTEM-initializer + +:noname + " keyboard" input +; CONSOLE-IN-initializer + + diff --git a/arch/x86/ldscript b/arch/x86/ldscript new file mode 100644 index 0000000..8976c7a --- /dev/null +++ b/arch/x86/ldscript @@ -0,0 +1,73 @@ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +ENTRY(entry) + +/* Initial load address + * To be loaded by GRUB, this must be >= 1MB + */ +BASE_ADDR = 0x100000; + +/* 16KB heap and stack */ +HEAP_SIZE = 16384; +STACK_SIZE = 16384; + +SECTIONS +{ + . = BASE_ADDR; + + /* Put Multiboot header near beginning of file, if any. */ + .hdr : { *(.hdr) *(.hdr.*) } + + /* Start of the program. + * Now the version string is in the note, we must include it + * in the program. Otherwise we lose the string after relocation. */ + . = ALIGN(16); + _start = .; + + /* Putting ELF notes near beginning of file might help bootloaders. + * We discard .note sections other than .note.ELFBoot, + * because some versions of GCC generates useless ones. */ + .note : { *(.note.ELFBoot) } + + /* Normal sections */ + .text : { *(.text) *(.text.*) } + .rodata : { + . = ALIGN(4); + sound_drivers_start = .; + *(.rodata.sound_drivers) + sound_drivers_end = .; + *(.rodata) + *(.rodata.*) + } + .data : { *(.data) *(.data.*) } + + .bss : { + *(.bss) + *(.bss.*) + *(COMMON) + + /* Put heap and stack here, so they are included in PT_LOAD segment + * and the bootloader is aware of it. */ + + . = ALIGN(16); + _heap = .; + . += HEAP_SIZE; + . = ALIGN(16); + _eheap = .; + + _stack = .; + . += STACK_SIZE; + . = ALIGN(16); + _estack = .; + } + + .initctx : { + /* Initial contents of stack. This MUST BE just after the stack. */ + *(.initctx) + } + + _end = .; + + /DISCARD/ : { *(.comment) *(.note) } +} diff --git a/arch/x86/lib.c b/arch/x86/lib.c new file mode 100644 index 0000000..88cd79e --- /dev/null +++ b/arch/x86/lib.c @@ -0,0 +1,58 @@ +/* lib.c + * tag: simple function library + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "asm/types.h" +#include +#include "libc/stdlib.h" +#include "libc/vsprintf.h" +#include "openbios/kernel.h" + +/* Format a string and print it on the screen, just like the libc + * function printf. + */ +int printk( const char *fmt, ... ) +{ + char *p, buf[512]; /* XXX: no buffer overflow protection... */ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + + for( p=buf; *p; p++ ) + putchar(*p); + return i; +} + +// dumb quick memory allocator until we get a decent thing here. + +#define MEMSIZE 128*1024 +static char memory[MEMSIZE]; +static void *memptr=memory; +static int memsize=MEMSIZE; + +void *malloc(int size) +{ + void *ret=(void *)0; + if(memsize>=size) { + memsize-=size; + ret=memptr; + memptr+=size; + } + return ret; +} + +void free(void *ptr) +{ + /* Nothing yet */ +} + + diff --git a/arch/x86/linux_load.c b/arch/x86/linux_load.c new file mode 100644 index 0000000..f647c00 --- /dev/null +++ b/arch/x86/linux_load.c @@ -0,0 +1,648 @@ +/* + * Linux/i386 loader + * Supports bzImage, zImage and Image format. + * + * Based on work by Steve Gehlbach. + * Portions are taken from mkelfImage. + * + * 2003-09 by SONE Takeshi + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "openbios/bindings.h" +#include "sys_info.h" +#include "context.h" +#include "segment.h" +#include "loadfs.h" +#include "boot.h" + +#define printf printk +#define debug printk +#define strtoull_with_suffix strtol + +#define LINUX_PARAM_LOC 0x90000 +#define COMMAND_LINE_LOC 0x91000 +#define GDT_LOC 0x92000 +#define STACK_LOC 0x93000 + +#define E820MAX 32 /* number of entries in E820MAP */ +struct e820entry { + unsigned long long addr; /* start of memory segment */ + unsigned long long size; /* size of memory segment */ + unsigned long type; /* type of memory segment */ +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ +#define E820_NVS 4 +}; + +/* The header of Linux/i386 kernel */ +struct linux_header { + uint8_t reserved1[0x1f1]; /* 0x000 */ + uint8_t setup_sects; /* 0x1f1 */ + uint16_t root_flags; /* 0x1f2 */ + uint8_t reserved2[6]; /* 0x1f4 */ + uint16_t vid_mode; /* 0x1fa */ + uint16_t root_dev; /* 0x1fc */ + uint16_t boot_sector_magic; /* 0x1fe */ + /* 2.00+ */ + uint8_t reserved3[2]; /* 0x200 */ + uint8_t header_magic[4]; /* 0x202 */ + uint16_t protocol_version; /* 0x206 */ + uint32_t realmode_swtch; /* 0x208 */ + uint16_t start_sys; /* 0x20c */ + uint16_t kver_addr; /* 0x20e */ + uint8_t type_of_loader; /* 0x210 */ + uint8_t loadflags; /* 0x211 */ + uint16_t setup_move_size; /* 0x212 */ + uint32_t code32_start; /* 0x214 */ + uint32_t ramdisk_image; /* 0x218 */ + uint32_t ramdisk_size; /* 0x21c */ + uint8_t reserved4[4]; /* 0x220 */ + /* 2.01+ */ + uint16_t heap_end_ptr; /* 0x224 */ + uint8_t reserved5[2]; /* 0x226 */ + /* 2.02+ */ + uint32_t cmd_line_ptr; /* 0x228 */ + /* 2.03+ */ + uint32_t initrd_addr_max; /* 0x22c */ +} __attribute__ ((packed)); + + +/* Paramters passed to 32-bit part of Linux + * This is another view of the structure above.. */ +struct linux_params { + uint8_t orig_x; /* 0x00 */ + uint8_t orig_y; /* 0x01 */ + uint16_t ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */ + uint16_t orig_video_page; /* 0x04 */ + uint8_t orig_video_mode; /* 0x06 */ + uint8_t orig_video_cols; /* 0x07 */ + uint16_t unused2; /* 0x08 */ + uint16_t orig_video_ega_bx; /* 0x0a */ + uint16_t unused3; /* 0x0c */ + uint8_t orig_video_lines; /* 0x0e */ + uint8_t orig_video_isVGA; /* 0x0f */ + uint16_t orig_video_points; /* 0x10 */ + + /* VESA graphic mode -- linear frame buffer */ + uint16_t lfb_width; /* 0x12 */ + uint16_t lfb_height; /* 0x14 */ + uint16_t lfb_depth; /* 0x16 */ + uint32_t lfb_base; /* 0x18 */ + uint32_t lfb_size; /* 0x1c */ + uint16_t cl_magic; /* 0x20 */ +#define CL_MAGIC_VALUE 0xA33F + uint16_t cl_offset; /* 0x22 */ + uint16_t lfb_linelength; /* 0x24 */ + uint8_t red_size; /* 0x26 */ + uint8_t red_pos; /* 0x27 */ + uint8_t green_size; /* 0x28 */ + uint8_t green_pos; /* 0x29 */ + uint8_t blue_size; /* 0x2a */ + uint8_t blue_pos; /* 0x2b */ + uint8_t rsvd_size; /* 0x2c */ + uint8_t rsvd_pos; /* 0x2d */ + uint16_t vesapm_seg; /* 0x2e */ + uint16_t vesapm_off; /* 0x30 */ + uint16_t pages; /* 0x32 */ + uint8_t reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */ + + //struct apm_bios_info apm_bios_info; /* 0x40 */ + uint8_t apm_bios_info[0x40]; + //struct drive_info_struct drive_info; /* 0x80 */ + uint8_t drive_info[0x20]; + //struct sys_desc_table sys_desc_table; /* 0xa0 */ + uint8_t sys_desc_table[0x140]; + uint32_t alt_mem_k; /* 0x1e0 */ + uint8_t reserved5[4]; /* 0x1e4 */ + uint8_t e820_map_nr; /* 0x1e8 */ + uint8_t reserved6[9]; /* 0x1e9 */ + uint16_t mount_root_rdonly; /* 0x1f2 */ + uint8_t reserved7[4]; /* 0x1f4 */ + uint16_t ramdisk_flags; /* 0x1f8 */ +#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_PROMPT_FLAG 0x8000 +#define RAMDISK_LOAD_FLAG 0x4000 + uint8_t reserved8[2]; /* 0x1fa */ + uint16_t orig_root_dev; /* 0x1fc */ + uint8_t reserved9[1]; /* 0x1fe */ + uint8_t aux_device_info; /* 0x1ff */ + uint8_t reserved10[2]; /* 0x200 */ + uint8_t param_block_signature[4]; /* 0x202 */ + uint16_t param_block_version; /* 0x206 */ + uint8_t reserved11[8]; /* 0x208 */ + uint8_t loader_type; /* 0x210 */ +#define LOADER_TYPE_LOADLIN 1 +#define LOADER_TYPE_BOOTSECT_LOADER 2 +#define LOADER_TYPE_SYSLINUX 3 +#define LOADER_TYPE_ETHERBOOT 4 +#define LOADER_TYPE_KERNEL 5 + uint8_t loader_flags; /* 0x211 */ + uint8_t reserved12[2]; /* 0x212 */ + uint32_t kernel_start; /* 0x214 */ + uint32_t initrd_start; /* 0x218 */ + uint32_t initrd_size; /* 0x21c */ + uint8_t reserved12_5[8]; /* 0x220 */ + uint32_t cmd_line_ptr; /* 0x228 */ + uint8_t reserved13[164]; /* 0x22c */ + struct e820entry e820_map[E820MAX]; /* 0x2d0 */ + uint8_t reserved16[688]; /* 0x550 */ +#define COMMAND_LINE_SIZE 256 + /* Command line is copied here by 32-bit i386/kernel/head.S. + * So I will follow the boot protocol, rather than putting it + * directly here. --ts1 */ + uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */ + uint8_t reserved17[1792]; /* 0x900 - 0x1000 */ +}; + +uint64_t forced_memsize; + +/* Load the first part the file and check if it's Linux */ +static uint32_t load_linux_header(struct linux_header *hdr) +{ + int load_high; + uint32_t kern_addr; + + if (lfile_read(hdr, sizeof *hdr) != sizeof *hdr) { + debug("Can't read Linux header\n"); + return 0; + } + if (hdr->boot_sector_magic != 0xaa55) { + debug("Not a Linux kernel image\n"); + return 0; + } + + /* Linux is found. Print some information */ + if (memcmp(hdr->header_magic, "HdrS", 4) != 0) { + /* This may be floppy disk image or something. + * Perform a simple (incomplete) sanity check. */ + if (hdr->setup_sects >= 16 + || file_size() - (hdr->setup_sects<<9) >= 512<<10) { + debug("This looks like a bootdisk image but not like Linux...\n"); + return 0; + } + + printf("Possible very old Linux"); + /* This kernel does not even have a protocol version. + * Force the value. */ + hdr->protocol_version = 0; /* pre-2.00 */ + } else + printf("Found Linux"); + if (hdr->protocol_version >= 0x200 && hdr->kver_addr) { + char kver[256]; + file_seek(hdr->kver_addr + 0x200); + if (lfile_read(kver, sizeof kver) != 0) { + kver[255] = 0; + printf(" version %s", kver); + } + } + debug(" (protocol %#x)", hdr->protocol_version); + load_high = 0; + if (hdr->protocol_version >= 0x200) { + debug(" (loadflags %#x)", hdr->loadflags); + load_high = hdr->loadflags & 1; + } + if (load_high) { + printf(" bzImage"); + kern_addr = 0x100000; + } else { + printf(" zImage or Image"); + kern_addr = 0x1000; + } + printf(".\n"); + + return kern_addr; +} + +/* Set up parameters for 32-bit kernel */ +static void +init_linux_params(struct linux_params *params, struct linux_header *hdr) +{ + debug("Setting up paramters at %#lx\n", virt_to_phys(params)); + memset(params, 0, sizeof *params); + + /* Copy some useful values from header */ + params->mount_root_rdonly = hdr->root_flags; + params->orig_root_dev = hdr->root_dev; + + /* Video parameters. + * This assumes we have VGA in standard 80x25 text mode, + * just like our vga.c does. + * Cursor position is filled later to allow some more printf's. */ + params->orig_video_mode = 3; + params->orig_video_cols = 80; + params->orig_video_lines = 25; + params->orig_video_isVGA = 1; + params->orig_video_points = 16; + + params->loader_type = 0xff; /* Unregistered Linux loader */ +} + +/* Memory map */ +static void +set_memory_size(struct linux_params *params, struct sys_info *info) +{ + int i; + uint64_t end; + uint32_t ramtop = 0; + struct e820entry *linux_map; + struct memrange *filo_map; + + linux_map = params->e820_map; + filo_map = info->memrange; + for (i = 0; i < info->n_memranges; i++, linux_map++, filo_map++) { + if (i < E820MAX) { + /* Convert to BIOS e820 style */ + linux_map->addr = filo_map->base; + linux_map->size = filo_map->size; + linux_map->type = E820_RAM; + debug("%016Lx - %016Lx\n", linux_map->addr, + linux_map->addr + linux_map->size); + params->e820_map_nr = i+1; + } + + /* Find out top of RAM. XXX This ignores hole above 1MB */ + end = filo_map->base + filo_map->size; + if (end < (1ULL << 32)) { /* don't count memory above 4GB */ + if (end > ramtop) + ramtop = (uint32_t) end; + } + } + debug("ramtop=%#x\n", ramtop); + /* Size of memory above 1MB in KB */ + params->alt_mem_k = (ramtop - (1<<20)) >> 10; + /* old style, 64MB max */ + if (ramtop >= (64<<20)) + params->ext_mem_k = (63<<10); + else + params->ext_mem_k = params->alt_mem_k; + debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k); +} + +/* + * Parse command line + * Some parameters, like initrd=, are not passed to kernel, + * we are responsible to process them. + * Parameters for kernel are copied to kern_cmdline. Returns name of initrd. + */ +static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline) +{ + const char *start, *sep, *end, *val; + char name[64]; + int len; + int k_len; + int to_kern; + char *initrd = 0; + int toolong = 0; + + forced_memsize = 0; + + if (!orig_cmdline) { + *kern_cmdline = 0; + return 0; + } + + k_len = 0; + debug("original command line: \"%s\"\n", orig_cmdline); + debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline)); + + start = orig_cmdline; + while (*start == ' ') + start++; + while (*start) { + end = strchr(start, ' '); + if (!end) + end = start + strlen(start); + sep = strchr(start, '='); + if (!sep || sep > end) + sep = end; + len = sep - start; + if (len >= sizeof(name)) + len = sizeof(name) - 1; + memcpy(name, start, len); + name[len] = 0; + + if (*sep == '=') { + val = sep + 1; + len = end - val; + } else { + val = 0; + len = 0; + } + + /* Only initrd= and mem= are handled here. vga= is not, + * which I believe is a paramter to the realmode part of Linux, + * which we don't execute. */ + if (strcmp(name, "initrd") == 0) { + if (!val) + printf("Missing filename to initrd parameter\n"); + else { + initrd = malloc(len + 1); + memcpy(initrd, val, len); + initrd[len] = 0; + debug("initrd=%s\n", initrd); + } + /* Don't pass this to kernel */ + to_kern = 0; + } else if (strcmp(name, "mem") == 0) { + if (!val) + printf("Missing value for mem parameter\n"); + else { + forced_memsize = strtoull_with_suffix(val, (char**)&val, 0); + if (forced_memsize == 0) + printf("Invalid mem option, ignored\n"); + if (val != end) { + printf("Garbage after mem=, ignored\n"); + forced_memsize = 0; + } + debug("mem=%Lu\n", forced_memsize); + } + /* mem= is for both loader and kernel */ + to_kern = 1; + } else + to_kern = 1; + + if (to_kern) { + /* Copy to kernel command line buffer */ + if (k_len != 0) + kern_cmdline[k_len++] = ' '; /* put separator */ + len = end - start; + if (k_len + len >= COMMAND_LINE_SIZE) { + len = COMMAND_LINE_SIZE - k_len - 1; + if (!toolong) { + printf("Kernel command line is too long; truncated to " + "%d bytes\n", COMMAND_LINE_SIZE-1); + toolong = 1; + } + } + memcpy(kern_cmdline + k_len, start, len); + k_len += len; + } + + start = end; + while (*start == ' ') + start++; + } + kern_cmdline[k_len] = 0; + debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline); + + return initrd; +} + +/* Set command line location */ +static void set_command_line_loc(struct linux_params *params, + struct linux_header *hdr) +{ + if (hdr->protocol_version >= 0x202) { + /* new style */ + params->cmd_line_ptr = COMMAND_LINE_LOC; + } else { + /* old style */ + params->cl_magic = CL_MAGIC_VALUE; + params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC; + } +} + +/* Load 32-bit part of kernel */ +static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr) +{ + uint32_t kern_offset, kern_size; + + if (hdr->setup_sects == 0) + hdr->setup_sects = 4; + kern_offset = (hdr->setup_sects + 1) * 512; + file_seek(kern_offset); + kern_size = file_size() - kern_offset; + debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size); + +#if 0 + if (using_devsize) { + printf("Attempt to load up to end of device as kernel; " + "specify the image size\n"); + return 0; + } +#endif + + printf("Loading kernel... "); + if (lfile_read(phys_to_virt(kern_addr), kern_size) != kern_size) { + printf("Can't read kernel\n"); + return 0; + } + printf("ok\n"); + + return kern_size; +} + +static int load_initrd(struct linux_header *hdr, struct sys_info *info, + uint32_t kern_end, struct linux_params *params, const char *initrd_file) +{ + uint32_t max; + uint32_t start, end, size; + uint64_t forced; + extern char _start[], _end[]; + + if (!file_open(initrd_file)) { + printf("Can't open initrd: %s\n", initrd_file); + return -1; + } + +#if 0 + if (using_devsize) { + printf("Attempt to load up to end of device as initrd; " + "specify the image size\n"); + return -1; + } +#endif + + size = file_size(); + + + /* Find out the kernel's restriction on how high the initrd can be + * placed */ + if (hdr->protocol_version >= 0x203) + max = hdr->initrd_addr_max; + else + max = 0x38000000; /* Hardcoded value for older kernels */ + + /* FILO itself is at the top of RAM. (relocated) + * So, try putting initrd just below us. */ + end = virt_to_phys(_start); + if (end > max) + end = max; + + /* If "mem=" option is given, we have to put the initrd within + * the specified range. */ + if (forced_memsize) { + forced = forced_memsize; + if (forced > max) + forced = max; + /* If the "mem=" is lower, it's easy */ + if (forced <= end) + end = forced; + else { + /* Otherwise, see if we can put it above us */ + if (virt_to_phys(_end) + size <= forced) + end = forced; /* Ok */ + } + } + + start = end - size; + start &= ~0xfff; /* page align */ + end = start + size; + + debug("start=%#x end=%#x\n", start, end); + + if (start < kern_end) { + printf("Initrd is too big to fit in memory\n"); + return -1; + } + + printf("Loading initrd... "); + if (lfile_read(phys_to_virt(start), size) != size) { + printf("Can't read initrd\n"); + return -1; + } + printf("ok\n"); + + params->initrd_start = start; + params->initrd_size = size; + + return 0; +} + +static void hardware_setup(void) +{ + /* Disable nmi */ + outb(0x80, 0x70); + + /* Make sure any coprocessor is properly reset.. */ + outb(0, 0xf0); + outb(0, 0xf1); + + /* we're getting screwed again and again by this problem of the 8259. + * so we're going to leave this lying around for inclusion into + * crt0.S on an as-needed basis. + * + * well, that went ok, I hope. Now we have to reprogram the interrupts :-( + * we put them right after the intel-reserved hardware interrupts, at + * int 0x20-0x2F. There they won't mess up anything. Sadly IBM really + * messed this up with the original PC, and they haven't been able to + * rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, + * which is used for the internal hardware interrupts as well. We just + * have to reprogram the 8259's, and it isn't fun. + */ + + outb(0x11, 0x20); /* initialization sequence to 8259A-1 */ + outb(0x11, 0xA0); /* and to 8259A-2 */ + + outb(0x20, 0x21); /* start of hardware int's (0x20) */ + outb(0x28, 0xA1); /* start of hardware int's 2 (0x28) */ + + outb(0x04, 0x21); /* 8259-1 is master */ + outb(0x02, 0xA1); /* 8259-2 is slave */ + + outb(0x01, 0x21); /* 8086 mode for both */ + outb(0x01, 0xA1); + + outb(0xFF, 0xA1); /* mask off all interrupts for now */ + outb(0xFB, 0x21); /* mask all irq's but irq2 which is cascaded */ +} + +/* Start Linux */ +static int start_linux(uint32_t kern_addr, struct linux_params *params) +{ + struct segment_desc *linux_gdt; + struct context *ctx; + //extern int cursor_x, cursor_y; + + ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0); + + /* Linux expects GDT being in low memory */ + linux_gdt = phys_to_virt(GDT_LOC); + memset(linux_gdt, 0, 13*sizeof(struct segment_desc)); + /* Normal kernel code/data segments */ + linux_gdt[2] = gdt[FLAT_CODE]; + linux_gdt[3] = gdt[FLAT_DATA]; + /* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible + * segments (2 and 3), so it SHOULD not be a problem. + * However, some distro kernels (eg. RH9) with backported threading + * patch use 12 and 13 also when booting... */ + linux_gdt[12] = gdt[FLAT_CODE]; + linux_gdt[13] = gdt[FLAT_DATA]; + ctx->gdt_base = GDT_LOC; + ctx->gdt_limit = 14*8-1; + ctx->cs = 0x10; + ctx->ds = 0x18; + ctx->es = 0x18; + ctx->fs = 0x18; + ctx->gs = 0x18; + ctx->ss = 0x18; + + /* Parameter location */ + ctx->esi = virt_to_phys(params); + + /* Entry point */ + ctx->eip = kern_addr; + + debug("eip=%#x\n", kern_addr); + printf("Jumping to entry point...\n"); + +#ifdef VGA_CONSOLE + /* Update VGA cursor position. + * This must be here because the printf changes the value! */ + params->orig_x = cursor_x; + params->orig_y = cursor_y; +#endif + + /* Go... */ + ctx = switch_to(ctx); + + /* It's impossible but... */ + printf("Returned with eax=%#x\n", ctx->eax); + + return ctx->eax; +} + +int linux_load(struct sys_info *info, const char *file, const char *cmdline) +{ + struct linux_header hdr; + struct linux_params *params; + uint32_t kern_addr, kern_size; + char *initrd_file = 0; + + if (!file_open(file)) + return -1; + + kern_addr = load_linux_header(&hdr); + if (kern_addr == 0) + return LOADER_NOT_SUPPORT; + + params = phys_to_virt(LINUX_PARAM_LOC); + init_linux_params(params, &hdr); + set_memory_size(params, info); + initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC)); + set_command_line_loc(params, &hdr); + + kern_size = load_linux_kernel(&hdr, kern_addr); + if (kern_size == 0) { + if (initrd_file) + free(initrd_file); + return -1; + } + + if (initrd_file) { + if (load_initrd(&hdr, info, kern_addr+kern_size, params, initrd_file) + != 0) { + free(initrd_file); + return -1; + } + free(initrd_file); + } + + hardware_setup(); + + start_linux(kern_addr, params); + return 0; +} diff --git a/arch/x86/loadfs.c b/arch/x86/loadfs.c new file mode 100644 index 0000000..6081b01 --- /dev/null +++ b/arch/x86/loadfs.c @@ -0,0 +1,46 @@ +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "libc/diskio.h" +#include "loadfs.h" + +static int load_fd=-1; + +int file_open(const char *filename) +{ + load_fd=open_io(filename); + /* if(load_fd!=-1) */ seek_io(load_fd, 0); + return load_fd>-1; +} + +int lfile_read(void *buf, unsigned long len) +{ + int ret; + ret=read_io(load_fd, buf, len); + return ret; +} + +int file_seek(unsigned long offset) +{ + return seek_io(load_fd, offset); +} + +unsigned long file_size(void) +{ + llong fpos, fsize; + + /* save current position */ + fpos=tell(load_fd); + + /* go to end of file and get position */ + seek_io(load_fd, -1); + fsize=tell(load_fd); + + /* go back to old position */ + seek_io(load_fd, 0); + seek_io(load_fd, fpos); + + return fsize; +} + + + diff --git a/arch/x86/loadfs.h b/arch/x86/loadfs.h new file mode 100644 index 0000000..71b39c1 --- /dev/null +++ b/arch/x86/loadfs.h @@ -0,0 +1,7 @@ +int file_open(const char *filename); +int lfile_read(void *buf, unsigned long len); +int file_seek(unsigned long offset); +unsigned long file_size(void); + + + diff --git a/arch/x86/multiboot.c b/arch/x86/multiboot.c new file mode 100644 index 0000000..d042581 --- /dev/null +++ b/arch/x86/multiboot.c @@ -0,0 +1,126 @@ +/* Support for Multiboot */ + +#include "openbios/config.h" +#include "asm/io.h" +#include "sys_info.h" +#include "multiboot.h" + +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +struct mbheader { + unsigned int magic, flags, checksum; +}; +const struct mbheader multiboot_header + __attribute__((section (".hdr"))) = +{ + MULTIBOOT_HEADER_MAGIC, + MULTIBOOT_HEADER_FLAGS, + -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) +}; + +/* Multiboot information structure, provided by loader to us */ + +struct multiboot_mmap { + unsigned entry_size; + unsigned base_lo, base_hi; + unsigned size_lo, size_hi; + unsigned type; +}; + +#define MULTIBOOT_MEM_VALID 0x01 +#define MULTIBOOT_BOOT_DEV_VALID 0x02 +#define MULTIBOOT_CMDLINE_VALID 0x04 +#define MULTIBOOT_MODS_VALID 0x08 +#define MULTIBOOT_AOUT_SYMS_VALID 0x10 +#define MULTIBOOT_ELF_SYMS_VALID 0x20 +#define MULTIBOOT_MMAP_VALID 0x40 + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ + struct multiboot_info *mbinfo; + struct multiboot_mmap *mbmem; + unsigned mbcount, mbaddr; + int i; + struct memrange *mmap; + int mmap_count; + module_t *mod; + + if (info->boot_type != 0x2BADB002) + return; + + debug("Using Multiboot information at %#lx\n", info->boot_data); + + mbinfo = phys_to_virt(info->boot_data); + + if (mbinfo->mods_count != 1) { + printk("multiboot: no dictionary\n"); + return; + } + + mod = (module_t *) mbinfo->mods_addr; + info->dict_start=(unsigned long *)mod->mod_start; + info->dict_end=(unsigned long *)mod->mod_end; + debug("multiboot: dictionary at %x-%x\n", + info->dict_start, info->dict_end); + + if (mbinfo->flags & MULTIBOOT_MMAP_VALID) { + /* convert mmap records */ + mbmem = phys_to_virt(mbinfo->mmap_addr); + mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4); + mmap = malloc(mbcount * sizeof(struct memrange)); + mmap_count = 0; + mbaddr = mbinfo->mmap_addr; + for (i = 0; i < mbcount; i++) { + mbmem = phys_to_virt(mbaddr); + debug("%08x%08x %08x%08x (%d)\n", + mbmem->base_hi, + mbmem->base_lo, + mbmem->size_hi, + mbmem->size_lo, + mbmem->type); + if (mbmem->type == 1) { /* Only normal RAM */ + mmap[mmap_count].base = mbmem->base_lo + + (((unsigned long long) mbmem->base_hi) << 32); + mmap[mmap_count].size = mbmem->size_lo + + (((unsigned long long) mbmem->size_hi) << 32); + mmap_count++; + } + mbaddr += mbmem->entry_size + 4; + if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length) + break; + } + /* simple sanity check - there should be at least 2 RAM segments + * (base 640k and extended) */ + if (mmap_count >= 2) + goto got_it; + + printk("Multiboot mmap is broken\n"); + free(mmap); + /* fall back to mem_lower/mem_upper */ + } + + if (mbinfo->flags & MULTIBOOT_MEM_VALID) { + /* use mem_lower and mem_upper */ + mmap_count = 2; + mmap = malloc(2 * sizeof(*mmap)); + mmap[0].base = 0; + mmap[0].size = mbinfo->mem_lower << 10; + mmap[1].base = 1 << 20; /* 1MB */ + mmap[1].size = mbinfo->mem_upper << 10; + goto got_it; + } + + printk("Can't get memory information from Multiboot\n"); + return; + +got_it: + info->memrange = mmap; + info->n_memranges = mmap_count; + + return; +} diff --git a/arch/x86/multiboot.h b/arch/x86/multiboot.h new file mode 100644 index 0000000..adf1363 --- /dev/null +++ b/arch/x86/multiboot.h @@ -0,0 +1,96 @@ +/* multiboot.h + * tag: header for multiboot + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +/* magic number for multiboot header */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* flags for multiboot header */ +#define MULTIBOOT_HEADER_FLAGS 0x00010003 + +/* magic number passed by multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (8KB). */ +#define STACK_SIZE 0x2000 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* We don't want these declarations in boot.S */ + +/* multiboot header */ +typedef struct multiboot_header { + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* symbol table for a.out */ +typedef struct aout_symbol_table { + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* section header table for ELF */ +typedef struct elf_section_header_table { + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* multiboot information */ +typedef struct multiboot_info { + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; +} multiboot_info_t; + +/* module structure */ +typedef struct module { + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map { + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +#endif /* ! ASM */ diff --git a/arch/x86/openbios.c b/arch/x86/openbios.c new file mode 100644 index 0000000..6a304d7 --- /dev/null +++ b/arch/x86/openbios.c @@ -0,0 +1,120 @@ +/* tag: openbios forth environment, executable code + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "asm/types.h" +#include "dict.h" +#include "openbios/kernel.h" +#include "openbios/stack.h" +#include "openbios/drivers.h" +#include "sys_info.h" +#include "openbios.h" +#include "relocate.h" + +void boot(void); + +static char intdict[256 * 1024]; + +static void init_memory(void) +{ + /* push start and end of available memory to the stack + * so that the forth word QUIT can initialize memory + * management. For now we use hardcoded memory between + * 0x10000 and 0x9ffff (576k). If we need more memory + * than that we have serious bloat. + */ + + PUSH(0x10000); + PUSH(0x9FFFF); +} + +void exception(cell no) +{ + /* The exception mechanism is used during bootstrap to catch + * build errors. In a running system this is a noop since we + * can't break out to the unix host os anyways. + */ +} + +static void +arch_init( void ) +{ + void setup_timers(void); + + modules_init(); +#ifdef CONFIG_DRIVER_PCI + ob_pci_init(); +#endif +#ifdef CONFIG_DRIVER_IDE + setup_timers(); + ob_ide_init(); +#endif +#ifdef CONFIG_DRIVER_FLOPPY + ob_floppy_init(); +#endif +#ifdef CONFIG_XBOX + init_video(); + node_methods_init(); +#endif + device_end(); + bind_func("platform-boot", boot ); +} + +int openbios(void) +{ + extern struct sys_info sys_info; +#ifdef CONFIG_DEBUG_CONSOLE +#ifdef CONFIG_DEBUG_CONSOLE_SERIAL + uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED); +#endif + /* Clear the screen. */ + cls(); +#endif + + collect_sys_info(&sys_info); + + dict=intdict; + load_dictionary((char *)sys_info.dict_start, + (unsigned long)sys_info.dict_end - + (unsigned long)sys_info.dict_start); + + relocate(&sys_info); + +#ifdef CONFIG_DEBUG_CONSOLE_VGA + video_init(); +#endif +#ifdef CONFIG_DEBUG_BOOT + printk("forth started.\n"); + printk("initializing memory..."); +#endif + + init_memory(); + +#ifdef CONFIG_DEBUG_BOOT + printk("done\n"); +#endif + + PUSH_xt( bind_noname_func(arch_init) ); + fword("PREPOST-initializer"); + + PC = (ucell)findword("initialize-of"); + + if (!PC) { + printk("panic: no dictionary entry point.\n"); + return -1; + } +#ifdef CONFIG_DEBUG_DICTIONARY + printk("done (%d bytes).\n", dicthead); + printk("Jumping to dictionary...\n"); +#endif + + enterforth((xt_t)PC); + + return 0; +} diff --git a/arch/x86/openbios.h b/arch/x86/openbios.h new file mode 100644 index 0000000..f4df27d --- /dev/null +++ b/arch/x86/openbios.h @@ -0,0 +1,29 @@ +/* + * Creation Date: <2004/01/15 16:14:05 samuel> + * Time-stamp: <2004/01/15 16:14:05 samuel> + * + * + * + * + * + * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_OPENBIOS +#define _H_OPENBIOS + +int openbios(void); + +/* console.c */ +extern void cls(void); +#ifdef CONFIG_DEBUG_CONSOLE +extern int uart_init(int port, unsigned long speed); +extern void video_init(void); +#endif + +#endif /* _H_OPENBIOS */ diff --git a/arch/x86/plainboot.c b/arch/x86/plainboot.c new file mode 100644 index 0000000..e09af50 --- /dev/null +++ b/arch/x86/plainboot.c @@ -0,0 +1,22 @@ +/* tag: openbios fixed address forth starter + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "sys_info.h" +#include "multiboot.h" + +#define FIXED_DICTSTART 0xfffe0000 +#define FIXED_DICTEND 0xfffeffff + +void collect_multiboot_info(struct sys_info *info); +void collect_multiboot_info(struct sys_info *info) +{ + info->dict_start=(unsigned long *)FIXED_DICTSTART; + info->dict_end=(unsigned long *)FIXED_DICTEND; +} + diff --git a/arch/x86/relocate.h b/arch/x86/relocate.h new file mode 100644 index 0000000..2087540 --- /dev/null +++ b/arch/x86/relocate.h @@ -0,0 +1,2 @@ +void relocate(struct sys_info *); + diff --git a/arch/x86/segment.c b/arch/x86/segment.c new file mode 100644 index 0000000..ae91445 --- /dev/null +++ b/arch/x86/segment.c @@ -0,0 +1,134 @@ +/* Segmentation of the i386 architecture. + * + * 2003-07 by SONE Takeshi + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "sys_info.h" +#include "relocate.h" +#include "segment.h" + +#define printf printk +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +/* i386 lgdt argument */ +struct gdtarg { + unsigned short limit; + unsigned int base; +} __attribute__((packed)); + +/* How far the virtual address (used in C) is different from physical + * address. Since we start in flat mode, the initial value is zero. */ +unsigned long virt_offset = 0; + +/* GDT, the global descriptor table */ +struct segment_desc gdt[NUM_SEG] = { + /* 0x00: null segment */ + {0, 0, 0, 0, 0, 0}, + /* 0x08: flat code segment */ + {0xffff, 0, 0, 0x9f, 0xcf, 0}, + /* 0x10: flat data segment */ + {0xffff, 0, 0, 0x93, 0xcf, 0}, + /* 0x18: code segment for relocated execution */ + {0xffff, 0, 0, 0x9f, 0xcf, 0}, + /* 0x20: data segment for relocated execution */ + {0xffff, 0, 0, 0x93, 0xcf, 0}, +}; + +extern char _start[], _end[]; + +void relocate(struct sys_info *info) +{ + int i; + unsigned long prog_addr; + unsigned long prog_size; + unsigned long addr, new_base; + unsigned long long segsize; + unsigned long new_offset; + unsigned d0, d1, d2; + struct gdtarg gdtarg; +#define ALIGNMENT 16 + + prog_addr = virt_to_phys(&_start); + prog_size = virt_to_phys(&_end) - virt_to_phys(&_start); + debug("Current location: %#lx-%#lx\n", prog_addr, prog_addr+prog_size-1); + + new_base = 0; + for (i = 0; i < info->n_memranges; i++) { + if (info->memrange[i].base >= 1ULL<<32) + continue; + segsize = info->memrange[i].size; + if (info->memrange[i].base + segsize > 1ULL<<32) + segsize = (1ULL<<32) - info->memrange[i].base; + if (segsize < prog_size+ALIGNMENT) + continue; + addr = info->memrange[i].base + segsize - prog_size; + addr &= ~(ALIGNMENT-1); + if (addr >= prog_addr && addr < prog_addr + prog_size) + continue; + if (prog_addr >= addr && prog_addr < addr + prog_size) + continue; + if (addr > new_base) + new_base = addr; + } + if (new_base == 0) { + printf("Can't find address to relocate\n"); + return; + } + + debug("Relocating to %#lx-%#lx... ", + new_base, new_base + prog_size - 1); + + /* New virtual address offset */ + new_offset = new_base - (unsigned long) &_start; + + /* Tweak the GDT */ + gdt[RELOC_CODE].base_0 = (unsigned short) new_offset; + gdt[RELOC_CODE].base_16 = (unsigned char) (new_offset>>16); + gdt[RELOC_CODE].base_24 = (unsigned char) (new_offset>>24); + gdt[RELOC_DATA].base_0 = (unsigned short) new_offset; + gdt[RELOC_DATA].base_16 = (unsigned char) (new_offset>>16); + gdt[RELOC_DATA].base_24 = (unsigned char) (new_offset>>24); + + /* Load new GDT and reload segments */ + gdtarg.base = new_offset + (unsigned long) gdt; + gdtarg.limit = GDT_LIMIT; + __asm__ __volatile__ ( + "rep; movsb\n\t" /* copy everything */ + "lgdt %3\n\t" + "ljmp %4, $1f\n1:\t" + "movw %5, %%ds\n\t" + "movw %5, %%es\n\t" + "movw %5, %%fs\n\t" + "movw %5, %%gs\n\t" + "movw %5, %%ss\n" + : "=&S" (d0), "=&D" (d1), "=&c" (d2) + : "m" (gdtarg), "n" (RELOC_CS), "q" ((unsigned short) RELOC_DS), + "0" (&_start), "1" (new_base), "2" (prog_size)); + + virt_offset = new_offset; + debug("ok\n"); +} + +#if 0 +/* Copy GDT to new location and reload it */ +void move_gdt(unsigned long newgdt) +{ + struct gdtarg gdtarg; + + debug("Moving GDT to %#lx...", newgdt); + memcpy(phys_to_virt(newgdt), gdt, sizeof gdt); + gdtarg.base = newgdt; + gdtarg.limit = GDT_LIMIT; + debug("reloading GDT..."); + __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg)); + debug("reloading CS for fun..."); + __asm__ __volatile__ ("ljmp %0, $1f\n1:" : : "n" (RELOC_CS)); + debug("ok\n"); +} +#endif diff --git a/arch/x86/segment.h b/arch/x86/segment.h new file mode 100644 index 0000000..0371a80 --- /dev/null +++ b/arch/x86/segment.h @@ -0,0 +1,30 @@ + +/* Segment indexes. Must match the gdt definition in segment.c. */ +enum { + NULL_SEG, + FLAT_CODE, + FLAT_DATA, + RELOC_CODE, + RELOC_DATA, + NUM_SEG, +}; + +/* Values for segment selector register */ +#define FLAT_CS (FLAT_CODE << 3) +#define FLAT_DS (FLAT_DATA << 3) +#define RELOC_CS (RELOC_CODE << 3) +#define RELOC_DS (RELOC_DATA << 3) + +/* i386 segment descriptor */ +struct segment_desc { + unsigned short limit_0; + unsigned short base_0; + unsigned char base_16; + unsigned char types; + unsigned char flags; + unsigned char base_24; +}; + +extern struct segment_desc gdt[NUM_SEG]; + +#define GDT_LIMIT ((NUM_SEG << 3) - 1) diff --git a/arch/x86/sys_info.c b/arch/x86/sys_info.c new file mode 100644 index 0000000..84dbc58 --- /dev/null +++ b/arch/x86/sys_info.c @@ -0,0 +1,56 @@ +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "sys_info.h" +#include "context.h" + +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +void collect_multiboot_info(struct sys_info *); + +void collect_sys_info(struct sys_info *info) +{ + int i; + unsigned long long total = 0; + struct memrange *mmap; + + /* Pick up paramters given by bootloader to us */ + info->boot_type = boot_ctx->eax; + info->boot_data = boot_ctx->ebx; + info->boot_arg = boot_ctx->param[0]; + debug("boot eax = %#lx\n", info->boot_type); + debug("boot ebx = %#lx\n", info->boot_data); + debug("boot arg = %#lx\n", info->boot_arg); + + collect_elfboot_info(info); +#ifdef CONFIG_LINUXBIOS + collect_linuxbios_info(info); +#endif +#ifdef CONFIG_IMAGE_ELF_MULTIBOOT + collect_multiboot_info(info); +#endif + + if (!info->memrange) { + printk("Can't get memory map from firmware. " + "Using hardcoded default.\n"); + info->n_memranges = 2; + info->memrange = malloc(2 * sizeof(struct memrange)); + info->memrange[0].base = 0; + info->memrange[0].size = 640*1024; + info->memrange[1].base = 1024*1024; + info->memrange[1].size = 32*1024*1024 + - info->memrange[1].base; + } + + debug("\n"); + mmap=info->memrange; + for (i = 0; i < info->n_memranges; i++) { + debug("%016Lx-", mmap[i].base); + debug("%016Lx\n", mmap[i].base+mmap[i].size); + total += mmap[i].size; + } + debug("RAM %Ld MB\n", (total + 512*1024) >> 20); +} diff --git a/arch/x86/xbox/console.c b/arch/x86/xbox/console.c new file mode 100644 index 0000000..3bdc2d3 --- /dev/null +++ b/arch/x86/xbox/console.c @@ -0,0 +1,39 @@ +/* + * Xbox framebuffer - Video + Console + * + * Copyright (C) 2005 Ed Schouten , + * Stefan Reinauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation + */ + + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/diskio.h" + +typedef struct osi_fb_info { + unsigned long mphys; + int rb, w, h, depth; +} osi_fb_info_t; + +int Xbox_GetFBInfo (osi_fb_info_t *fb) +{ + fb->w = 640; + fb->h = 480; + fb->depth = 32; + fb->rb = fb->w * 4; /* rgb + alpha */ + fb->mphys = phys_to_virt(0x3C00000); /* 60M - 64M */ + + return 0; +} + +#define openbios_GetFBInfo(x) Xbox_GetFBInfo(x) + +#include "../../../modules/video.c" +#include "../../../modules/console.c" + + + diff --git a/arch/x86/xbox/methods.c b/arch/x86/xbox/methods.c new file mode 100644 index 0000000..54f1de2 --- /dev/null +++ b/arch/x86/xbox/methods.c @@ -0,0 +1,108 @@ +/* + * Creation Date: <2004/08/28 18:38:22 greg> + * Time-stamp: <2004/08/28 18:38:22 greg> + * + * + * + * Misc device node methods + * + * Copyright (C) 2004 Greg Watson + * + * Based on MOL specific code which is + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/string.h" +// #include "ofmem.h" + +/************************************************************************/ +/* stdout */ +/************************************************************************/ + +DECLARE_NODE( video_stdout, INSTALL_OPEN, 0, "Tdisplay" ); + +/* ( addr len -- actual ) */ +static void +stdout_write( void ) +{ + int len = POP(); + char *addr = (char*)POP(); + char *s = malloc( len + 1 ); + + strncpy_nopad( s, addr, len ); + s[len]=0; + + printk( "%s", s ); + //vfd_draw_str( s ); + console_draw_str( s ); + + free( s ); + + PUSH( len ); +} + +NODE_METHODS( video_stdout ) = { + { "write", stdout_write }, +}; + + +/************************************************************************/ +/* tty */ +/************************************************************************/ + +DECLARE_NODE( tty, INSTALL_OPEN, 0, "/packages/terminal-emulator" ); + +/* ( addr len -- actual ) */ +static void +tty_read( void ) +{ + int ch, len = POP(); + char *p = (char*)POP(); + int ret=0; + + if( len > 0 ) { + ret = 1; + ch = getchar(); + if( ch >= 0 ) { + *p = ch; + } else { + ret = 0; + } + } + PUSH( ret ); +} + +/* ( addr len -- actual ) */ +static void +tty_write( void ) +{ + int i, len = POP(); + char *p = (char*)POP(); + for( i=0; i + + + + + + + + + + + + + diff --git a/config.xml b/config.xml new file mode 120000 index 0000000..982a804 --- /dev/null +++ b/config.xml @@ -0,0 +1 @@ +config/examples/cross-ppc_config.xml \ No newline at end of file diff --git a/config/examples/amd64_config.xml b/config/examples/amd64_config.xml new file mode 100644 index 0000000..b375b6b --- /dev/null +++ b/config/examples/amd64_config.xml @@ -0,0 +1,72 @@ + + + + + + diff --git a/config/examples/amd64_rules.xml b/config/examples/amd64_rules.xml new file mode 100644 index 0000000..a5e8bec --- /dev/null +++ b/config/examples/amd64_rules.xml @@ -0,0 +1,73 @@ + + +
 $(dir $@)/version.fs
+
+]]>
+ + + + + $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ + + + + $(HOSTCC) $(HOSTCFLAGS) $(HOSTINCLUDES) -c -o $@ $^ + + + + $(AR) cru $@ $^; $(RANLIB) $@ + + + + + + $(CC) $(CFLAGS) -o $@ $^ + + + + $(CC) $$EXTRACFLAGS $(CFLAGS) $(INCLUDES) -c -o $@ $^ + + + + $(AR) cru $@ $^; $(RANLIB) $@ + + +
diff --git a/config/examples/cross-ppc_config.xml b/config/examples/cross-ppc_config.xml new file mode 100644 index 0000000..aeeeaf8 --- /dev/null +++ b/config/examples/cross-ppc_config.xml @@ -0,0 +1,71 @@ + + + + + + + diff --git a/config/examples/cross-ppc_rules.xml b/config/examples/cross-ppc_rules.xml new file mode 100644 index 0000000..d6733fd --- /dev/null +++ b/config/examples/cross-ppc_rules.xml @@ -0,0 +1,97 @@ + + +
 $(dir $@)/version.fs
+
+$(ODIR)/target/include/openbios-version.h:
+	@DATE="$(shell echo `date +'%b %e %Y %H:%M'`)" ; \
+          ( echo "#define OPENBIOS_BUILD_DATE \"$$DATE\"" ; \
+           echo "#define OPENBIOS_VERSION_STR \"$(VERSION)\"" ; \
+           echo "#define OPENBIOS_RELEASE \"$(VERSION)\"" ; ) \
+         > $(dir $@)/openbios-version.h
+mol:
+	@grep CONFIG_MOL $(ODIR)/forth/config.fs >/dev/null && ( \
+	echo "Using MOL path $(MOLPATH)..."; \
+	ln -s $(MOLPATH)/src/shared/osi_calls.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/shared/osi.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/shared/prom.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/include/boothelper_sh.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/include/video_sh.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/include/pseudofs_sh.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/include/kbd_sh.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/drivers/disk/include/scsi_sh.h $(ODIR)/target/include/; \
+	ln -s $(MOLPATH)/src/drivers/disk/include/ablk_sh.h $(ODIR)/target/include/ ) || true
+
+]]>
+ + + + + $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ + + + + $(HOSTCC) $(HOSTCFLAGS) $(HOSTINCLUDES) -c -o $@ $^ + + + + $(AR) cru $@ $^; ranlib $@ + + + + + + $(CC) $(CFLAGS) -o $@ $^ + + + + $(CC) $$EXTRACFLAGS $(CFLAGS) $(INCLUDES) -c -o $@ $^ + + + + $(AR) cru $@ $^; $(RANLIB) $@ + + +
diff --git a/config/examples/x86_config.xml b/config/examples/x86_config.xml new file mode 100644 index 0000000..8874eea --- /dev/null +++ b/config/examples/x86_config.xml @@ -0,0 +1,74 @@ + + + + + + + diff --git a/config/examples/x86_rules.xml b/config/examples/x86_rules.xml new file mode 100644 index 0000000..e20af54 --- /dev/null +++ b/config/examples/x86_rules.xml @@ -0,0 +1,77 @@ + + +
 $(dir $@)/version.fs
+
+]]>
+ + + + + $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ + + + + $(HOSTCC) $(HOSTCFLAGS) $(HOSTINCLUDES) -c -o $@ $^ + + + + $(AR) cru $@ $^; $(RANLIB) $@ + + + + + + $(CC) $(CFLAGS) -o $@ $^ + + + + $(CC) $$EXTRACFLAGS $(CFLAGS) $(INCLUDES) -c -o $@ $^ + + + + $(AR) cru $@ $^; $(RANLIB) $@ + + +
diff --git a/config/scripts/archname b/config/scripts/archname new file mode 100755 index 0000000..df7bc89 --- /dev/null +++ b/config/scripts/archname @@ -0,0 +1,16 @@ +#!/bin/sh + +unset ARCH + +case "$1" in + # ppc|powerpc) ARCH=ppc ;; + # mpc107) ARCH=mpc107 ;; + # osx|darwin) ARCH=osx ;; + ppc|powerpc|mpc107|osx|darwin) ARCH=ppc ;; +esac + +test "$ARCH" || ARCH=`uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/ \ + -e "s/Power Macintosh/ppc/"` + +echo $ARCH diff --git a/config/scripts/reldir b/config/scripts/reldir new file mode 100755 index 0000000..afe043b --- /dev/null +++ b/config/scripts/reldir @@ -0,0 +1,11 @@ +#!/bin/sh + +PREF="." +for x in 0 1 2 3 4 5 6 7 ; do + test -f $PREF/config/configure.in && break + PREF="../$PREF" +done +ROOT=$( echo $(pwd) | sed "s,\(//*[^/][^/]*\)\{$x\}/*\$,," ) +RELNAME=$( echo $(pwd) | sed "s,^$ROOT/*,,g" ) +echo $RELNAME + diff --git a/config/scripts/switch-arch b/config/scripts/switch-arch new file mode 100755 index 0000000..33493d4 --- /dev/null +++ b/config/scripts/switch-arch @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ x"$1" = x ]; then + echo -e "Usage:\n $0 [arch-config]" + echo -e "\narch-config: cross-ppc, x86" + exit 0 +fi + +ARCH=$1 + +rm rules.xml +rm config.xml +ln -s config/examples/${ARCH}_rules.xml rules.xml +ln -s config/examples/${ARCH}_config.xml config.xml + diff --git a/config/xml/config-c.xsl b/config/xml/config-c.xsl new file mode 100644 index 0000000..b49b456 --- /dev/null +++ b/config/xml/config-c.xsl @@ -0,0 +1,52 @@ + + + + + + + /* * Automatically generated C config: don't edit */ + + + + + + + + + + #define + + 1 + + + #undef + + + + ERROR: boolean configuration option '' has unsupported value '' instead of [true|false]. + + + + + + + #define + + + + + + + ERROR: configuration option ' has unsupported type ''. + + + + + + + + + + + + diff --git a/config/xml/config-forth.xsl b/config/xml/config-forth.xsl new file mode 100644 index 0000000..4decba1 --- /dev/null +++ b/config/xml/config-forth.xsl @@ -0,0 +1,38 @@ + + + + + + + + + + + [DEFINE] + + + + + + + + ERROR: boolean configuration option '' has unsupported value '' instead of [true|false]. + + + + + + [DEFINE] + + + + + ERROR: configuration option '' has unsupported type ''. + + + + + + + + diff --git a/config/xml/dictionary.xsl b/config/xml/dictionary.xsl new file mode 100644 index 0000000..0b350f7 --- /dev/null +++ b/config/xml/dictionary.xsl @@ -0,0 +1,162 @@ + + + + + + + # # dictionary rules # + + + + + + + 0 + + + + + + + + + + + + -DICTIONARY := + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + -DICTIONARY:=$( + -DICTIONARY) + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + $(ODIR)/ + .dict: $( + + -DICTIONARY) $(ODIR)/forthstrap + + $(ODIR)/.dict + + + + $(ODIR)/forthstrap + + + + 0 + + + + + + + + + + + + + + + + + -I + + + + + + -I$(ODIR)/forth + + -D $@ + + -d $(ODIR)/.dict + + $( + + -DICTIONARY) + + + + + + dictionaries: + + + + + 0 + + + + + + + + + + + $(ODIR)/ + .dict + + + + + + + diff --git a/config/xml/makefile.xsl b/config/xml/makefile.xsl new file mode 100644 index 0000000..f627b8e --- /dev/null +++ b/config/xml/makefile.xsl @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/config/xml/object.xsl b/config/xml/object.xsl new file mode 100644 index 0000000..178ffdd --- /dev/null +++ b/config/xml/object.xsl @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + # # + + compiler rules # + + + + + + + + + + + + + + 0 + + + + + + + + + + + $(ODIR)/ + + / + + + .o: + + + + + + + + + + + + + + EXTRACFLAGS=" + + " ;\ + + + + + + + + + + + + + + 0 + + + + + + + + + + + + $(ODIR)/ + + : + + + + + + 0 + + + + + + + + + + + + + + + + + + $(ODIR)/ + + / + + + .o + + + + + + + + + 0 + + + + + + + + + $(ODIR)/ + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + $(ODIR)/lib + + + + + .a + + + .so + + + : + + + + + + + + 0 + + + + + + + + + + + + + + + + + + $(ODIR)/ + + / + + + .o + + + + + + + + + + 0 + + + + + + + + + $(ODIR)/ + + + + + + + + + + + + + + + + + -libraries: + + + + + + + -executables: + + + + + + 0 + + + + + + + + $(ODIR)/ + + + + + + + + + diff --git a/config/xml/util.xsl b/config/xml/util.xsl new file mode 100644 index 0000000..afa26ac --- /dev/null +++ b/config/xml/util.xsl @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + No valid relative path + + + + + + + + + CONFIG_ + + + + + + + + + 0 + 1 + + 1 + + Error: has no valid value ''. + + + + + + 1 + + Error: is not a boolean value (''). + + + + + + 0 + + + + + diff --git a/config/xml/xinclude.xsl b/config/xml/xinclude.xsl new file mode 100644 index 0000000..5bcbf53 --- /dev/null +++ b/config/xml/xinclude.xsl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/Kconfig b/drivers/Kconfig new file mode 100644 index 0000000..df17476 --- /dev/null +++ b/drivers/Kconfig @@ -0,0 +1,40 @@ + + +menu "Drivers" + +config DRIVER_PCI + bool "PCI driver" + default y + help + Builtin PCI driver + +config DEBUG_PCI + bool "Debug PCI driver" + default n + help + Debug PCI driver + +config DRIVER_IDE + depends X86 || AMD64 || PPC + bool "Legacy IDE" + default y + help + If you want to be able to boot from IDE, enable this option. + +config IDE_NUM_CHANNELS + depends DRIVER_IDE + int "Number of IDE channels to be probed" + default 4 + help + Number of IDE channels to be probed. This should be set to + one or two if you build OpenBIOS for the Total Impact BRIQ. + +config DEBUG_IDE + depends DRIVER_IDE + bool "Debug IDE driver" + default n + help + Debug IDE driver + +endmenu + diff --git a/drivers/adb.c b/drivers/adb.c new file mode 100644 index 0000000..bee4088 --- /dev/null +++ b/drivers/adb.c @@ -0,0 +1,577 @@ +/* + * + * + * Open Hack'Ware BIOS ADB keyboard support, ported to OpenBIOS + * + * Copyright (c) 2005 Jocelyn Mayer + * Copyright (c) 2005 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License V2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "adb.h" +#include "kbd.h" +#include "cuda.h" + +#define DEBUG_ADB 1 + +#ifdef DEBUG_ADB +#define ADB_DPRINTF(fmt, args...) \ +do { printk("ADB - %s: " fmt, __func__ , ##args); } while (0) +#else +#define ADB_DPRINTF(fmt, args...) do { } while (0) +#endif + +DECLARE_NODE( adb, INSTALL_OPEN, 0, "/pci/via-cuda/adb" ); + +/* ADB US keyboard translation map + * XXX: for now, only shift modifier is defined + */ + + +static keymap_t ADB_kbd_us[] = { + /* 0x00 */ + { KBD_SH_CAPS, { 0x61, 0x41, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x73, 0x53, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x64, 0x44, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x66, 0x46, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x68, 0x48, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x67, 0x47, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x7A, 0x5A, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x78, 0x58, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x08 */ + { KBD_SH_CAPS, { 0x63, 0x43, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x76, 0x56, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x60, 0x40, -1, -1, -1, -1, -1, -1, /* ? */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x62, 0x42, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x71, 0x51, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x77, 0x57, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x65, 0x45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x72, 0x52, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x10 */ + { KBD_SH_CAPS, { 0x79, 0x59, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x74, 0x54, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x31, 0x21, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x32, 0x40, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x33, 0x23, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x34, 0x24, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x36, 0x5E, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x35, 0x25, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x18 */ + { KBD_SH_CAPS, { 0x3D, 0x2B, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x39, 0x28, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x37, 0x26, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x2D, 0x5F, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x38, 0x2A, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x30, 0x29, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x5D, 0x7D, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x6F, 0x4F, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x20 */ + { KBD_SH_CAPS, { 0x75, 0x55, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x5B, 0x7B, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x69, 0x49, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x70, 0x50, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MOD_MAP(0x0D), }, + { KBD_SH_CAPS, { 0x6C, 0x4C, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x6A, 0x4A, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x27, 0x22, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x28 */ + { KBD_SH_CAPS, { 0x6B, 0x4B, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x3B, 0x3A, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x5C, 0x7C, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x2C, 0x3C, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x2F, 0x3F, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x6E, 0x4E, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x6D, 0x4D, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_CAPS, { 0x2E, 0x3E, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x30 : tab */ + { KBD_MOD_MAP(0x09), }, + /* 0x31 : space */ + { KBD_MOD_MAP(0x20), }, + /* 0x32 : '<' '>' */ + { KBD_SH_CAPS, { 0x3C, 0x3E, -1, -1, -1, -1, -1, -1, /* ? */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x33 : backspace */ + { KBD_MOD_MAP(0x08), }, + { KBD_MAP_NONE, }, + /* 0x35 : ESC */ + { KBD_MOD_MAP(0x1B), }, + /* 0x36 : control */ + { KBD_MOD_MAP_LCTRL, }, + /* 0x37 : command */ + { KBD_MOD_MAP_LCMD, }, + /* 0x38 : left shift */ + { KBD_MOD_MAP_LSHIFT, }, + /* 0x39 : caps-lock */ + { KBD_MOD_MAP_CAPS, }, + /* 0x3A : option */ + { KBD_MOD_MAP_LOPT, }, + /* 0x3B : left */ + { KBD_MAP_NONE, }, + /* 0x3C : right */ + { KBD_MAP_NONE, }, + /* 0x3D : down */ + { KBD_MAP_NONE, }, + /* 0x3E : up */ + { KBD_MAP_NONE, }, + { KBD_MAP_NONE, }, + /* 0x40 */ + { KBD_MAP_NONE, }, + { KBD_SH_NUML, { 0x7F, 0x2E, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MAP_NONE, }, + { KBD_SH_NONE, { 0x2A, 0x2A, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MAP_NONE, }, + { KBD_SH_NONE, { 0x2B, 0x2B, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MAP_NONE, }, + { KBD_MOD_MAP(0x7F), }, + /* 0x48 */ + { KBD_MAP_NONE, }, + { KBD_MAP_NONE, }, + { KBD_MAP_NONE, }, + { KBD_SH_NONE, { 0x2F, 0x2F, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MOD_MAP(0x0D), }, + { KBD_MAP_NONE, }, + { KBD_SH_NONE, { 0x2D, 0x2D, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MAP_NONE, }, + /* 0x50 */ + { KBD_MAP_NONE, }, + { KBD_SH_NONE, { 0x3D, 0x3D, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x30, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x31, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x32, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x34, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x35, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + /* 0x58 */ + { KBD_SH_NUML, { -1, 0x36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x37, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MAP_NONE, }, + { KBD_SH_NUML, { -1, 0x38, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_SH_NUML, { -1, 0x39, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, }, }, + { KBD_MAP_NONE, }, + { KBD_MOD_MAP(0x2F), }, + { KBD_MAP_NONE, }, + /* 0x60 : F5 */ + { KBD_MAP_NONE, }, + /* 0x61 : F6 */ + { KBD_MAP_NONE, }, + /* 0x62 : F7 */ + { KBD_MAP_NONE, }, + /* 0x63 : F3 */ + { KBD_MAP_NONE, }, + /* 0x64 : F8 */ + { KBD_MAP_NONE, }, + /* 0x65 : F9 */ + { KBD_MAP_NONE, }, + { KBD_MAP_NONE, }, + /* 0x67 : F11 */ + { KBD_MAP_NONE, }, + /* 0x68 */ + { KBD_MAP_NONE, }, + /* 0x69 : F13 */ + { KBD_MAP_NONE, }, + { KBD_MAP_NONE, }, + /* 0x6B : F14 */ + { KBD_MAP_NONE, }, + { KBD_MAP_NONE, }, + /* 0x6D : F10 */ + { KBD_MAP_NONE, }, + { KBD_MAP_NONE, }, + /* 0x6F : F12 */ + { KBD_MAP_NONE, }, + /* 0x70 */ + { KBD_MAP_NONE, }, + /* 0x71 : F15 */ + { KBD_MAP_NONE, }, + /* 0x72 : help */ + { KBD_MAP_NONE, }, + /* 0x73 : home */ + { KBD_MAP_NONE, }, + /* 0x74 : page up */ + { KBD_MAP_NONE, }, + /* 0x75 : del */ + { KBD_MAP_NONE, }, + /* 0x76 : F4 */ + { KBD_MAP_NONE, }, + /* 0x77 : end */ + { KBD_MAP_NONE, }, + /* 0x78 : F2 */ + { KBD_MAP_NONE, }, + /* 0x79 : page down */ + { KBD_MAP_NONE, }, + /* 0x7A : F1 */ + { KBD_MAP_NONE, }, + /* 0x7B : right shift */ + { KBD_MOD_MAP_RSHIFT, }, + /* 0x7C : right option */ + { KBD_MOD_MAP_ROPT, }, + /* 0x7D : right control */ + { KBD_MOD_MAP_RCTRL, }, + { KBD_MAP_NONE, }, + /* 0x7F : power */ + { KBD_MAP_NONE, }, +}; + +typedef struct adb_kbd_t adb_kbd_t; +struct adb_kbd_t { + kbd_t kbd; + int next_key; +}; + + + + + +static adb_kbd_t *my_adb_kbd; +adb_dev_t *my_adb_dev; +//={ NULL, NULL, 2, 1, (unsigned int)0x80816000 }; + +static int adb_kbd_read (void *private) +{ + uint8_t buffer[ADB_BUF_SIZE]; + adb_dev_t *dev = private; + adb_kbd_t *kbd; + int key; + int ret; + + kbd = (void *)dev->state; + //ADB_DPRINTF("enter\n"); + /* Get saved state */ + ret = -1; + for (key = -1; key == -1; ) { + if (kbd->next_key != -1) { + key = kbd->next_key; + kbd->next_key = -1; + } else { + if (adb_reg_get(dev, 0, buffer) != 2) { + goto out; + } + kbd->next_key = buffer[1] == 0xFF ? -1 : buffer[1]; + key = buffer[0]; + } + ret = kbd_translate_key(&kbd->kbd, key & 0x7F, key >> 7); + ADB_DPRINTF("Translated %d (%02x) into %d (%02x)\n", + key, key, ret, ret); + } + out: + + return ret; +} + + +void *adb_kbd_new (void *private) +{ + adb_kbd_t *kbd=my_adb_kbd; + + memset(kbd, 0, sizeof(adb_kbd_t)); + kbd_set_keymap(&kbd->kbd, sizeof(ADB_kbd_us) / sizeof(keymap_t), ADB_kbd_us); + kbd->next_key = -1; + + //my_adb_dev.state=(unsigned int)my_adb_kbd; + my_adb_dev=private; + return NULL; +} + +/* ( addr len -- actual ) */ +void adb_read(void) +{ + char *addr; + int len, key; + len=POP(); + addr=(char *)POP(); + + if(len!=1) printk("adb_read: %x %x\n", (unsigned int)addr , len); + + key=adb_kbd_read(my_adb_dev); + //key=-1; + if (key!=-1) { + *addr=(char)key; + PUSH(1); + } else + PUSH(0); +} + + +int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg, + uint8_t *buf, int len) +{ + uint8_t adb_send[ADB_BUF_SIZE], adb_rcv[ADB_BUF_SIZE]; + + //ADB_DPRINTF("cmd: %d reg: %d len: %d\n", cmd, reg, len); + if (dev->bus == NULL || dev->bus->req == NULL) { + ADB_DPRINTF("ERROR: invalid bus !\n"); + for (;;); + } + /* Sanity checks */ + if (cmd != ADB_LISTEN && len != 0) { + /* No buffer transmitted but for LISTEN command */ + ADB_DPRINTF("in buffer for cmd %d\n", cmd); + return -1; + } + if (cmd == ADB_LISTEN && ((len < 2 || len > 8) || buf == NULL)) { + /* Need a buffer with a regular register size for LISTEN command */ + ADB_DPRINTF("no/invalid buffer for ADB_LISTEN (%d)\n", len); + return -1; + } + if ((cmd == ADB_TALK || cmd == ADB_LISTEN) && reg > 3) { + /* Need a valid register number for LISTEN and TALK commands */ + ADB_DPRINTF("invalid reg for TALK/LISTEN command (%d %d)\n", cmd, reg); + return -1; + } + switch (cmd) { + case ADB_SEND_RESET: + adb_send[0] = ADB_SEND_RESET; + break; + case ADB_FLUSH: + adb_send[0] = (dev->addr << 4) | ADB_FLUSH; + break; + case ADB_LISTEN: + memcpy(adb_send + 1, buf, len); + /* No break here */ + case ADB_TALK: + adb_send[0] = (dev->addr << 4) | cmd | reg; + break; + } + memset(adb_rcv, 0, ADB_BUF_SIZE); + len = (*dev->bus->req)(dev->bus->host, adb_send, len + 1, adb_rcv); +#ifdef DEBUG_ADB + //printk("%x %x %x %x\n", adb_rcv[0], adb_rcv[1], adb_rcv[2], adb_rcv[3]); +#endif + switch (len) { + case 0: + /* No data */ + break; + case 2 ... 8: + /* Register transmitted */ + if (buf != NULL) + memcpy(buf, adb_rcv, len); + break; + default: + /* Should never happen */ + //ADB_DPRINTF("Cmd %d returned %d bytes !\n", cmd, len); + return -1; + } + //ADB_DPRINTF("retlen: %d\n", len); + + return len; +} + + +NODE_METHODS( adb ) = { + { "read", adb_read }, +}; + +int ob_adb_init(void) +{ + printk("Initializing ADB driver\n"); + cuda_init(0x80800000 + 0x16000); + REGISTER_NODE( adb ); + //adb_kbd_new(); + return 0; +} + diff --git a/drivers/adb.fs b/drivers/adb.fs new file mode 100644 index 0000000..c88b163 --- /dev/null +++ b/drivers/adb.fs @@ -0,0 +1,33 @@ +[IFDEF] CONFIG_DRIVER_ADB + +dev /pci +\ simple pci bus node +new-device +" via-cuda" device-name +" via-cuda" encode-string " device_type" property +" cuda" encode-string " compatible" property + +external +: open ( ." opening CUDA" cr ) true ; +: close ; +: decode-unit 0 decode-unit-pci-bus ; +: encode-unit encode-unit-pci ; +finish-device + +dev /pci/via-cuda + +new-device +" adb" device-name +" adb" encode-string " device_type" property +0 encode-int " #size-cells" property +1 encode-int " #address-cells" property + +external +: open ( ." opening ADB" cr ) true ; +: close ; +finish-device + +device-end + +[THEN] + diff --git a/drivers/adb.h b/drivers/adb.h new file mode 100644 index 0000000..c492481 --- /dev/null +++ b/drivers/adb.h @@ -0,0 +1,107 @@ +/* + * ADB bus definitions for Open Hack'Ware + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License V2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#if !defined(__OHW_ADB_H__) +#define __OHW_ADB_H__ + +#include + +typedef struct adb_bus_t adb_bus_t; +typedef struct adb_dev_t adb_dev_t; + +#define ADB_BUF_SIZE 8 +struct adb_bus_t { + void *host; + int (*req)(void *host, const uint8_t *snd_buf, int len, uint8_t *rcv_buf); + adb_dev_t *devices; +}; + +struct adb_dev_t { + adb_dev_t *next; + adb_bus_t *bus; + uint8_t addr; + uint8_t type; + uint32_t state; +}; + +#define ADB_BUF_SIZE 8 + +/* ADB commands */ +enum { + ADB_SEND_RESET = 0x00, + ADB_FLUSH = 0x01, + ADB_LISTEN = 0x08, + ADB_TALK = 0x0C, +}; +/* ADB default IDs before relocation */ +enum { + ADB_PROTECT = 0x01, + ADB_KEYBD = 0x02, + ADB_MOUSE = 0x03, + ADB_ABS = 0x04, + ADB_MODEM = 0x05, + ADB_RES = 0x06, + ADB_MISC = 0x07, +}; +/* ADB special device handlers IDs */ +enum { + ADB_CHADDR = 0x00, + ADB_CHADDR_ACTIV = 0xFD, + ADB_CHADDR_NOCOLL = 0xFE, + ADB_SELF_TEST = 0xFF, +}; + +int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg, + uint8_t *buf, int len); +void adb_bus_reset (adb_bus_t *bus); +adb_bus_t *adb_bus_new (void *host, + int (*req)(void *host, const uint8_t *snd_buf, + int len, uint8_t *rcv_buf)); +int adb_bus_init (adb_bus_t *bus); + +static inline int adb_reset (adb_bus_t *bus) +{ + adb_dev_t fake_device; + + memset(&fake_device, 0, sizeof(adb_dev_t)); + fake_device.bus = bus; + + return adb_cmd(&fake_device, ADB_SEND_RESET, 0, NULL, 0); +} + +static inline int adb_flush (adb_dev_t *dev) +{ + return adb_cmd(dev, ADB_FLUSH, 0, NULL, 0); +} + +static inline int adb_reg_get (adb_dev_t *dev, uint8_t reg, uint8_t *buf) +{ + return adb_cmd(dev, ADB_TALK, reg, buf, 0); +} + +static inline int adb_reg_set (adb_dev_t *dev, uint8_t reg, + uint8_t *buf, int len) +{ + return adb_cmd(dev, ADB_LISTEN, reg, buf, len); +} + +void *adb_kbd_new (void *private); + + +#endif /* !defined(__OHW_ADB_H__) */ diff --git a/drivers/build.xml b/drivers/build.xml new file mode 100644 index 0000000..bfa3db5 --- /dev/null +++ b/drivers/build.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/drivers/cuda.c b/drivers/cuda.c new file mode 100644 index 0000000..ec6b593 --- /dev/null +++ b/drivers/cuda.c @@ -0,0 +1,297 @@ +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "adb.h" + + +#include "cuda.h" +#define DEBUG_CUDA +#ifdef DEBUG_CUDA +#define CUDA_DPRINTF(fmt, args...) \ + do { printk("CUDA - %s: " fmt, __func__ , ##args); } while (0) +#else +#define CUDA_DPRINTF(fmt, args...) do { } while (0) +#endif +#define ADB_DPRINTF CUDA_DPRINTF + +/* VIA registers - spaced 0x200 bytes apart */ +#define RS 0x200 /* skip between registers */ +#define B 0 /* B-side data */ +#define A RS /* A-side data */ +#define DIRB (2*RS) /* B-side direction (1=output) */ +#define DIRA (3*RS) /* A-side direction (1=output) */ +#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ +#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ +#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ +#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ +#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ +#define SR (10*RS) /* Shift register */ +#define ACR (11*RS) /* Auxiliary control register */ +#define PCR (12*RS) /* Peripheral control register */ +#define IFR (13*RS) /* Interrupt flag register */ +#define IER (14*RS) /* Interrupt enable register */ +#define ANH (15*RS) /* A-side data, no handshake */ + +/* Bits in B data register: all active low */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#define SR_EXT 0x0c /* Shift on external clock */ +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ + +#define CUDA_BUF_SIZE 16 + +#define ADB_PACKET 0 +#define CUDA_PACKET 1 + +static uint8_t cuda_readb (cuda_t *dev, int reg) +{ + return *(volatile uint8_t *)(dev->base + reg); +} + +static void cuda_writeb (cuda_t *dev, int reg, uint8_t val) +{ + *(volatile uint8_t *)(dev->base + reg) = val; +} + +static void cuda_wait_irq (cuda_t *dev) +{ + int val; + +// CUDA_DPRINTF("\n"); + for(;;) { + val = cuda_readb(dev, IFR); + cuda_writeb(dev, IFR, val & 0x7f); + if (val & SR_INT) + break; + } +} + + + +static int cuda_request (cuda_t *dev, uint8_t pkt_type, const uint8_t *buf, + int buf_len, uint8_t *obuf) +{ + int i, obuf_len, val; + + cuda_writeb(dev, ACR, cuda_readb(dev, ACR) | SR_OUT); + cuda_writeb(dev, SR, pkt_type); + cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP); + if (buf) { + //CUDA_DPRINTF("Send buf len: %d\n", buf_len); + /* send 'buf' */ + for(i = 0; i < buf_len; i++) { + cuda_wait_irq(dev); + cuda_writeb(dev, SR, buf[i]); + cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK); + } + } + cuda_wait_irq(dev); + cuda_writeb(dev, ACR, cuda_readb(dev, ACR) & ~SR_OUT); + cuda_readb(dev, SR); + cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK); + + obuf_len = 0; + if (obuf) { + cuda_wait_irq(dev); + cuda_readb(dev, SR); + cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP); + for(;;) { + cuda_wait_irq(dev); + val = cuda_readb(dev, SR); + if (obuf_len < CUDA_BUF_SIZE) + obuf[obuf_len++] = val; + if (cuda_readb(dev, B) & TREQ) + break; + cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK); + } + cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK); + + cuda_wait_irq(dev); + cuda_readb(dev, SR); + } +// CUDA_DPRINTF("Got len: %d\n", obuf_len); + + return obuf_len; +} + + + +static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len, + uint8_t *rcv_buf) +{ + uint8_t buffer[CUDA_BUF_SIZE], *pos; + + // CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]); + len = cuda_request(host, ADB_PACKET, snd_buf, len, buffer); + if (len > 1 && buffer[0] == ADB_PACKET) { + pos = buffer + 2; + len -= 2; + } else { + pos = buffer + 1; + len = -1; + } + memcpy(rcv_buf, pos, len); + + return len; +} + + +cuda_t *cuda_init (uint32_t base) +{ + cuda_t *cuda; + + //CUDA_DPRINTF(" base=%08x\n", base); + cuda = malloc(sizeof(cuda_t)); + if (cuda == NULL) + return NULL; + cuda->base = base; + cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP); + cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req); + if (cuda->adb_bus == NULL) { + free(cuda); + return NULL; + } + adb_bus_init(cuda->adb_bus); + + return cuda; +} + + +adb_bus_t *adb_bus_new (void *host, + int (*req)(void *host, const uint8_t *snd_buf, + int len, uint8_t *rcv_buf)) +{ + adb_bus_t *new; + + new = malloc(sizeof(adb_bus_t)); + if (new == NULL) + return NULL; + new->host = host; + new->req = req; + + return new; +} + +/* Check and relocate all ADB devices as suggested in + * * ADB_manager Apple documentation + * */ +int adb_bus_init (adb_bus_t *bus) +{ + uint8_t buffer[ADB_BUF_SIZE]; + uint8_t adb_addresses[16] = + { 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, 0, }; + adb_dev_t tmp_device, **cur; + int address; + int reloc = 0, next_free = 7; + int keep; + + /* Reset the bus */ + // ADB_DPRINTF("\n"); + adb_reset(bus); + cur = &bus->devices; + memset(&tmp_device, 0, sizeof(adb_dev_t)); + tmp_device.bus = bus; + for (address = 1; address < 8 && adb_addresses[reloc] > 0;) { + if (address == ADB_RES) { + /* Reserved */ + address++; + continue; + } + //ADB_DPRINTF("Check device on ADB address %d\n", address); + tmp_device.addr = address; + switch (adb_reg_get(&tmp_device, 3, buffer)) { + case 0: + //ADB_DPRINTF("No device on ADB address %d\n", address); + /* Register this address as free */ + if (adb_addresses[next_free] != 0) + adb_addresses[next_free++] = address; + /* Check next ADB address */ + address++; + break; + case 2: + /* One device answered : + * make it available and relocate it to a free address + */ + if (buffer[0] == ADB_CHADDR) { + /* device self test failed */ + ADB_DPRINTF("device on ADB address %d self-test failed " + "%02x %02x %02x\n", address, + buffer[0], buffer[1], buffer[2]); + keep = 0; + } else { + //ADB_DPRINTF("device on ADB address %d self-test OK\n", + // address); + keep = 1; + } + ADB_DPRINTF("Relocate device on ADB address %d to %d (%d)\n", + address, adb_addresses[reloc], reloc); + buffer[0] = ((buffer[0] & 0x40) & ~0x90) | adb_addresses[reloc]; + if (keep == 1) + buffer[0] |= 0x20; + buffer[1] = ADB_CHADDR_NOCOLL; + if (adb_reg_set(&tmp_device, 3, buffer, 2) < 0) { + ADB_DPRINTF("ADB device relocation failed\n"); + return -1; + } + if (keep == 1) { + *cur = malloc(sizeof(adb_dev_t)); + if (*cur == NULL) { + return -1; + } + (*cur)->type = address; + (*cur)->bus = bus; + (*cur)->addr = adb_addresses[reloc++]; + /* Flush buffers */ + adb_flush(*cur); + switch ((*cur)->type) { + case ADB_PROTECT: + ADB_DPRINTF("Found one protected device\n"); + break; + case ADB_KEYBD: + ADB_DPRINTF("Found one keyboard on address %d\n", address); + adb_kbd_new(*cur); + break; + case ADB_MOUSE: + ADB_DPRINTF("Found one mouse on address %d\n", address); + //chardev_register(CHARDEV_MOUSE, &adb_mouse_ops, *cur); + break; + case ADB_ABS: + ADB_DPRINTF("Found one absolute positioning device\n"); + break; + case ADB_MODEM: + ADB_DPRINTF("Found one modem\n"); + break; + case ADB_RES: + ADB_DPRINTF("Found one ADB res device\n"); + break; + case ADB_MISC: + ADB_DPRINTF("Found one ADB misc device\n"); + break; + } + cur = &((*cur)->next); + } + break; + case 1: + case 3 ... 7: + /* SHOULD NOT HAPPEN : register 3 is always two bytes long */ + ADB_DPRINTF("Invalid returned len for ADB register 3\n"); + return -1; + case -1: + /* ADB ERROR */ + ADB_DPRINTF("error gettting ADB register 3\n"); + return -1; + } + } + + return 0; +} + diff --git a/drivers/cuda.h b/drivers/cuda.h new file mode 100644 index 0000000..fbfea65 --- /dev/null +++ b/drivers/cuda.h @@ -0,0 +1,20 @@ +#include "adb.h" + +struct cuda_t { + uint32_t base; + adb_bus_t *adb_bus; +}; +typedef struct cuda_t cuda_t; + +enum { + CHARDEV_KBD = 0, + CHARDEV_MOUSE, + CHARDEV_SERIAL, + CHARDEV_DISPLAY, + CHARDEV_LAST, +}; + + +cuda_t *cuda_init (uint32_t base); + + diff --git a/drivers/floppy.c b/drivers/floppy.c new file mode 100644 index 0000000..bdd686e --- /dev/null +++ b/drivers/floppy.c @@ -0,0 +1,1143 @@ +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/kernel.h" +#include "libc/byteorder.h" +#include "libc/vsprintf.h" + +#include "openbios/drivers.h" + +#include "timer.h" + +#define REGISTER_NAMED_NODE( name, path ) do { \ + bind_new_node( name##_flags_, name##_size_, \ + path, name##_m, sizeof(name##_m)/sizeof(method_t)); \ + } while(0) + +/* DECLARE data structures for the nodes. */ +DECLARE_UNNAMED_NODE( ob_floppy, INSTALL_OPEN, 2*sizeof(int) ); + +#define printk_info printk +#define printk_debug printk +#define printk_err printk + +#ifndef FD_BASE +#define FD_BASE 0x3f0 +#endif + +#define FD_DRIVE 0 + + +#define FD_STATUS_A (FD_BASE + 0) /* Status register A */ +#define FD_STATUS_B (FD_BASE + 1) /* Status register B */ +#define FD_DOR (FD_BASE + 2) /* Digital Output Register */ +#define FD_TDR (FD_BASE + 3) /* Tape Drive Register */ +#define FD_STATUS (FD_BASE + 4) /* Main Status Register */ +#define FD_DSR (FD_BASE + 4) /* Data Rate Select Register (old) */ +#define FD_DATA (FD_BASE + 5) /* Data Transfer (FIFO) register */ +#define FD_DIR (FD_BASE + 7) /* Digital Input Register (read) */ +#define FD_DCR (FD_BASE + 7) /* Diskette Control Register (write)*/ + +/* Bit of FD_STATUS_A */ +#define STA_INT_PENDING 0x80 /* Interrupt Pending */ + +/* DOR */ +#define DOR_DRIVE0 0x00 +#define DOR_DRIVE1 0x01 +#define DOR_DRIVE2 0x02 +#define DOR_DRIVE3 0x03 +#define DOR_DRIVE_MASK 0x03 +#define DOR_NO_RESET 0x04 +#define DOR_DMA_EN 0x08 +#define DOR_MOT_EN0 0x10 +#define DOR_MOT_EN1 0x20 +#define DOR_MOT_EN2 0x40 +#define DOR_MOT_EN3 0x80 + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_NON_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment check error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ +#define ST0_INTR_OK (0 << 6) +#define ST0_INTR_ERROR (1 << 6) +#define ST0_INTR_INVALID (2 << 6) +#define ST0_INTR_POLL_ERROR (3 << 6) + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Address Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_DS 0x08 /* drive is double-sided */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_RY 0x20 /* drive is ready */ +#define ST3_WP 0x40 /* Write Protect */ +#define ST3_FT 0x80 /* Drive Fault */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xA6 /* read with MT, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ +#define FD_FORMAT 0x4D /* format one track */ +#define FD_VERSION 0x10 /* get version code */ +#define FD_CONFIGURE 0x13 /* configure FIFO operation */ +#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */ +#define FD_GETSTATUS 0x04 /* read ST3 */ +#define FD_DUMPREGS 0x0E /* dump the contents of the fdc regs */ +#define FD_READID 0xEA /* prints the header of a sector */ +#define FD_UNLOCK 0x14 /* Fifo config unlock */ +#define FD_LOCK 0x94 /* Fifo config lock */ +#define FD_RSEEK_OUT 0x8f /* seek out (i.e. to lower tracks) */ +#define FD_RSEEK_IN 0xcf /* seek in (i.e. to higher tracks) */ + + +/* the following commands are new in the 82078. They are not used in the + * floppy driver, except the first three. These commands may be useful for apps + * which use the FDRAWCMD interface. For doc, get the 82078 spec sheets at + * http://www-techdoc.intel.com/docs/periph/fd_contr/datasheets/ */ + +#define FD_PARTID 0x18 /* part id ("extended" version cmd) */ +#define FD_SAVE 0x2e /* save fdc regs for later restore */ +#define FD_DRIVESPEC 0x8e /* drive specification: Access to the + * 2 Mbps data transfer rate for tape + * drives */ + +#define FD_RESTORE 0x4e /* later restore */ +#define FD_POWERDOWN 0x27 /* configure FDC's powersave features */ +#define FD_FORMAT_N_WRITE 0xef /* format and write in one go. */ +#define FD_OPTION 0x33 /* ISO format (which is a clean way to + * pack more sectors on a track) */ + +/* FDC version return types */ +#define FDC_NONE 0x00 +#define FDC_UNKNOWN 0x10 /* DO NOT USE THIS TYPE EXCEPT IF IDENTIFICATION + FAILS EARLY */ +#define FDC_8272A 0x20 /* Intel 8272a, NEC 765 */ +#define FDC_765ED 0x30 /* Non-Intel 1MB-compatible FDC, can't detect */ +#define FDC_82072 0x40 /* Intel 82072; 8272a + FIFO + DUMPREGS */ +#define FDC_82072A 0x45 /* 82072A (on Sparcs) */ +#define FDC_82077_ORIG 0x51 /* Original version of 82077AA, sans LOCK */ +#define FDC_82077 0x52 /* 82077AA-1 */ +#define FDC_82078_UNKN 0x5f /* Unknown 82078 variant */ +#define FDC_82078 0x60 /* 44pin 82078 or 64pin 82078SL */ +#define FDC_82078_1 0x61 /* 82078-1 (2Mbps fdc) */ +#define FDC_S82078B 0x62 /* S82078B (first seen on Adaptec AVA-2825 VLB + * SCSI/EIDE/Floppy controller) */ +#define FDC_87306 0x63 /* National Semiconductor PC 87306 */ + +/* + * Beware: the fdc type list is roughly sorted by increasing features. + * Presence of features is tested by comparing the FDC version id with the + * "oldest" version that has the needed feature. + * If during FDC detection, an obscure test fails late in the sequence, don't + * assign FDC_UNKNOWN. Else the FDC will be treated as a dumb 8272a, or worse. + * This is especially true if the tests are unneeded. + */ + +/* Parameters for a 1.44 3.5" disk */ +#define DISK_H1440_SIZE 2880 +#define DISK_H1440_SECT 18 +#define DISK_H1440_HEAD 2 +#define DISK_H1440_TRACK 80 +#define DISK_H1440_STRETCH 0 +#define DISK_H1440_GAP 0x1B +#define DISK_H1440_RATE 0x00 +#define DISK_H1440_SPEC1 0xCF +#define DISK_H1440_FMT_GAP 0x6C + +/* Parameters for a 1.44 3.5" drive */ +#define DRIVE_H1440_MAX_DTR 500 +#define DRIVE_H1440_HLT 16 /* ms */ +#define DRIVE_H1440_HUT 16 /* ms */ +#define DRIVE_H1440_SRT 4000 /* us */ +#define DRIVE_H1440_SPINUP 400 /* ms */ +#define DRIVE_H1440_SPINDOWN 3000 /* ms */ +#define DRIVE_H1440_SPINDOWN_OFFSET 10 +#define DRIVE_H1440_SELECT_DELAY 20 /* ms */ +#define DRIVE_H1440_RPS 5 +#define DRIVE_H1440_TRACKS 83 +#define DRIVE_H1440_TIMEOUT 3000 /* ms */ +#define DRIVE_H1440_INTERLEAVE_SECT 20 + +/* Floppy drive configuration */ +#define FIFO_DEPTH 10 +#define USE_IMPLIED_SEEK 0 +#define USE_FIFO 1 +#define FIFO_THRESHOLD 10 +#define TRACK_PRECOMPENSATION 0 + +#define SLOW_FLOPPY 0 + +#define FD_RESET_DELAY 20 /* microseconds */ + +/* + * FDC state + */ +struct drive_state { + unsigned track; +} drive_state[1]; + +struct floppy_fdc_state { + int in_sync; + int spec1; /* spec1 value last used */ + int spec2; /* spec2 value last used */ + int dtr; + unsigned char dor; + unsigned char version; /* FDC version code */ +} fdc_state; + + + +/* Synchronization of FDC access. */ +#define FD_COMMAND_NONE -1 +#define FD_COMMAND_ERROR 2 +#define FD_COMMAND_OKAY 3 + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 16 + +static void show_floppy(void); +static void floppy_reset(void); + + +static int set_dor(int fdc, char mask, char data) +{ + unsigned char newdor,olddor; + + olddor = fdc_state.dor; + newdor = (olddor & mask) | data; + if (newdor != olddor){ + fdc_state.dor = newdor; + outb(newdor, FD_DOR); + } + return olddor; +} + + +static void bounce_motor(void) +{ + /* Bounce the drive motor... */ + outb(fdc_state.dor & ~(0x10<> 2) & 1; + int status; + unsigned new_dor; + if (drive > 3) { + printk_err("bad drive value\n"); + return; + } + if (fdc != 0) { + printk_err("bad fdc value\n"); + return; + } + drive &= 3; +#if 0 + new_dor = 8; /* Enable the controller */ +#else + new_dor = 0; /* Don't enable DMA on the controller */ +#endif + new_dor |= (1 << (drive + 4)); /* Spinup the selected drive */ + new_dor |= drive; /* Select the drive for commands as well */ + set_dor(fdc, 0xc, new_dor); + + mdelay(DRIVE_H1440_SPINUP); + + status = inb(FD_STATUS); + printk_debug("set_drive status = %02x, new_dor = %02x\n", + status, new_dor); + if (status != STATUS_READY) { + printk_err("set_drive bad status\n"); + } +} + + +/* Disable the motor for a given floppy drive */ +static void floppy_motor_off(int drive) +{ + unsigned mask; + printk_debug("floppy_motor_off\n"); + /* fix the number of drives */ + drive &= 3; + /* Clear the bit for the drive we care about */ + mask = 0xff; + mask &= ~(1 << (drive +4)); + /* Now clear the bit in the Digital Output Register */ + set_dor(0, mask, 0); +} + +/* Set the FDC's data transfer rate on behalf of the specified drive. + * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue + * of the specify command (i.e. using the fdc_specify function). + */ +static void fdc_dtr(unsigned rate) +{ + rate &= 3; + /* If data rate not already set to desired value, set it. */ + if (fdc_state.in_sync && (rate == fdc_state.dtr)) + return; + + /* Set dtr */ + outb(rate, FD_DCR); + + /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB) + * need a stabilization period of several milliseconds to be + * enforced after data rate changes before R/W operations. + * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) + */ + fdc_state.dtr = rate & 3; + mdelay(5); +} /* fdc_dtr */ + +static int fdc_configure(int use_implied_seek, int use_fifo, + unsigned fifo_threshold, unsigned precompensation) +{ + unsigned config_bits; + unsigned char cmd[4]; + /* 0 EIS EFIFO POLL FIFOOTHR[4] */ + + /* santize parameters */ + config_bits = fifo_threshold & 0xf; + config_bits |= (1 << 4); /* Always disable background floppy poll */ + config_bits |= (!use_fifo) << 5; + config_bits |= (!!use_implied_seek) << 6; + + precompensation &= 0xff; /* pre-compensation from track 0 upwards */ + + cmd[0] = FD_CONFIGURE; + cmd[1] = 0; + cmd[2] = config_bits; + cmd[3] = precompensation; + + /* Turn on FIFO */ + if (output_new_command(cmd, 4) < 0) + return 0; + return 1; +} + +#define NOMINAL_DTR 500 +/* Issue a "SPECIFY" command to set the step rate time, head unload time, + * head load time, and DMA disable flag to values needed by floppy. + * + * The value "dtr" is the data transfer rate in Kbps. It is needed + * to account for the data rate-based scaling done by the 82072 and 82077 + * FDC types. This parameter is ignored for other types of FDCs (i.e. + * 8272a). + * + * Note that changing the data transfer rate has a (probably deleterious) + * effect on the parameters subject to scaling for 82072/82077 FDCs, so + * fdc_specify is called again after each data transfer rate + * change. + * + * srt: 1000 to 16000 in microseconds + * hut: 16 to 240 milliseconds + * hlt: 2 to 254 milliseconds + * + * These values are rounded up to the next highest available delay time. + */ +static void fdc_specify( + unsigned head_load_time, unsigned head_unload_time, unsigned step_rate) +{ + unsigned char cmd[3]; + unsigned long srt, hlt, hut; + unsigned long dtr = NOMINAL_DTR; + unsigned long scale_dtr = NOMINAL_DTR; + int hlt_max_code = 0x7f; + int hut_max_code = 0xf; + + printk_debug("fdc_specify\n"); + + switch (DISK_H1440_RATE & 0x03) { + case 3: + dtr = 1000; + break; + case 1: + dtr = 300; + if (fdc_state.version >= FDC_82078) { + unsigned char cmd[3]; + /* chose the default rate table, not the one + * where 1 = 2 Mbps */ + cmd[0] = FD_DRIVESPEC; + cmd[1] = FD_DRIVE & 3; + cmd[2] = 0xc0; + output_new_command(cmd,3); + /* FIXME how do I handle errors here? */ + } + break; + case 2: + dtr = 250; + break; + } + + + if (fdc_state.version >= FDC_82072) { + scale_dtr = dtr; + hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */ + hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */ + } + + /* Convert step rate from microseconds to milliseconds and 4 bits */ + srt = 16 - (step_rate*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR; + if (SLOW_FLOPPY) { + srt = srt / 4; + } + if (srt > 0xf) { + srt = 0xf; + } + if (srt < 0 ) { + srt = 0; + } + + hlt = (head_load_time*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR; + if (hlt < 0x01) + hlt = 0x01; + else if (hlt > 0x7f) + hlt = hlt_max_code; + + hut = (head_unload_time*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR; + if (hut < 0x1) + hut = 0x1; + else if (hut > 0xf) + hut = hut_max_code; + + cmd[0] = FD_SPECIFY; + cmd[1] = (srt << 4) | hut; + cmd[2] = (hlt << 1) | 1; /* Always disable DMA */ + + /* If these parameters did not change, just return with success */ + if (!fdc_state.in_sync || fdc_state.spec1 != cmd[1] || fdc_state.spec2 != cmd[2]) { + /* Go ahead and set spec1 and spec2 */ + output_command(cmd, 3); + /* FIXME how do I handle errors here... */ + printk_info("FD_SPECIFY(%02x, %02x)\n", cmd[1], cmd[2]); + } +} /* fdc_specify */ + + +/* + * reset is done by pulling bit 2 of DOR low for a while (old FDCs), + * or by setting the self clearing bit 7 of STATUS (newer FDCs) + */ +static void reset_fdc(void) +{ + unsigned char reply[MAX_REPLIES]; + + fdc_state.in_sync = 0; + + /* Pseudo-DMA may intercept 'reset finished' interrupt. */ + /* Irrelevant for systems with true DMA (i386). */ + + if (fdc_state.version >= FDC_82072A) + outb(0x80 | (fdc_state.dtr &3), FD_DSR); + else { + outb(fdc_state.dor & ~DOR_NO_RESET, FD_DOR); + udelay(FD_RESET_DELAY); + outb(fdc_state.dor, FD_DOR); + } + result(reply, MAX_REPLIES); +} + + + +static void show_floppy(void) +{ + + printk_debug("\n"); + printk_debug("floppy driver state\n"); + printk_debug("-------------------\n"); + + printk_debug("fdc_bytes: %02x %02x xx %02x %02x %02x xx %02x\n", + inb(FD_BASE + 0), inb(FD_BASE + 1), + inb(FD_BASE + 3), inb(FD_BASE + 4), inb(FD_BASE + 5), + inb(FD_BASE + 7)); + + printk_debug("status=%x\n", inb(FD_STATUS)); + printk_debug("\n"); +} + +static void floppy_recalibrate(void) +{ + unsigned char cmd[2]; + unsigned char reply[MAX_REPLIES]; + int nr, success; + success = 0; + do { + printk_debug("floppy_recalibrate\n"); + /* Send the recalibrate command to the controller. + * We don't have interrupts or anything we can poll + * so we have to guess when it is done. + */ + cmd[0] = FD_RECALIBRATE; + cmd[1] = 0; + if (output_command(cmd, 2) < 0) + continue; + + /* Sleep for the maximum time the recalibrate command + * can run. + */ + mdelay(80*DRIVE_H1440_SRT/1000); + + /* Now call FD_SENSEI to end the command + * and collect up the reply. + */ + if (output_byte(FD_SENSEI) < 0) + continue; + nr = result(reply, MAX_REPLIES); + + /* Now see if we have succeeded in our seek */ + success = + /* We have the right size result */ + (nr == 2) && + /* The command didn't terminate in error */ + ((reply[0] & ST0_INTR) == ST0_INTR_OK) && + /* We finished a seek */ + (reply[0] & ST0_SE) && + /* We are at cylinder 0 */ + (reply[1] == 0); + } while(!success); + /* Remember we are at track 0 */ + drive_state[FD_DRIVE].track = 0; +} + + +static int floppy_seek(unsigned track) +{ + unsigned char cmd[3]; + unsigned char reply[MAX_REPLIES]; + int nr, success; + unsigned distance, old_track; + + /* Look up the old track and see if we need to + * do anything. + */ + old_track = drive_state[FD_DRIVE].track; + if (old_track == track) { + return 1; + } + + /* Compute the distance we are about to move, + * We need to know this so we know how long to sleep... + */ + distance = (old_track > track)?(old_track - track):(track - old_track); + distance += 1; + + + /* Send the seek command to the controller. + * We don't have interrupts or anything we can poll + * so we have to guess when it is done. + */ + cmd[0] = FD_SEEK; + cmd[1] = FD_DRIVE; + cmd[2] = track; + if (output_command(cmd, 3) < 0) + return 0; + + /* Sleep for the time it takes to step throuhg distance tracks. + */ + mdelay(distance*DRIVE_H1440_SRT/1000); + + /* Now call FD_SENSEI to end the command + * and collect up the reply. + */ + cmd[0] = FD_SENSEI; + if (output_command(cmd, 1) < 0) + return 0; + nr = result(reply, MAX_REPLIES); + + /* Now see if we have succeeded in our seek */ + success = + /* We have the right size result */ + (nr == 2) && + /* The command didn't terminate in error */ + ((reply[0] & ST0_INTR) == ST0_INTR_OK) && + /* We finished a seek */ + (reply[0] & ST0_SE) && + /* We are at cylinder 0 */ + (reply[1] == track); + if (success) + drive_state[FD_DRIVE].track = track; + else { + int i; + printk_debug("seek failed\n"); + printk_debug("nr = %d\n", nr); + printk_debug("ST0 = %02x\n", reply[0]); + printk_debug("PCN = %02x\n", reply[1]); + printk_debug("status = %d\n", inb(FD_STATUS)); + } + return success; +} + +static int read_ok(unsigned head) +{ + unsigned char results[7]; + int result_ok; + int nr; + + /* read back the read results */ + nr = result(results, 7); + + /* Now see if they say we are o.k. */ + result_ok = 0; + /* Are my result bytes o.k.? */ + if (nr == 7) { + /* Are we o.k. */ + if ((results[0] & ST0_INTR) == ST0_INTR_OK) { + result_ok = 1; + } + /* Or did we get just an overflow error */ + else if (((results[0] & ST0_INTR) == ST0_INTR_ERROR) && + (results[1]== ST1_OR) && + (results[2] == 0)) { + result_ok = 1; + } + /* Verify the reply had the correct head */ + if (((results[0] & ST0_HA) >> 2) != head) { + result_ok = 0; + } + /* Verify the reply had the correct drive */ + if (((results[0] & ST0_DS) != FD_DRIVE)) { + result_ok = 0; + } + } + if (!result_ok) { + printk_debug("result_bytes = %d\n", nr); + printk_debug("ST0 = %02x\n", results[0]); + printk_debug("ST1 = %02x\n", results[1]); + printk_debug("ST2 = %02x\n", results[2]); + printk_debug(" C = %02x\n", results[3]); + printk_debug(" H = %02x\n", results[4]); + printk_debug(" R = %02x\n", results[5]); + printk_debug(" N = %02x\n", results[6]); + } + return result_ok; +} + +static int floppy_read_sectors( + char *dest, unsigned byte_offset, unsigned length, + unsigned sector, unsigned head, unsigned track) +{ + /* MT == Multitrack */ + /* MFM == MFM or FM Mode */ + /* SK == Skip deleted data addres Mark */ + /* HDS == Head number select */ + /* DS0 == Disk Drive Select 0 */ + /* DS1 == Disk Drive Select 1 */ + /* C == Cylinder number 0 - 255 */ + /* H == Head number */ + /* R == Record */ + /* N == The number of data bytes written in a sector */ + /* EOT == End of Track */ + /* GPL == Gap Length */ + /* DTL == Data Length */ + /* MT MFM SK 0 1 1 0 0 */ + /* 0 0 0 0 0 HDS DS1 DS0 */ + /* C, H, R, N, EOT, GPL, DTL */ + + int i, status, result_ok; + int max_bytes, bytes_read; + int ret; + unsigned char cmd[9]; + unsigned end_offset; + + end_offset = byte_offset + length; + max_bytes = 512*(DISK_H1440_SECT - sector + 1); + + if (byte_offset >= max_bytes) { + return 0; + } + cmd[0] = FD_READ | (((DISK_H1440_HEAD ==2)?1:0) << 6); + cmd[1] = (head << 2) | FD_DRIVE; + cmd[2] = track; + cmd[3] = head; + cmd[4] = sector; + cmd[5] = 2; /* 2^N *128 == Sector size. Hard coded to 512 bytes */ + cmd[6] = DISK_H1440_SECT; + cmd[7] = DISK_H1440_GAP; + cmd[8] = 0xff; + + /* Output the command bytes */ + if (output_command(cmd, 9) < 0) + return -1; + + /* The execution stage begins when STATUS_READY&STATUS_NON_DMA is set */ + do { + status = inb(FD_STATUS); + status &= STATUS_READY | STATUS_NON_DMA; + } while(status != (STATUS_READY|STATUS_NON_DMA)); + + for(i = 0; i < max_bytes; i++) { + unsigned char byte; + if ((status = wait_til_ready()) < 0) { + break; + } + status &= STATUS_READY|STATUS_DIR|STATUS_NON_DMA; + if (status != (STATUS_READY|STATUS_DIR|STATUS_NON_DMA)) { + break; + } + byte = inb(FD_DATA); + if ((i >= byte_offset) && (i < end_offset)) { + dest[i - byte_offset] = byte; + } + } + bytes_read = i; + + /* The result stage begins when STATUS_NON_DMA is cleared */ + while((status = inb(FD_STATUS)) & STATUS_NON_DMA) { + /* We get extra bytes in the fifo past + * the end of the sector and drop them on the floor. + * Otherwise the fifo is polluted. + */ + inb(FD_DATA); + } + /* Did I get an error? */ + result_ok = read_ok(head); + /* Did I read enough bytes? */ + ret = -1; + if (result_ok && (bytes_read == max_bytes)) { + ret = bytes_read - byte_offset; + if (ret > length) { + ret = length; + } + } + + if (ret < 0) { + printk_debug("ret = %d\n", ret); + printk_debug("bytes_read = %d\n", bytes_read); + printk_debug("status = %x\n", status); + } + return ret; +} + + +static int __floppy_read(char *dest, unsigned long offset, unsigned long length) +{ + unsigned head, track, sector, byte_offset, sector_offset; + int ret; + + /* break the offset up into sectors and bytes */ + byte_offset = offset % 512; + sector_offset = offset / 512; + + /* Find the disk block we are starting with... */ + sector = (sector_offset % DISK_H1440_SECT) + 1; + head = (sector_offset / DISK_H1440_SECT) % DISK_H1440_HEAD; + track = (sector_offset / (DISK_H1440_SECT *DISK_H1440_HEAD))% DISK_H1440_TRACK; + + /* First seek to our start track */ + if (!floppy_seek(track)) { + return -1; + } + /* Then read the data */ + ret = floppy_read_sectors(dest, byte_offset, length, sector, head, track); + if (ret >= 0) { + return ret; + } + /* If we failed reset the fdc... */ + floppy_reset(); + return -1; +} + +int floppy_read(char *dest, unsigned long offset, unsigned long length) +{ + int result, bytes_read;; + printk_debug("floppy_read\n"); + bytes_read = 0; + do { + int max_errors = 3; + do { + result = __floppy_read(dest + bytes_read, offset, length - bytes_read); + if (max_errors-- == 0) { + return (bytes_read)?bytes_read: -1; + } + } while (result <= 0); + offset += result; + bytes_read += result; + } while(bytes_read < length); + return bytes_read; +} + +/* Determine the floppy disk controller type */ +/* This routine was written by David C. Niemi */ +static char get_fdc_version(void) +{ + int bytes, ret; + unsigned char reply_buffer[MAX_REPLIES]; + + ret = output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */ + if (ret < 0) + return FDC_NONE; + if ((bytes = result(reply_buffer, MAX_REPLIES)) <= 0x00) + return FDC_NONE; /* No FDC present ??? */ + if ((bytes==1) && (reply_buffer[0] == 0x80)){ + printk_info("FDC %d is an 8272A\n"); + return FDC_8272A; /* 8272a/765 don't know DUMPREGS */ + } + if (bytes != 10) { + printk_debug("init: DUMPREGS: unexpected return of %d bytes.\n", + bytes); + return FDC_UNKNOWN; + } + if (!fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD, + TRACK_PRECOMPENSATION)) { + printk_info("FDC is an 82072\n"); + return FDC_82072; /* 82072 doesn't know CONFIGURE */ + } + + output_byte(FD_PERPENDICULAR); + if (need_more_output() == MORE_OUTPUT) { + output_byte(0); + } else { + printk_info("FDC is an 82072A\n"); + return FDC_82072A; /* 82072A as found on Sparcs. */ + } + + output_byte(FD_UNLOCK); + bytes = result(reply_buffer, MAX_REPLIES); + if ((bytes == 1) && (reply_buffer[0] == 0x80)){ + printk_info("FDC is a pre-1991 82077\n"); + return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know + * LOCK/UNLOCK */ + } + if ((bytes != 1) || (reply_buffer[0] != 0x00)) { + printk_debug("FDC init: UNLOCK: unexpected return of %d bytes.\n", + bytes); + return FDC_UNKNOWN; + } + output_byte(FD_PARTID); + bytes = result(reply_buffer, MAX_REPLIES); + if (bytes != 1) { + printk_debug("FDC init: PARTID: unexpected return of %d bytes.\n", + bytes); + return FDC_UNKNOWN; + } + if (reply_buffer[0] == 0x80) { + printk_info("FDC is a post-1991 82077\n"); + return FDC_82077; /* Revised 82077AA passes all the tests */ + } + switch (reply_buffer[0] >> 5) { + case 0x0: + /* Either a 82078-1 or a 82078SL running at 5Volt */ + printk_info("FDC is an 82078.\n"); + return FDC_82078; + case 0x1: + printk_info("FDC is a 44pin 82078\n"); + return FDC_82078; + case 0x2: + printk_info("FDC is a S82078B\n"); + return FDC_S82078B; + case 0x3: + printk_info("FDC is a National Semiconductor PC87306\n"); + return FDC_87306; + default: + printk_info("FDC init: 82078 variant with unknown PARTID=%d.\n", + reply_buffer[0] >> 5); + return FDC_82078_UNKN; + } +} /* get_fdc_version */ + + +int floppy_init(void) +{ + printk_debug("floppy_init\n"); + fdc_state.in_sync = 0; + fdc_state.spec1 = -1; + fdc_state.spec2 = -1; + fdc_state.dtr = -1; + fdc_state.dor = DOR_NO_RESET; + fdc_state.version = FDC_UNKNOWN; + reset_fdc(); + /* Try to determine the floppy controller type */ + fdc_state.version = get_fdc_version(); + if (fdc_state.version == FDC_NONE) { + return -1; + } + floppy_reset(); + printk_info("fdc_state.version = %04x\n", fdc_state.version); + return 0; +} + +static void floppy_reset(void) +{ + printk_debug("floppy_reset\n"); + floppy_motor_off(FD_DRIVE); + reset_fdc(); + fdc_dtr(DISK_H1440_RATE); + /* program data rate via ccr */ + collect_interrupt(); + fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD, + TRACK_PRECOMPENSATION); + fdc_specify(DRIVE_H1440_HLT, DRIVE_H1440_HUT, DRIVE_H1440_SRT); + set_drive(FD_DRIVE); + floppy_recalibrate(); + fdc_state.in_sync = 1; +} + +void floppy_fini(void) +{ + /* Disable the floppy and the floppy drive controller */ + set_dor(0, 0, 0); +} + + +static void +ob_floppy_initialize(int *idx) +{ + int props[3]; + phandle_t ph=get_cur_dev(); + + push_str("block"); + fword("device-type"); + + // Set dummy reg properties + props[0] = __cpu_to_be32(0); props[1] = __cpu_to_be32(0); props[2] = __cpu_to_be32(0); + set_property(ph, "reg", (char *)&props, 3*sizeof(int)); + + fword("is-deblocker"); +} + + +static void +ob_floppy_open(int *idx) +{ + int ret=1, len; + phandle_t ph; + + fword("my-unit"); + idx[0]=POP(); + + fword("my-parent"); + fword("ihandle>phandle"); + ph=(phandle_t)POP(); + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + RET ( -ret ); +} + +static void +ob_floppy_close(int *idx) +{ + selfword("close-deblocker"); +} + +static void +ob_floppy_read_blocks(int *idx) +{ + cell cnt = POP(); + ucell blk = POP(); + char *dest = (char*)POP(); + floppy_read(dest, blk*512, cnt*512); + PUSH(cnt); +} + + +static void +ob_floppy_block_size(int *idx) +{ + PUSH(512); +} + +static void +ob_floppy_max_transfer(int *idx) +{ + // Fixme + PUSH(18 * 512); +} + +NODE_METHODS(ob_floppy) = { + { NULL, ob_floppy_initialize }, + { "open", ob_floppy_open }, + { "close", ob_floppy_close }, + { "read-blocks", ob_floppy_read_blocks }, + { "block-size", ob_floppy_block_size }, + { "max-transfer", ob_floppy_max_transfer }, +}; + + +int ob_floppy_init(void) +{ + REGISTER_NAMED_NODE(ob_floppy, "/isa/floppy0"); + floppy_init(); + return 0; +} + diff --git a/drivers/floppy.h b/drivers/floppy.h new file mode 100644 index 0000000..b0f30d5 --- /dev/null +++ b/drivers/floppy.h @@ -0,0 +1,9 @@ +#ifndef FLOPPY_SUBR_H +#define FLOPPY_SUBR_H + +int floppy_init(void); +int floppy_read(char *dest, unsigned long offset, unsigned long length); +void floppy_fini(void); + + +#endif /* FLOPPY_SUBR_H */ diff --git a/drivers/hdreg.h b/drivers/hdreg.h new file mode 100644 index 0000000..91e4d1f --- /dev/null +++ b/drivers/hdreg.h @@ -0,0 +1,289 @@ +/* + * this header holds data structures as dictated by spec + */ +#ifndef HDREG_H +#define HDREG_H + +struct hd_driveid { + unsigned short config; /* lots of obsolete bit flags */ + unsigned short cyls; /* Obsolete, "physical" cyls */ + unsigned short reserved2; /* reserved (word 2) */ + unsigned short heads; /* Obsolete, "physical" heads */ + unsigned short track_bytes; /* unformatted bytes per track */ + unsigned short sector_bytes; /* unformatted bytes per sector */ + unsigned short sectors; /* Obsolete, "physical" sectors per track */ + unsigned short vendor0; /* vendor unique */ + unsigned short vendor1; /* vendor unique */ + unsigned short vendor2; /* Retired vendor unique */ + unsigned char serial_no[20]; /* 0 = not_specified */ + unsigned short buf_type; /* Retired */ + unsigned short buf_size; /* Retired, 512 byte increments + * 0 = not_specified + */ + unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */ + unsigned char fw_rev[8]; /* 0 = not_specified */ + unsigned char model[40]; /* 0 = not_specified */ + unsigned char max_multsect; /* 0=not_implemented */ + unsigned char vendor3; /* vendor unique */ + unsigned short dword_io; /* 0=not_implemented; 1=implemented */ + unsigned char vendor4; /* vendor unique */ + unsigned char capability; /* (upper byte of word 49) + * 3: IORDYsup + * 2: IORDYsw + * 1: LBA + * 0: DMA + */ + unsigned short reserved50; /* reserved (word 50) */ + unsigned char vendor5; /* Obsolete, vendor unique */ + unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ + unsigned char vendor6; /* Obsolete, vendor unique */ + unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ + unsigned short field_valid; /* (word 53) + * 2: ultra_ok word 88 + * 1: eide_ok words 64-70 + * 0: cur_ok words 54-58 + */ + unsigned short cur_cyls; /* Obsolete, logical cylinders */ + unsigned short cur_heads; /* Obsolete, l heads */ + unsigned short cur_sectors; /* Obsolete, l sectors per track */ + unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */ + unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */ + unsigned char multsect; /* current multiple sector count */ + unsigned char multsect_valid; /* when (bit0==1) multsect is ok */ + unsigned int lba_capacity; /* Obsolete, total number of sectors */ + unsigned short dma_1word; /* Obsolete, single-word dma info */ + unsigned short dma_mword; /* multiple-word dma info */ + unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */ + unsigned short eide_dma_min; /* min mword dma cycle time (ns) */ + unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */ + unsigned short eide_pio; /* min cycle time (ns), no IORDY */ + unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */ + unsigned short words69_70[2]; /* reserved words 69-70 + * future command overlap and queuing + */ + /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */ + unsigned short words71_74[4]; /* reserved words 71-74 + * for IDENTIFY PACKET DEVICE command + */ + unsigned short queue_depth; /* (word 75) + * 15:5 reserved + * 4:0 Maximum queue depth -1 + */ + unsigned short words76_79[4]; /* reserved words 76-79 */ + unsigned short major_rev_num; /* (word 80) */ + unsigned short minor_rev_num; /* (word 81) */ + unsigned short command_set_1; /* (word 82) supported + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + unsigned short command_set_2; /* (word 83) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + unsigned short cfsse; /* (word 84) + * cmd set-feature supported extensions + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:6 reserved + * 5: General Purpose Logging + * 4: Streaming Feature Set + * 3: Media Card Pass Through + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + unsigned short cfs_enable_1; /* (word 85) + * command set-feature enabled + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + unsigned short cfs_enable_2; /* (word 86) + * command set-feature enabled + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + unsigned short csf_default; /* (word 87) + * command set-feature default + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:6 reserved + * 5: General Purpose Logging enabled + * 4: Valid CONFIGURE STREAM executed + * 3: Media Card Pass Through enabled + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + unsigned short dma_ultra; /* (word 88) */ + unsigned short trseuc; /* time required for security erase */ + unsigned short trsEuc; /* time required for enhanced erase */ + unsigned short CurAPMvalues; /* current APM values */ + unsigned short mprc; /* master password revision code */ + unsigned short hw_config; /* hardware config (word 93) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: + * 12: + * 11: + * 10: + * 9: + * 8: + * 7: + * 6: + * 5: + * 4: + * 3: + * 2: + * 1: + * 0: Shall be ONE + */ + unsigned short acoustic; /* (word 94) + * 15:8 Vendor's recommended value + * 7:0 current value + */ + unsigned short msrqs; /* min stream request size */ + unsigned short sxfert; /* stream transfer time */ + unsigned short sal; /* stream access latency */ + unsigned int spg; /* stream performance granularity */ + unsigned long long lba_capacity_2;/* 48-bit total number of sectors */ + unsigned short words104_125[22];/* reserved words 104-125 */ + unsigned short last_lun; /* (word 126) */ + unsigned short word127; /* (word 127) Feature Set + * Removable Media Notification + * 15:2 reserved + * 1:0 00 = not supported + * 01 = supported + * 10 = reserved + * 11 = reserved + */ + unsigned short dlf; /* (word 128) + * device lock function + * 15:9 reserved + * 8 security level 1:max 0:high + * 7:6 reserved + * 5 enhanced erase + * 4 expire + * 3 frozen + * 2 locked + * 1 en/disabled + * 0 capability + */ + unsigned short csfo; /* (word 129) + * current set features options + * 15:4 reserved + * 3: auto reassign + * 2: reverting + * 1: read-look-ahead + * 0: write cache + */ + unsigned short words130_155[26];/* reserved vendor words 130-155 */ + unsigned short word156; /* reserved vendor word 156 */ + unsigned short words157_159[3];/* reserved vendor words 157-159 */ + unsigned short cfa_power; /* (word 160) CFA Power Mode + * 15 word 160 supported + * 14 reserved + * 13 + * 12 + * 11:0 + */ + unsigned short words161_175[15];/* Reserved for CFA */ + unsigned short words176_205[30];/* Current Media Serial Number */ + unsigned short words206_254[49];/* reserved words 206-254 */ + unsigned short integrity_word; /* (word 255) + * 15:8 Checksum + * 7:0 Signature + */ +}; + +struct request_sense { +#if defined(CONFIG_BIG_ENDIAN) + u8 valid : 1; + u8 error_code : 7; +#elif defined(CONFIG_LITTLE_ENDIAN) + u8 error_code : 7; + u8 valid : 1; +#endif + u8 segment_number; +#if defined(CONFIG_BIG_ENDIAN) + u8 reserved1 : 2; + u8 ili : 1; + u8 reserved2 : 1; + u8 sense_key : 4; +#elif defined(CONFIG_LITTLE_ENDIAN) + u8 sense_key : 4; + u8 reserved2 : 1; + u8 ili : 1; + u8 reserved1 : 2; +#endif + u8 information[4]; + u8 add_sense_len; + u8 command_info[4]; + u8 asc; + u8 ascq; + u8 fruc; + u8 sks[3]; + u8 asb[46]; +}; + +struct atapi_capacity { + u32 lba; + u32 block_size; +}; + +#endif diff --git a/drivers/ide.c b/drivers/ide.c new file mode 100644 index 0000000..4e93532 --- /dev/null +++ b/drivers/ide.c @@ -0,0 +1,1374 @@ +/* + * OpenBIOS polled ide driver + * + * Copyright (C) 2004 Jens Axboe + * Copyright (C) 2005 Stefan Reinauer + * + * Credit goes to Hale Landis for his excellent ata demo software + * OF node handling and some fixes by Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +/* + * TODO: + * - Really probe for interfaces, don't just rely on legacy + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/kernel.h" +#include "libc/byteorder.h" +#include "libc/vsprintf.h" + +#include "openbios/drivers.h" +#include "ide.h" +#include "hdreg.h" +#include "timer.h" + +#define REGISTER_NAMED_NODE( name, path ) do { \ + bind_new_node( name##_flags_, name##_size_, \ + path, name##_m, sizeof(name##_m)/sizeof(method_t)); \ + } while(0) + + +/* DECLARE data structures for the nodes. */ +DECLARE_UNNAMED_NODE( ob_ide, INSTALL_OPEN, 2*sizeof(int) ); +DECLARE_UNNAMED_NODE( ob_ide_ctrl, INSTALL_OPEN, sizeof(int)); + +/* + * define to 2 for the standard 2 channels only + */ +#ifndef CONFIG_IDE_NUM_CHANNELS +#define IDE_NUM_CHANNELS 4 +#else +#define IDE_NUM_CHANNELS CONFIG_IDE_NUM_CHANNELS +#endif +#define IDE_MAX_CHANNELS 4 + +static struct ide_channel ob_ide_channels[IDE_MAX_CHANNELS]; + +/* + * FIXME: probe, we just hardwire legacy ports for now + */ +static const int io_ports[IDE_MAX_CHANNELS] = { 0x1f0, 0x170, 0x1e8, 0x168 }; +static const int ctl_ports[IDE_MAX_CHANNELS] = { 0x3f6, 0x376, 0x3ee, 0x36e }; + +/* + * don't be pedantic + */ +#undef ATA_PEDANTIC + +static void dump_drive(struct ide_drive *drive) +{ +#ifdef CONFIG_DEBUG_IDE + printk("IDE DRIVE @%lx:\n", (unsigned long)drive); + printk("unit: %d\n",drive->unit); + printk("present: %d\n",drive->present); + printk("type: %d\n",drive->type); + printk("media: %d\n",drive->media); + printk("model: %s\n",drive->model); + printk("nr: %d\n",drive->nr); + printk("cyl: %d\n",drive->cyl); + printk("head: %d\n",drive->head); + printk("sect: %d\n",drive->sect); + printk("bs: %d\n",drive->bs); +#endif +} + +/* + * old style io port operations + */ +static unsigned char +ob_ide_inb(unsigned long port) +{ + return inb(port); +} + +static void +ob_ide_outb(unsigned char data, unsigned long port) +{ + outb(data, port); +} + +static void +ob_ide_insw(unsigned long port, unsigned char *addr, unsigned int count) +{ + insw(port, addr, count); +} + +static void +ob_ide_outsw(unsigned long port, unsigned char *addr, unsigned int count) +{ + outsw(port, addr, count); +} + +static inline unsigned char +ob_ide_pio_readb(struct ide_drive *drive, unsigned int offset) +{ + struct ide_channel *chan = drive->channel; + + return chan->obide_inb(chan->io_regs[offset]); +} + +static inline void +ob_ide_pio_writeb(struct ide_drive *drive, unsigned int offset, + unsigned char data) +{ + struct ide_channel *chan = drive->channel; + + chan->obide_outb(data, chan->io_regs[offset]); +} + +static inline void +ob_ide_pio_insw(struct ide_drive *drive, unsigned int offset, + unsigned char *addr, unsigned int len) +{ + struct ide_channel *chan = drive->channel; + + if (len & 1) { + printk("%d: command not word aligned\n", drive->nr); + return; + } + + chan->obide_insw(chan->io_regs[offset], addr, len / 2); +} + +static inline void +ob_ide_pio_outsw(struct ide_drive *drive, unsigned int offset, + unsigned char *addr, unsigned int len) +{ + struct ide_channel *chan = drive->channel; + + if (len & 1) { + printk("%d: command not word aligned\n", drive->nr); + return; + } + + chan->obide_outsw(chan->io_regs[offset], addr, len / 2); +} + +static void +ob_ide_400ns_delay(struct ide_drive *drive) +{ + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS); + + udelay(1); +} + +static void +ob_ide_error(struct ide_drive *drive, unsigned char stat, char *msg) +{ + struct ide_channel *chan = drive->channel; + unsigned char err; + + if (!stat) + stat = ob_ide_pio_readb(drive, IDEREG_STATUS); + + printk("ob_ide_error drive<%d>: %s:\n", drive->nr, msg); + printk(" cmd=%x, stat=%x", chan->ata_cmd.command, stat); + + if ((stat & (BUSY_STAT | ERR_STAT)) == ERR_STAT) { + err = ob_ide_pio_readb(drive, IDEREG_ERROR); + printk(", err=%x", err); + } + printk("\n"); + + /* + * see if sense is valid and dump that + */ + if (chan->ata_cmd.command == WIN_PACKET) { + struct atapi_command *cmd = &chan->atapi_cmd; + unsigned char old_cdb = cmd->cdb[0]; + + if (cmd->cdb[0] == ATAPI_REQ_SENSE) { + old_cdb = cmd->old_cdb; + + printk(" atapi opcode=%02x", old_cdb); + } else { + int i; + + printk(" cdb: "); + for (i = 0; i < sizeof(cmd->cdb); i++) + printk("%02x ", cmd->cdb[i]); + } + if (cmd->sense_valid) + printk(", sense: %02x/%02x/%02x", cmd->sense.sense_key, cmd->sense.asc, cmd->sense.ascq); + else + printk(", no sense"); + printk("\n"); + } +} + +/* + * wait for 'stat' to be set. returns 1 if failed, 0 if succesful + */ +static int +ob_ide_wait_stat(struct ide_drive *drive, unsigned char ok_stat, + unsigned char bad_stat, char *ret_stat) +{ + unsigned char stat; + int i; + + ob_ide_400ns_delay(drive); + + for (i = 0; i < 5000; i++) { + stat = ob_ide_pio_readb(drive, IDEREG_STATUS); + if (!(stat & BUSY_STAT)) + break; + + udelay(1000); + } + + if (ret_stat) + *ret_stat = stat; + + if (stat & bad_stat) + return 1; + + if ((stat & ok_stat) || !ok_stat) + return 0; + + return 1; +} + +static int +ob_ide_select_drive(struct ide_drive *drive) +{ + struct ide_channel *chan = drive->channel; + unsigned char control = IDEHEAD_DEV0; + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) { + printk("select_drive: timed out\n"); + return 1; + } + + /* + * don't select drive if already active. Note: we always + * wait for BUSY clear + */ + if (drive->unit == chan->selected) + return 0; + + if (drive->unit) + control = IDEHEAD_DEV1; + + ob_ide_pio_writeb(drive, IDEREG_CURRENT, control); + ob_ide_400ns_delay(drive); + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) { + printk("select_drive: timed out\n"); + return 1; + } + + chan->selected = drive->unit; + return 0; +} + +static void +ob_ide_write_tasklet(struct ide_drive *drive, struct ata_command *cmd) +{ + ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[1]); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[3]); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[7]); + ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[8]); + ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[9]); + + ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[0]); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[2]); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[4]); + ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[5]); + ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[6]); + + if (drive->unit) + cmd->device_head |= IDEHEAD_DEV1; + + ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head); + + ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command); + ob_ide_400ns_delay(drive); +} + +static void +ob_ide_write_registers(struct ide_drive *drive, struct ata_command *cmd) +{ + /* + * we are _always_ polled + */ + ob_ide_pio_writeb(drive, IDEREG_CONTROL, cmd->control | IDECON_NIEN); + + ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->feature); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->nsector); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->sector); + ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->lcyl); + ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->hcyl); + + if (drive->unit) + cmd->device_head |= IDEHEAD_DEV1; + + ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head); + + ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command); + ob_ide_400ns_delay(drive); +} + +/* + * execute command with "pio non data" protocol + */ +#if 0 +static int +ob_ide_pio_non_data(struct ide_drive *drive, struct ata_command *cmd) +{ + if (ob_ide_select_drive(drive)) + return 1; + + ob_ide_write_registers(drive, cmd); + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) + return 1; + + return 0; +} +#endif + +/* + * execute given command with a pio data-in phase. + */ +static int +ob_ide_pio_data_in(struct ide_drive *drive, struct ata_command *cmd) +{ + unsigned char stat; + unsigned int bytes, timeout; + + if (ob_ide_select_drive(drive)) + return 1; + + /* + * ATA must set ready and seek stat, ATAPI need only clear busy + */ + timeout = 0; + do { + stat = ob_ide_pio_readb(drive, IDEREG_STATUS); + + if (drive->type == ide_type_ata) { + /* + * this is BIOS code, don't be too pedantic + */ +#ifdef ATA_PEDANTIC + if ((stat & (BUSY_STAT | READY_STAT | SEEK_STAT)) == + (READY_STAT | SEEK_STAT)) + break; +#else + if ((stat & (BUSY_STAT | READY_STAT)) == READY_STAT) + break; +#endif + } else { + if (!(stat & BUSY_STAT)) + break; + } + ob_ide_400ns_delay(drive); + } while (timeout++ < 1000); + + if (timeout >= 1000) { + ob_ide_error(drive, stat, "drive timed out"); + cmd->stat = stat; + return 1; + } + + ob_ide_write_registers(drive, cmd); + + /* + * now read the data + */ + bytes = cmd->buflen; + do { + unsigned count = cmd->buflen; + + if (count > drive->bs) + count = drive->bs; + + /* delay 100ms for ATAPI? */ + + /* + * wait for BUSY clear + */ + if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) { + ob_ide_error(drive, stat, "timed out waiting for BUSY clear"); + cmd->stat = stat; + break; + } + + /* + * transfer the data + */ + if ((stat & (BUSY_STAT | DRQ_STAT)) == DRQ_STAT) { + ob_ide_pio_insw(drive, IDEREG_DATA, cmd->buffer, count); + cmd->bytes -= count; + cmd->buffer += count; + bytes -= count; + + ob_ide_400ns_delay(drive); + } + + if (stat & (BUSY_STAT | WRERR_STAT | ERR_STAT)) { + cmd->stat = stat; + break; + } + + if (!(stat & DRQ_STAT)) { + cmd->stat = stat; + break; + } + } while (bytes); + + if (bytes) + printk("bytes=%d, stat=%x\n", bytes, stat); + + return bytes ? 1 : 0; +} + +/* + * execute ata command with pio packet protocol + */ +static int +ob_ide_pio_packet(struct ide_drive *drive, struct atapi_command *cmd) +{ + unsigned char stat, reason, lcyl, hcyl; + struct ata_command *acmd = &drive->channel->ata_cmd; + unsigned char *buffer; + unsigned int bytes; + + if (ob_ide_select_drive(drive)) + return 1; + + if (cmd->buflen && cmd->data_direction == atapi_ddir_none) + printk("non-zero buflen but no data direction\n"); + + memset(acmd, 0, sizeof(*acmd)); + acmd->lcyl = cmd->buflen & 0xff; + acmd->hcyl = (cmd->buflen >> 8) & 0xff; + acmd->command = WIN_PACKET; + ob_ide_write_registers(drive, acmd); + + /* + * BUSY must be set, _or_ DRQ | ERR + */ + stat = ob_ide_pio_readb(drive, IDEREG_ASTATUS); + if ((stat & BUSY_STAT) == 0) { + if (!(stat & (DRQ_STAT | ERR_STAT))) { + ob_ide_error(drive, stat, "bad stat in atapi cmd"); + cmd->stat = stat; + return 1; + } + } + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) { + ob_ide_error(drive, stat, "timeout, ATAPI BUSY clear"); + cmd->stat = stat; + return 1; + } + + if ((stat & (BUSY_STAT | DRQ_STAT | ERR_STAT)) != DRQ_STAT) { + /* + * if command isn't request sense, then we have a problem. if + * we are doing a sense, ERR_STAT == CHECK_CONDITION + */ + if (cmd->cdb[0] != ATAPI_REQ_SENSE) { + printk("odd, drive didn't want to transfer %x\n", stat); + return 1; + } + } + + /* + * transfer cdb + */ + ob_ide_pio_outsw(drive, IDEREG_DATA, cmd->cdb,sizeof(cmd->cdb)); + ob_ide_400ns_delay(drive); + + /* + * ok, cdb was sent to drive, now do data transfer (if any) + */ + bytes = cmd->buflen; + buffer = cmd->buffer; + do { + unsigned int bc; + + if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) { + ob_ide_error(drive, stat, "busy not clear after cdb"); + cmd->stat = stat; + break; + } + + /* + * transfer complete! + */ + if ((stat & (BUSY_STAT | DRQ_STAT)) == 0) + break; + + if ((stat & (BUSY_STAT | DRQ_STAT)) != DRQ_STAT) + break; + + reason = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + lcyl = ob_ide_pio_readb(drive, IDEREG_LCYL); + hcyl = ob_ide_pio_readb(drive, IDEREG_HCYL); + + /* + * check if the drive wants to transfer data in the same + * direction as we do... + */ + if ((reason & IREASON_CD) && cmd->data_direction != atapi_ddir_read) { + ob_ide_error(drive, stat, "atapi, bad transfer ddir"); + break; + } + + bc = (hcyl << 8) | lcyl; + if (!bc) + break; + + if (bc > bytes) + bc = bytes; + + if (cmd->data_direction == atapi_ddir_read) + ob_ide_pio_insw(drive, IDEREG_DATA, buffer, bc); + else + ob_ide_pio_outsw(drive, IDEREG_DATA, buffer, bc); + + bytes -= bc; + buffer += bc; + + ob_ide_400ns_delay(drive); + } while (bytes); + + if (cmd->data_direction != atapi_ddir_none) + (void) ob_ide_wait_stat(drive, 0, BUSY_STAT, &stat); + + if (bytes) + printk("cdb failed, bytes=%d, stat=%x\n", bytes, stat); + + return (stat & ERR_STAT) || bytes; +} + +/* + * execute a packet command, with retries if appropriate + */ +static int +ob_ide_atapi_packet(struct ide_drive *drive, struct atapi_command *cmd) +{ + int retries = 5, ret; + + if (drive->type != ide_type_atapi) + return 1; + if (cmd->buflen > 0xffff) + return 1; + + /* + * retry loop + */ + do { + ret = ob_ide_pio_packet(drive, cmd); + if (!ret) + break; + + /* + * request sense failed, bummer + */ + if (cmd->cdb[0] == ATAPI_REQ_SENSE) + break; + + if (ob_ide_atapi_request_sense(drive)) + break; + + /* + * we know sense is valid. retry if the drive isn't ready, + * otherwise don't bother. + */ + if (cmd->sense.sense_key != ATAPI_SENSE_NOT_READY) + break; + /* + * ... except 'medium not present' + */ + if (cmd->sense.asc == 0x3a) + break; + + udelay(1000000); + } while (retries--); + + if (ret) + ob_ide_error(drive, 0, "atapi command"); + + return ret; +} + +static int +ob_ide_atapi_request_sense(struct ide_drive *drive) +{ + struct atapi_command *cmd = &drive->channel->atapi_cmd; + unsigned char old_cdb; + + /* + * save old cdb for debug error + */ + old_cdb = cmd->cdb[0]; + + memset(cmd, 0, sizeof(*cmd)); + cmd->cdb[0] = ATAPI_REQ_SENSE; + cmd->cdb[4] = 18; + cmd->buffer = (unsigned char *) &cmd->sense; + cmd->buflen = 18; + cmd->data_direction = atapi_ddir_read; + cmd->old_cdb = old_cdb; + + if (ob_ide_atapi_packet(drive, cmd)) + return 1; + + cmd->sense_valid = 1; + return 0; +} + +/* + * make sure drive is ready and media loaded + */ +static int +ob_ide_atapi_drive_ready(struct ide_drive *drive) +{ + struct atapi_command *cmd = &drive->channel->atapi_cmd; + struct atapi_capacity cap; + + /* + * Test Unit Ready is like a ping + */ + memset(cmd, 0, sizeof(*cmd)); + cmd->cdb[0] = ATAPI_TUR; + + if (ob_ide_atapi_packet(drive, cmd)) { + printk("%d: TUR failed\n", drive->nr); + return 1; + } + + /* + * don't force load of tray (bit 2 in byte 4 of cdb), it's + * annoying and we don't want to deal with errors from drives + * that cannot do it + */ + memset(cmd, 0, sizeof(*cmd)); + cmd->cdb[0] = ATAPI_START_STOP_UNIT; + cmd->cdb[4] = 0x01; + + if (ob_ide_atapi_packet(drive, cmd)) { + printk("%d: START_STOP unit failed\n", drive->nr); + return 1; + } + + /* + * finally, get capacity and block size + */ + memset(cmd, 0, sizeof(*cmd)); + memset(&cap, 0, sizeof(cap)); + + cmd->cdb[0] = ATAPI_READ_CAPACITY; + cmd->buffer = (unsigned char *) ∩ + cmd->buflen = sizeof(cap); + cmd->data_direction = atapi_ddir_read; + + if (ob_ide_atapi_packet(drive, cmd)) { + drive->sectors = 0x1fffff; + drive->bs = 2048; + return 1; + } + + drive->sectors = __be32_to_cpu(cap.lba) + 1; + drive->bs = __be32_to_cpu(cap.block_size); + return 0; +} + +/* + * read from an atapi device, using READ_10 + */ +static int +ob_ide_read_atapi(struct ide_drive *drive, unsigned long long block, char *buf, + unsigned int sectors) +{ + struct atapi_command *cmd = &drive->channel->atapi_cmd; + + if (ob_ide_atapi_drive_ready(drive)) + return 1; + + memset(cmd, 0, sizeof(*cmd)); + + /* + * READ_10 should work on generally any atapi device + */ + cmd->cdb[0] = ATAPI_READ_10; + cmd->cdb[2] = (block >> 24) & 0xff; + cmd->cdb[3] = (block >> 16) & 0xff; + cmd->cdb[4] = (block >> 8) & 0xff; + cmd->cdb[5] = block & 0xff; + cmd->cdb[7] = (sectors >> 8) & 0xff; + cmd->cdb[8] = sectors & 0xff; + + cmd->buffer = buf; + cmd->buflen = sectors * 2048; + cmd->data_direction = atapi_ddir_read; + + return ob_ide_atapi_packet(drive, cmd); +} + +static int +ob_ide_read_ata_chs(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + unsigned int track = (block / drive->sect); + unsigned int sect = (block % drive->sect) + 1; + unsigned int head = (track % drive->head); + unsigned int cyl = (track / drive->head); + struct ata_sector ata_sector; + + /* + * fill in chs command to read from disk at given location + */ + cmd->buffer = buf; + cmd->buflen = sectors * 512; + + ata_sector.all = sectors; + cmd->nsector = ata_sector.low; + cmd->sector = sect; + cmd->lcyl = cyl; + cmd->hcyl = cyl >> 8; + cmd->device_head = head; + + cmd->command = WIN_READ; + + return ob_ide_pio_data_in(drive, cmd); +} + +static int +ob_ide_read_ata_lba28(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + + memset(cmd, 0, sizeof(*cmd)); + + /* + * fill in 28-bit lba command to read from disk at given location + */ + cmd->buffer = buf; + cmd->buflen = sectors * 512; + + cmd->nsector = sectors; + cmd->sector = block; + cmd->lcyl = block >>= 8; + cmd->hcyl = block >>= 8; + cmd->device_head = ((block >> 8) & 0x0f); + cmd->device_head |= (1 << 6); + + cmd->command = WIN_READ; + + return ob_ide_pio_data_in(drive, cmd); +} + +static int +ob_ide_read_ata_lba48(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + struct ata_sector ata_sector; + + memset(cmd, 0, sizeof(*cmd)); + + cmd->buffer = buf; + cmd->buflen = sectors * 512; + ata_sector.all = sectors; + + /* + * we are using tasklet addressing here + */ + cmd->task[2] = ata_sector.low; + cmd->task[3] = ata_sector.high; + cmd->task[4] = block; + cmd->task[5] = block >> 8; + cmd->task[6] = block >> 16; + cmd->task[7] = block >> 24; + cmd->task[8] = (u64) block >> 32; + cmd->task[9] = (u64) block >> 40; + + cmd->command = WIN_READ_EXT; + + ob_ide_write_tasklet(drive, cmd); + + return ob_ide_pio_data_in(drive, cmd); +} +/* + * read 'sectors' sectors from ata device + */ +static int +ob_ide_read_ata(struct ide_drive *drive, unsigned long long block, char *buf, + unsigned int sectors) +{ + unsigned long long end_block = block + sectors; + const int need_lba48 = (end_block > (1ULL << 28)) || (sectors > 255); + + if (end_block > drive->sectors) + return 1; + if (need_lba48 && drive->addressing != ide_lba48) + return 1; + + /* + * use lba48 if we have to, otherwise use the faster lba28 + */ + if (need_lba48) + return ob_ide_read_ata_lba48(drive, block, buf, sectors); + else if (drive->addressing != ide_chs) + return ob_ide_read_ata_lba28(drive, block, buf, sectors); + + return ob_ide_read_ata_chs(drive, block, buf, sectors); +} + +static int +ob_ide_read_sectors(struct ide_drive *drive, unsigned long long block, + char *buf, unsigned int sectors) +{ + if (!sectors) + return 1; + if (block + sectors > drive->sectors) + return 1; + +#ifdef CONFIG_DEBUG_IDE + printk("ob_ide_read_sectors: block=%Ld sectors=%u\n", (unsigned long) block, sectors); +#endif + + if (drive->type == ide_type_ata) + return ob_ide_read_ata(drive, block, buf, sectors); + else + return ob_ide_read_atapi(drive, block, buf, sectors); +} + +/* + * byte swap the string if necessay, and strip leading/trailing blanks + */ +static void +ob_ide_fixup_string(unsigned char *s, unsigned int len) +{ + unsigned char *p = s, *end = &s[len & ~1]; + + /* + * if little endian arch, byte swap the string + */ +#ifdef CONFIG_LITTLE_ENDIAN + for (p = end ; p != s;) { + unsigned short *pp = (unsigned short *) (p -= 2); + *pp = __be16_to_cpu(*pp); + } +#endif + + while (s != end && *s == ' ') + ++s; + while (s != end && *s) + if (*s++ != ' ' || (s != end && *s && *s != ' ')) + *p++ = *(s-1); + while (p != end) + *p++ = '\0'; +} + +/* + * it's big endian, we need to swap (if on little endian) the items we use + */ +static int +ob_ide_fixup_id(struct hd_driveid *id) +{ + ob_ide_fixup_string(id->model, 40); + id->config = __le16_to_cpu(id->config); + id->lba_capacity = __le32_to_cpu(id->lba_capacity); + id->cyls = __le16_to_cpu(id->cyls); + id->heads = __le16_to_cpu(id->heads); + id->sectors = __le16_to_cpu(id->sectors); + id->command_set_2 = __le16_to_cpu(id->command_set_2); + id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); + + return 0; +} + +static int +ob_ide_identify_drive(struct ide_drive *drive) +{ + struct ata_command *cmd = &drive->channel->ata_cmd; + struct hd_driveid id; + + memset(cmd, 0, sizeof(*cmd)); + cmd->buffer = (unsigned char *) &id; + cmd->buflen = 512; + + if (drive->type == ide_type_ata) + cmd->command = WIN_IDENTIFY; + else if (drive->type == ide_type_atapi) + cmd->command = WIN_IDENTIFY_PACKET; + else { + printk("%s: called with bad device type %d\n", __FUNCTION__, drive->type); + return 1; + } + + if (ob_ide_pio_data_in(drive, cmd)) + return 1; + + ob_ide_fixup_id(&id); + + if (drive->type == ide_type_atapi) { + drive->media = (id.config >> 8) & 0x1f; + drive->sectors = 0x7fffffff; + drive->bs = 2048; + drive->max_sectors = 31; + } else { + drive->media = ide_media_disk; + drive->sectors = id.lba_capacity; + drive->bs = 512; + drive->max_sectors = 255; + +#ifdef CONFIG_IDE_LBA48 + if ((id.command_set_2 & 0x0400) && (id.cfs_enable_2 & 0x0400)) { + drive->addressing = ide_lba48; + drive->max_sectors = 65535; + } else +#endif + if (id.capability & 2) + drive->addressing = ide_lba28; + else { + drive->addressing = ide_chs; + } + + /* only set these in chs mode? */ + drive->cyl = id.cyls; + drive->head = id.heads; + drive->sect = id.sectors; + } + + strcpy(drive->model, id.model); + return 0; +} + +/* + * identify type of devices on channel. must have already been probed. + */ +static void +ob_ide_identify_drives(struct ide_channel *chan) +{ + struct ide_drive *drive; + int i; + + for (i = 0; i < 2; i++) { + drive = &chan->drives[i]; + + if (!drive->present) + continue; + + ob_ide_identify_drive(drive); + } +} + +/* + * software reset (ATA-4, section 8.3) + */ +static void +ob_ide_software_reset(struct ide_drive *drive) +{ + struct ide_channel *chan = drive->channel; + + ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN | IDECON_SRST); + ob_ide_400ns_delay(drive); + ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN); + ob_ide_400ns_delay(drive); + + /* + * if master is present, wait for BUSY clear + */ + if (chan->drives[0].present) + ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL); + + /* + * if slave is present, wait until it allows register access + */ + if (chan->drives[1].present) { + unsigned char sectorn, sectorc; + int timeout = 1000; + + do { + /* + * select it + */ + ob_ide_pio_writeb(drive, IDEREG_CURRENT, IDEHEAD_DEV1); + ob_ide_400ns_delay(drive); + + sectorn = ob_ide_pio_readb(drive, IDEREG_SECTOR); + sectorc = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + + if (sectorc == 0x01 && sectorn == 0x01) + break; + + } while (--timeout); + } + + /* + * reset done, reselect original device + */ + drive->channel->selected = -1; + ob_ide_select_drive(drive); +} + +/* + * this serves as both a device check, and also to verify that the drives + * we initially "found" are really there + */ +static void +ob_ide_device_type_check(struct ide_drive *drive) +{ + unsigned char sc, sn, cl, ch, st; + + if (ob_ide_select_drive(drive)) + return; + + sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + sn = ob_ide_pio_readb(drive, IDEREG_SECTOR); + + if (sc == 0x01 && sn == 0x01) { + /* + * read device signature + */ + cl = ob_ide_pio_readb(drive, IDEREG_LCYL); + ch = ob_ide_pio_readb(drive, IDEREG_HCYL); + st = ob_ide_pio_readb(drive, IDEREG_STATUS); + if (cl == 0x14 && ch == 0xeb) + drive->type = ide_type_atapi; + else if (cl == 0x00 && ch == 0x00 && st != 0x00) + drive->type = ide_type_ata; + else + drive->present = 0; + } else + drive->present = 0; +} + +/* + * pure magic + */ +static void +ob_ide_device_check(struct ide_drive *drive) +{ + unsigned char sc, sn; + + /* + * non-existing io port should return 0xff, don't probe this + * channel at all then + */ + if (ob_ide_pio_readb(drive, IDEREG_STATUS) == 0xff) { + drive->channel->present = 0; + return; + } + + if (ob_ide_select_drive(drive)) + return; + + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0xaa); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0x55); + ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55); + ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa); + + sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR); + sn = ob_ide_pio_readb(drive, IDEREG_SECTOR); + + /* + * we _think_ the device is there, we will make sure later + */ + if (sc == 0x55 && sn == 0xaa) { + drive->present = 1; + drive->type = ide_type_unknown; + } +} + +/* + * probe the legacy ide ports and find attached devices. + */ +static void +ob_ide_probe(struct ide_channel *chan) +{ + struct ide_drive *drive; + int i; + + for (i = 0; i < 2; i++) { + drive = &chan->drives[i]; + + ob_ide_device_check(drive); + + /* + * no point in continuing + */ + if (!chan->present) + break; + + if (!drive->present) + continue; + + /* + * select and reset device + */ + if (ob_ide_select_drive(drive)) + continue; + + ob_ide_software_reset(drive); + + ob_ide_device_type_check(drive); + } +} + +/* + * The following functions are interfacing with OpenBIOS. They + * are device node methods. Thus they have to do proper stack handling. + * + */ + +/* + * 255 sectors for ata lba28, 65535 for lba48, and 31 sectors for atapi + */ +static void +ob_ide_max_transfer(int *idx) +{ + struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]]; + + PUSH(drive->max_sectors * drive->bs); +} + +static void +ob_ide_read_blocks(int *idx) +{ + cell n = POP(), cnt=n; + ucell blk = POP(); + char *dest = (char*)POP(); + struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]]; + +#ifdef CONFIG_DEBUG_IDE + printk("ob_ide_read_blocks %x block=%d n=%d\n", (unsigned long)dest, blk, n ); +#endif + + while (n) { + int len = n; + if (len > drive->max_sectors) + len = drive->max_sectors; + + if (ob_ide_read_sectors(drive, blk, dest, len)) { + printk("ob_ide_read_blocks: error\n"); + RET(0); + } + + dest += len * drive->bs; + n -= len; + blk += len; + } + + PUSH(cnt); +} + +static void +ob_ide_block_size(int *idx) +{ + struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]]; + PUSH(drive->bs); +} + +static void +ob_ide_initialize(int *idx) +{ + int props[3]; + phandle_t ph=get_cur_dev(); + + push_str("block"); + fword("device-type"); + + // Set dummy reg properties + props[0] = __cpu_to_be32(0); props[1] = __cpu_to_be32(0); props[2] = __cpu_to_be32(0); + set_property(ph, "reg", (char *)&props, 3*sizeof(int)); + + fword("is-deblocker"); +} + +static void +ob_ide_open(int *idx) +{ + int ret=1, len; + phandle_t ph; + struct ide_drive *drive; + char *idename; + + fword("my-unit"); + idx[0]=POP(); + + fword("my-parent"); + fword("ihandle>phandle"); + ph=(phandle_t)POP(); + idename=get_property(ph, "name", &len); + idx[1]=idename[3]-0x30; + +#ifdef CONFIG_DEBUG_IDE + printk("opening channel %d unit %d\n", idx[1], idx[0]); +#endif + drive=&ob_ide_channels[idx[1]].drives[idx[0]]; + dump_drive(drive); + + if (drive->type != ide_type_ata) + ret= !ob_ide_atapi_drive_ready(drive); + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + RET ( -ret ); +} + +static void +ob_ide_close(struct ide_drive *drive) +{ + selfword("close-deblocker"); +} + +NODE_METHODS(ob_ide) = { + { NULL, ob_ide_initialize }, + { "open", ob_ide_open }, + { "close", ob_ide_close }, + { "read-blocks", ob_ide_read_blocks }, + { "block-size", ob_ide_block_size }, + { "max-transfer", ob_ide_max_transfer }, +}; + +static void +ob_ide_ctrl_initialize(int *idx) +{ + int len, devnum, props[6]; + phandle_t ph=get_cur_dev(); + char *idename; + + set_int_property(ph, "#address-cells", 1); + set_int_property(ph, "#size-cells", 0); + + /* set device type */ + push_str("ide"); + fword("device-type"); + + idename=get_property(ph, "name", &len); + devnum=idename[3]-0x30; + + /* Create interrupt properties. */ + props[0]=14; props[1]=0; + set_property(ph, "interrupts", (char *)&props, 2*sizeof(int)); + + props[0] = __cpu_to_be32(io_ports[devnum]); + props[1] = __cpu_to_be32(1); props[2] = __cpu_to_be32(8); + props[3] = __cpu_to_be32(ctl_ports[devnum]); + props[4] = __cpu_to_be32(1); props[5] = __cpu_to_be32(2); + set_property(ph, "reg", (char *)&props, 6*sizeof(int)); +} + +static void +ob_ide_ctrl_decodeunit(int *idx) +{ + fword("parse-hex"); +} + +NODE_METHODS(ob_ide_ctrl) = { + { NULL, ob_ide_ctrl_initialize }, + { "decode-unit", ob_ide_ctrl_decodeunit }, +}; + +int ob_ide_init(void) +{ + int i, j; + + char * nodetemp_chan = "/pci/isa/ide%d"; + char * nodetemp = "/pci/isa/ide%d/%s"; + char * nodebuff = "/pci/isa/ide / "; + phandle_t dnode; + + for (i = 0; i < IDE_NUM_CHANNELS; i++) { + struct ide_channel *chan = &ob_ide_channels[i]; + + chan->mmio = 0; + + for (j = 0; j < 8; j++) + chan->io_regs[j] = io_ports[i] + j; + + chan->io_regs[8] = ctl_ports[i]; + chan->io_regs[9] = ctl_ports[i] + 1; + + chan->obide_inb = ob_ide_inb; + chan->obide_insw = ob_ide_insw; + chan->obide_outb = ob_ide_outb; + chan->obide_outsw = ob_ide_outsw; + + chan->selected = -1; + + /* + * assume it's there, if not io port dead check will clear + */ + chan->present = 1; + + for (j = 0; j < 2; j++) { + chan->drives[j].present = 0; + chan->drives[j].unit = j; + chan->drives[j].channel = chan; + /* init with a decent value */ + chan->drives[j].bs = 512; + + chan->drives[j].nr = i * 2 + j; + } + + ob_ide_probe(chan); + + if (!chan->present) + continue; + + ob_ide_identify_drives(chan); + + sprintf(nodebuff, nodetemp_chan, i); + REGISTER_NAMED_NODE(ob_ide_ctrl, nodebuff); + + printk("ide%d: [io ports 0x%x-0x%x,0x%x]\n", i, chan->io_regs[0], chan->io_regs[0] + 7, chan->io_regs[8]); + for (j = 0; j < 2; j++) { + struct ide_drive *drive = &chan->drives[j]; + char *media = "UNKNOWN"; + + if (!drive->present) + continue; + + printk(" drive%d [ATA%s ", j, drive->type == ide_type_atapi ? "PI" : ""); + switch (drive->media) { + case ide_media_floppy: + media = "floppy"; + break; + case ide_media_cdrom: + media = "cdrom"; + break; + case ide_media_optical: + media = "mo"; + break; + case ide_media_disk: + media = "disk"; + break; + } + printk("%s]: %s\n", media, drive->model); + sprintf(nodebuff, nodetemp, i, media); + REGISTER_NAMED_NODE(ob_ide, nodebuff); + dnode=find_dev(nodebuff); + set_int_property(dnode, "reg", j); + } + } + + return 0; +} diff --git a/drivers/ide.fs b/drivers/ide.fs new file mode 100644 index 0000000..4217e99 --- /dev/null +++ b/drivers/ide.fs @@ -0,0 +1,69 @@ + +dev /pci + +[IFDEF] CONFIG_DRIVER_IDE + +\ simple isa bus node +new-device + " isa" device-name + " isa" device-type + 2 encode-int " #address-cells" property + 1 encode-int " #size-cells" property + + external + : open true ; + : close ; + +finish-device + +: ?devalias ( alias-str alias-len device-str device-len -- + \ alias-str alias-len false | true ) + active-package >r + " /aliases" find-device + \ 2dup ." Checking " type + 2dup find-dev if \ check if device exists + drop + 2over find-dev if \ do we already have an alias? + \ ." alias exists" cr + drop 2drop false + else + \ ." device exists" cr + encode-string + 2swap property + true + then + else + \ ." device doesn't exist" cr + 2drop false + then + r> active-package! + ; + +:noname + " hd" + " /pci/isa/ide0/disk@0" ?devalias not if + " /pci/isa/ide0/disk@1" ?devalias not if + " /pci/isa/ide1/disk@0" ?devalias not if + " /pci/isa/ide1/disk@1" ?devalias not if + 2drop ." No disk found." cr + then + then + then + then + + " cdrom" + " /pci/isa/ide0/cdrom@0" ?devalias not if + " /pci/isa/ide0/cdrom@1" ?devalias not if + " /pci/isa/ide1/cdrom@0" ?devalias not if + " /pci/isa/ide1/cdrom@1" ?devalias not if + 2drop ." No cdrom found" cr + then + then + then + then +; SYSTEM-initializer + + +[THEN] + +device-end diff --git a/drivers/ide.h b/drivers/ide.h new file mode 100644 index 0000000..e56d9b4 --- /dev/null +++ b/drivers/ide.h @@ -0,0 +1,217 @@ +#ifndef IDE_H +#define IDE_H + +#include "hdreg.h" + +/* + * legacy ide ports + */ +#define IDEREG_DATA 0x00 +#define IDEREG_ERROR 0x01 +#define IDEREG_FEATURE IDEREG_ERROR +#define IDEREG_NSECTOR 0x02 +#define IDEREG_SECTOR 0x03 +#define IDEREG_LCYL 0x04 +#define IDEREG_HCYL 0x05 +#define IDEREG_CURRENT 0x06 +#define IDEREG_STATUS 0x07 +#define IDEREG_COMMAND IDEREG_STATUS +#define IDEREG_CONTROL 0x08 +#define IDEREG_ASTATUS IDEREG_CONTROL + +/* + * device control bits + */ +#define IDECON_NIEN 0x02 +#define IDECON_SRST 0x04 + +/* + * device head bits + */ +#define IDEHEAD_LBA 0x40 +#define IDEHEAD_DEV0 0x00 +#define IDEHEAD_DEV1 0x10 + +/* + * status bytes + */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +#define IREASON_CD 0x01 +#define IREASON_IO 0x02 + +/* + * ATA opcodes + */ +#define WIN_READ 0x20 +#define WIN_READ_EXT 0x24 +#define WIN_IDENTIFY 0xEC +#define WIN_PACKET 0xA0 +#define WIN_IDENTIFY_PACKET 0xA1 + +/* + * ATAPI opcodes + */ +#define ATAPI_TUR 0x00 +#define ATAPI_READ_10 0x28 +#define ATAPI_REQ_SENSE 0x03 +#define ATAPI_START_STOP_UNIT 0x1b +#define ATAPI_READ_CAPACITY 0x25 + +/* + * atapi sense keys + */ +#define ATAPI_SENSE_NOT_READY 0x02 + +/* + * supported device types + */ +enum { + ide_type_unknown, + ide_type_ata, + ide_type_atapi, +}; + +enum { + ide_media_floppy = 0x00, + ide_media_cdrom = 0x05, + ide_media_optical = 0x07, + ide_media_disk = 0x20, +}; + +/* + * drive addressing + */ +enum { + ide_chs = 1, + ide_lba28, + ide_lba48, +}; + +/* + * simple ata command that works for everything (except 48-bit lba commands) + */ +struct ata_command { + char *buffer; + unsigned int buflen; + + /* + * data register + */ + unsigned char data; + unsigned char feature; + unsigned char nsector; + unsigned char sector; + unsigned char lcyl; + unsigned char hcyl; + unsigned char device_head; + unsigned char command; + unsigned char control; + + /* + * or tasklet, just for lba48 for now (above could be scrapped) + */ + unsigned char task[10]; + + /* + * output + */ + unsigned char stat; + unsigned int bytes; +}; + +struct atapi_command { + unsigned char cdb[12]; + unsigned char *buffer; + unsigned int buflen; + unsigned char data_direction; + + unsigned char stat; + unsigned char sense_valid; + struct request_sense sense; + unsigned char old_cdb; +}; + +struct ide_channel; + +struct ide_drive { + char unit; /* 0: master, 1: slave */ + char present; /* there or not */ + char type; /* ata or atapi */ + char media; /* disk, cdrom, etc */ + char addressing; /* chs/lba28/lba48 */ + + char model[40]; /* name */ + int nr; + + unsigned long sectors; + + unsigned int max_sectors; + + /* + * for legacy chs crap + */ + unsigned int cyl; + unsigned int head; + unsigned int sect; + + unsigned int bs; /* block size */ + + struct ide_channel *channel; +}; + +struct ide_channel { + /* + * either mmio or io_regs is set to indicate mmio or not + */ + int mmio; + int io_regs[10]; + + /* + * can be set to a mmio hook, default it legacy outb/inb + */ + void (*obide_outb)(unsigned char addr, unsigned long port); + unsigned char (*obide_inb)(unsigned long port); + void (*obide_insw)(unsigned long port, unsigned char *addr, unsigned int count); + void (*obide_outsw)(unsigned long port, unsigned char *addr, unsigned int count); + + struct ide_drive drives[2]; + char selected; + char present; + + /* + * only one can be busy per channel + */ + struct ata_command ata_cmd; + struct atapi_command atapi_cmd; + +}; + +enum { + atapi_ddir_none, + atapi_ddir_read, + atapi_ddir_write, +}; + +struct ata_sector { + u16 all; + union { +#ifdef CONFIG_BIG_ENDIAN + u8 high; + u8 low; +#endif +#ifdef CONFIG_LITTLE_ENDIAN + u8 low; + u8 high; +#endif + }; +}; + +static int ob_ide_atapi_request_sense(struct ide_drive *drive); + +#endif diff --git a/drivers/kbd.c b/drivers/kbd.c new file mode 100644 index 0000000..b65ebc6 --- /dev/null +++ b/drivers/kbd.c @@ -0,0 +1,106 @@ +/* + * + * + * Open Hack'Ware BIOS generic keyboard input translation. + * + * Copyright (c) 2005 Jocelyn Mayer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License V2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#include +#include +#include "kbd.h" + +//#define DEBUG_KBD +#ifdef DEBUG_KBD +#define KBD_DPRINTF(fmt, args...) \ +do { printk("KBD - %s: " fmt, __func__ , ##args); } while (0) +#else +#define KBD_DPRINTF(fmt, args...) do { } while (0) +#endif + +int kbd_set_keymap (kbd_t *kbd, int nb_keys, keymap_t *keymap) +{ + kbd->nb_keys = nb_keys; + kbd->keymap = keymap; + + return 0; +} + +int kbd_translate_key (kbd_t *kbd, int keycode, int up_down) +{ + keymap_t *keyt; + int mod_state, key, type; + int ret; + + ret = -1; + /* Get key table */ + if (keycode < kbd->nb_keys) { + keyt = &kbd->keymap[keycode]; + /* Get modifier state */ + mod_state = (kbd->mod_state | (kbd->mod_state >> 8)) & 0xFF; + /* Adjust with lock */ + if (keyt->lck_shift >= 0) { + if ((kbd->mod_state >> (16 + keyt->lck_shift)) & 0x01) { + KBD_DPRINTF("adjust with lock %02x => %02x (%d %08x)\n", + mod_state, + mod_state ^ ((kbd->mod_state >> + (16 + keyt->lck_shift)) & + 0x01), + keyt->lck_shift, kbd->mod_state); + } + mod_state ^= (kbd->mod_state >> (16 + keyt->lck_shift)) & 0x01; + } + key = keyt->trans[mod_state]; + type = key & 0xFF000000; + key &= ~0xFF000000; + switch (type) { + case KBD_TYPE_REGULAR: + if (!up_down) { + /* We don't care about up events on "normal" keys */ + ret = key; + } + break; + case KBD_TYPE_LOCK: + if (!up_down) { + kbd->mod_state ^= key; + ret = -2; + KBD_DPRINTF("Change modifier type %d key %04x %s => %08x\n", + type, key, up_down ? "up" : "down", + kbd->mod_state); + } + break; + case KBD_TYPE_LMOD: + case KBD_TYPE_RMOD: + if (up_down) + kbd->mod_state &= ~key; + else + kbd->mod_state |= key; + KBD_DPRINTF("Change modifier type %d key %04x %s => %08x\n", + type, key, up_down ? "up" : "down", kbd->mod_state); + ret = -2; /* The caller may know the key was a modifier */ + break; + default: + KBD_DPRINTF("Unknown key: keycode=%02x mod_state=%02x (%08x)\n", + keycode, mod_state, kbd->mod_state); + break; + } + } else { + KBD_DPRINTF("Unmanaged key: keycode=%02x mod_state %08x\n", + keycode, kbd->mod_state); + } + + return ret; +} diff --git a/drivers/kbd.h b/drivers/kbd.h new file mode 100644 index 0000000..c6069a2 --- /dev/null +++ b/drivers/kbd.h @@ -0,0 +1,104 @@ +/* + * + * + * Open Hack'Ware BIOS generic keyboard management definitions. + * + * Copyright (c) 2005 Jocelyn Mayer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License V2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#if !defined (__OHW_KBD_H__) +#define __OHW_KBD_H__ +#include +typedef struct kbd_t kbd_t; +typedef struct keymap_t keymap_t; +struct kbd_t { + uint32_t mod_state; + /* Modifier state + * 0x00 kk ll rr + * | | | | + * Not used for now -+ | | | + * Locks ---------------+ | | + * Left modifiers ---------+ | + * Right modifiers -----------+ + */ + int nb_keys; + keymap_t *keymap; +}; + +/* Modifiers */ +typedef enum { + KBD_MOD_SHIFT = 0x01, + KBD_MOD_CTRL = 0x02, + KBD_MOD_ALT = 0x04, + KBD_MOD_CMD = 0x08, + KBD_MOD_OPT = 0x10, +} kbd_modifiers; + +/* Locks */ +typedef enum { + KBD_LCK_CAPS = 0x01, + KBD_LCK_NUM = 0x02, + KBD_LCK_SCROLL = 0x04, +} kbd_locks; + +/* Lock shifts */ +typedef enum { + KBD_SH_NONE = -1, + KBD_SH_CAPS = 0, + KBD_SH_NUML = 1, + KBD_SH_SCRL = 2, +} kbd_lck_shifts; + +enum { + KBD_TYPE_REGULAR = 0 << 24, + KBD_TYPE_LMOD = 1 << 24, + KBD_TYPE_RMOD = 2 << 24, + KBD_TYPE_LOCK = 3 << 24, +}; + +#define KBD_MOD_MAP(mod) \ +KBD_SH_NONE, { (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \ + (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \ + (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \ + (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), } +#define KBD_MOD_MAP_LSHIFT KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_SHIFT) +#define KBD_MOD_MAP_RSHIFT KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_SHIFT << 8)) +#define KBD_MOD_MAP_LCTRL KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_CTRL) +#define KBD_MOD_MAP_RCTRL KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_CTRL << 8)) +#define KBD_MOD_MAP_LALT KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_ALT) +#define KBD_MOD_MAP_RALT KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_ALT << 8)) +#define KBD_MOD_MAP_LCMD KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_CMD) +#define KBD_MOD_MAP_RCMD KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_CMD << 8)) +#define KBD_MOD_MAP_LOPT KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_OPT) +#define KBD_MOD_MAP_ROPT KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_OPT << 8)) +#define KBD_MOD_MAP_CAPS KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_CAPS << 16)) +#define KBD_MOD_MAP_NUML KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_NUML << 16)) +#define KBD_MOD_MAP_SCROLL KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_SCRL << 16)) +#define KBD_MAP_NONE KBD_MOD_MAP(-1) + +/* Keymap definition */ +struct keymap_t { + /* Set the lock which applies to this key (if any) */ + int lck_shift; + /* Key translations */ + uint32_t trans[32]; +}; + +void *kbd_new (int len); +int kbd_set_keymap (kbd_t *kbd, int nb_keys, keymap_t *keymap); +int kbd_translate_key (kbd_t *kbd, int keycode, int up_down); + +#endif /* !defined (__OHW_KBD_H__) */ diff --git a/drivers/pci.c b/drivers/pci.c new file mode 100644 index 0000000..7c142e7 --- /dev/null +++ b/drivers/pci.c @@ -0,0 +1,333 @@ +/* + * OpenBIOS pci driver + * + * This driver is compliant to the + * PCI bus binding to IEEE 1275-1994 Rev 2.1 + * + * (C) 2004 Stefan Reinauer + * (C) 2005 Ed Schouten + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/kernel.h" +#include "libc/byteorder.h" +#include "libc/vsprintf.h" + +#include "openbios/drivers.h" +#include "timer.h" +#include "pci.h" + +#define REGISTER_NAMED_NODE( name, path ) do { \ + bind_new_node( name##_flags_, name##_size_, \ + path, name##_m, sizeof(name##_m)/sizeof(method_t)); \ + } while(0) + +#define set_bool_property(ph, name) set_property(ph, name, NULL, 0); + +/* DECLARE data structures for the nodes. */ +DECLARE_UNNAMED_NODE( ob_pci_node, INSTALL_OPEN, 2*sizeof(int) ); + +static void +ob_pci_open(int *idx) +{ + int ret=1; + RET ( -ret ); +} + +static void +ob_pci_close(int *idx) +{ + selfword("close-deblocker"); +} + +static void +ob_pci_initialize(int *idx) +{ +} + + +NODE_METHODS(ob_pci_node) = { + { NULL, ob_pci_initialize }, + { "open", ob_pci_open }, + { "close", ob_pci_close }, +}; + +static int ob_pci_add_properties(pci_addr addr) +{ + phandle_t dev=get_cur_dev(); + int status,id; + + /* create properties as described in 2.5 */ + + set_int_property(dev, "vendor-id", pci_config_read16(addr, PCI_VENDOR_ID)); + set_int_property(dev, "device-id", pci_config_read16(addr, PCI_DEVICE_ID)); + set_int_property(dev, "revision-id", pci_config_read8(addr, PCI_REVISION_ID)); + + set_int_property(dev, "interrupts", + pci_config_read8(addr, PCI_INTERRUPT_LINE)); + + set_int_property(dev, "min-grant", pci_config_read8(addr, PCI_MIN_GNT)); + set_int_property(dev, "max-latency", pci_config_read8(addr, PCI_MAX_LAT)); + + status=pci_config_read16(addr, PCI_STATUS); + + set_int_property(dev, "devsel-speed", + (status&PCI_STATUS_DEVSEL_MASK)>>10); + + if(status&PCI_STATUS_FAST_BACK) + set_bool_property(dev, "fast-back-to-back"); + if(status&PCI_STATUS_66MHZ) + set_bool_property(dev, "66mhz-capable"); + if(status&PCI_STATUS_UDF) + set_bool_property(dev, "udf-supported"); + + id=pci_config_read16(addr, PCI_SUBSYSTEM_VENDOR_ID); + if(id) + set_int_property(dev, "subsystem-vendor-id", id); + id=pci_config_read16(addr, PCI_SUBSYSTEM_ID); + if(id) + set_int_property(dev, "subsystem-id", id); + + set_int_property(dev, "cache-line-size", + pci_config_read16(addr, PCI_CACHE_LINE_SIZE)); + +} + + +static int ob_pci_add_reg(pci_addr addr) +{ + PUSH(0); + PUSH(0); + PUSH(addr&(~0x80000000u)); + fword("pci-addr-encode"); + PUSH(0); + PUSH(0); + fword("pci-len-encode"); + fword("encode+"); + push_str("reg"); + fword("property"); +} + +static int ob_pci_add_class(pci_addr addr) +{ + unsigned int class; + char *strc; + + class=pci_config_read16(addr, PCI_CLASS_DEVICE); + switch (class) { + case 0x001: strc="display"; break; + case 0x100: strc="scsi"; break; + case 0x101: strc="ide"; break; + case 0x102: strc="fdc"; break; + case 0x103: strc="ipi"; break; + case 0x104: strc="raid"; break; + case 0x200: strc="ethernet"; break; + case 0x201: strc="token-ring"; break; + case 0x202: strc="fddi"; break; + case 0x203: strc="atm"; break; + case 0x400: strc="video"; break; + case 0x401: strc="sound"; break; + case 0x500: strc="memory"; break; + case 0x501: strc="flash"; break; + case 0x600: strc="host"; break; + case 0x601: strc="isa"; break; + case 0x602: strc="eisa"; break; + case 0x603: strc="mca"; break; + case 0x604: strc="pci"; break; + case 0x605: strc="pcmcia"; break; + case 0x606: strc="nubus"; break; + case 0x607: strc="cardbus"; break; + case 0x680: strc="pmu"; break; /* not in pci binding */ + case 0x700: strc="serial"; break; + case 0x701: strc="parallel"; break; + case 0x703: strc="modem"; break; /* not in pci binding */ + case 0x800: strc="interrupt-controller"; break; + case 0x801: strc="dma-controller"; break; + case 0x802: strc="timer"; break; + case 0x803: strc="rtc"; break; + case 0x900: strc="keyboard"; break; + case 0x901: strc="pen"; break; + case 0x902: strc="mouse"; break; + case 0xC00: strc="firewire"; break; + case 0xC01: strc="access-bus"; break; + case 0xC02: strc="ssa"; break; + case 0xC03: strc="usb"; break; + case 0xC04: strc="fibre-channel"; break; + default: + switch (class>>8) { + case 0x3: strc="display"; break; + case 0xA: strc="dock"; break; + case 0xB: strc="cpu"; break; + default:strc="unknown"; break; + } + } + if ((class>>8) == 0x03) { + push_str(strc); + fword("encode-string"); + push_str("device_type"); + fword("property"); + } + push_str(strc); + fword("encode-string"); + push_str("class"); + fword("property"); + + +#ifdef CONFIG_DEBUG_PCI + printk("%s\n", strc); +#endif +} + +static void +pci_enable_rom(pci_addr dev) +{ + u32 rom_addr; + + rom_addr=pci_config_read32(dev, PCI_ROM_ADDRESS); + rom_addr |= PCI_ROM_ADDRESS_ENABLE; + pci_config_write32(dev, PCI_ROM_ADDRESS, rom_addr); +} + +static void +pci_disable_rom(pci_addr dev) +{ + u32 rom_addr; + + rom_addr=pci_config_read32(dev, PCI_ROM_ADDRESS); + rom_addr &= ~PCI_ROM_ADDRESS_ENABLE; + pci_config_write32(dev, PCI_ROM_ADDRESS, rom_addr); +} + + +static void ob_pci_scan_rom(pci_addr addr) +{ + unsigned long rom_addr=pci_config_read32(addr,PCI_ROM_ADDRESS); + unsigned char *walk; + + rom_addr &= PCI_ROM_ADDRESS_MASK; + if(rom_addr) { + printk(" ROM found at 0x%lx\n",rom_addr); + pci_enable_rom(addr); + walk=phys_to_virt((unsigned char *)rom_addr); + if (walk[0]!=0x55 || walk[1]!=0xaa) { + printk("no pci rom\n"); + goto rom_err; + } + +rom_err: + pci_disable_rom(addr); + } + +} + +#ifdef CONFIG_XBOX +static char pci_xbox_blacklisted (int bus, int devnum, int fn) +{ + /* + * The Xbox MCPX chipset is a derivative of the nForce 1 + * chipset. It almost has the same bus layout; some devices + * cannot be used, because they have been removed. + */ + + /* + * Devices 00:00.1 and 00:00.2 used to be memory controllers on + * the nForce chipset, but on the Xbox, using them will lockup + * the chipset. + */ + if ((bus == 0) && (devnum == 0) && ((fn == 1) || (fn == 2))) + return 1; + + /* + * Bus 1 only contains a VGA controller at 01:00.0. When you try + * to probe beyond that device, you only get garbage, which + * could cause lockups. + */ + if ((bus == 1) && ((devnum != 0) || (fn != 0))) + return 1; + + /* + * Bus 2 used to contain the AGP controller, but the Xbox MCPX + * doesn't have one. Probing it can cause lockups. + */ + if (bus >= 2) + return 1; + + /* + * The device is not blacklisted. + */ + return 0; +} +#endif + +static void ob_scan_pci_bus(int bus, char *path) +{ + int devnum, fn, is_multi, vid, did; + unsigned int htype; + pci_addr addr; + char * nodetemp = "%s/pci%x,%x"; + char nodebuff[32]; + phandle_t dnode, dbus; + + for (devnum = 0; devnum < 32; devnum++) { + is_multi = 0; + for (fn = 0; fn==0 || (is_multi && fn<8); fn++) { +#ifdef CONFIG_XBOX + if (pci_xbox_blacklisted (bus, devnum, fn)) + continue; +#endif + + addr = PCI_ADDR(bus, devnum, fn); + vid = pci_config_read16(addr, PCI_VENDOR_ID); + did = pci_config_read16(addr, PCI_DEVICE_ID); + + if (vid==0xffff || vid==0) + continue; +#ifdef CONFIG_DEBUG_PCI + printk("%x:%x.%x - %x:%x - ", bus, devnum, fn, + vid, did); +#endif + htype = pci_config_read8(addr, PCI_HEADER_TYPE); + if (fn == 0) + is_multi = htype & 0x80; + + activate_device(path); + + dbus=get_cur_dev(); + sprintf(nodebuff, nodetemp, path, vid, did); +#ifdef CONFIG_DEBUG_PCI + printk("%s - ", nodebuff); +#endif + REGISTER_NAMED_NODE(ob_pci_node, nodebuff); + dnode=find_dev(nodebuff); + activate_dev( dnode ); + + ob_pci_add_properties(addr); + ob_pci_add_reg(addr); + ob_pci_add_class(addr); + ob_pci_scan_rom(addr); + device_end(); + activate_dev( dbus ); + } + } +} + + +int ob_pci_init(void) +{ + char *path="/pci"; + int bus; + + printk("Initializing PCI devices...\n"); + + /* brute force bus scan */ + for (bus=0; bus<0x100; bus++) { + ob_scan_pci_bus(bus, path); + } + return 0; +} diff --git a/drivers/pci.fs b/drivers/pci.fs new file mode 100644 index 0000000..64bcda2 --- /dev/null +++ b/drivers/pci.fs @@ -0,0 +1,37 @@ +[IFDEF] CONFIG_DRIVER_PCI + +dev / + +\ simple pci bus node +new-device + " pci" device-name + 3 encode-int " #address-cells" property + 2 encode-int " #size-cells" property + 0 encode-int 0 encode-int encode+ " bus-range" property + " pci" encode-string " device_type" property + + external + : open ( cr ." opening PCI" cr ) true ; + : close ; + : decode-unit 0 decode-unit-pci-bus ; + : encode-unit encode-unit-pci ; +finish-device + +device-end + +: pci-addr-encode ( addr.lo addr.mi addr.hi ) + rot >r swap >r + encode-int + r> encode-int encode+ + r> encode-int encode+ + ; + +: pci-len-encode ( len.lo len.hi ) + encode-int + rot encode-int encode+ + ; + + + +[THEN] + diff --git a/drivers/pci.h b/drivers/pci.h new file mode 100644 index 0000000..39f0dc8 --- /dev/null +++ b/drivers/pci.h @@ -0,0 +1,79 @@ +#ifndef PCI_H +#define PCI_H + +#define PCI_VENDOR_ID 0x00 +#define PCI_DEVICE_ID 0x02 + +#define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features + [obsolete] */ +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ +#define PCI_STATUS_DEVSEL_FAST 0x000 +#define PCI_STATUS_DEVSEL_MEDIUM 0x200 +#define PCI_STATUS_DEVSEL_SLOW 0x400 +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ + + +#define PCI_REVISION_ID 0x08 /* Revision ID */ +#define PCI_CLASS_PROG 0x09 +#define PCI_CLASS_DEVICE 0x0a +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e +#define PCI_HEADER_TYPE_NORMAL 0x00 +#define PCI_HEADER_TYPE_BRIDGE 0x01 +#define PCI_HEADER_TYPE_CARDBUS 0x02 +#define PCI_SECONDARY_BUS 0x19 +#define PCI_BASE_ADDR_0 0x10 +#define PCI_BASE_ADDR_1 0x14 +#define PCI_BASE_ADDR_2 0x18 +#define PCI_BASE_ADDR_3 0x1c +#define PCI_BASE_ADDR_4 0x20 +#define PCI_BASE_ADDR_5 0x24 + +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c +#define PCI_SUBSYSTEM_ID 0x2e + +#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ +#define PCI_ROM_ADDRESS_ENABLE 0x01 +#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) + +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + +typedef uint32_t pci_addr; + +typedef struct { + u16 signature; + u8 reserved[0x16]; + u16 dptr; +} rom_header_t; + +typedef struct { + u32 signature; + u16 vendor; + u16 device; + u16 reserved_1; + u16 dlen; + u8 drevision; + u8 class_hi; + u16 class_lo; + u16 ilen; + u16 irevision; + u8 type; + u8 indicator; + u16 reserved_2; +} pci_data_t; + + +#include "asm/pci.h" + +#endif /* PCI_H */ diff --git a/drivers/timer.c b/drivers/timer.c new file mode 100644 index 0000000..6b58ea1 --- /dev/null +++ b/drivers/timer.c @@ -0,0 +1,104 @@ +/* + * OpenBIOS native timer driver + * + * (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "timer.h" +#include "asm/io.h" + +#if defined(CONFIG_X86) || defined(CONFIG_AMD64) + +void setup_timers(void) +{ + /* nothing to do */ +} + +static void load_timer2(unsigned int ticks) +{ + /* Set up the timer gate, turn off the speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + outb(TIMER2_SEL | WORD_ACCESS | MODE0 | BINARY_COUNT, + TIMER_MODE_PORT); + outb(ticks & 0xFF, TIMER2_PORT); + outb(ticks >> 8, TIMER2_PORT); +} + +void udelay(unsigned int usecs) +{ + load_timer2((usecs * TICKS_PER_MS) / 1000); + while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); +} + +unsigned long currticks(void) +{ + static unsigned long totticks = 0UL; /* High resolution */ + unsigned long ticks = 0; + unsigned char portb = inb(PPC_PORTB); + + /* + * Read the timer, and hope it hasn't wrapped around + * (call this again within 54ms), then restart it + */ + outb(TIMER2_SEL | LATCH_COUNT, TIMER_MODE_PORT); + ticks = inb(TIMER2_PORT); + ticks |= inb(TIMER2_PORT) << 8; + outb(TIMER2_SEL | WORD_ACCESS | MODE0 | BINARY_COUNT, + TIMER_MODE_PORT); + outb(0, TIMER2_PORT); + outb(0, TIMER2_PORT); + + /* + * Check if the timer was running. If not, + * result is rubbish and need to start it + */ + if (portb & PPCB_T2GATE) { + totticks += (0x10000 - ticks); + } else { + /* Set up the timer gate, turn off the speaker */ + outb((portb & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + } + return totticks / TICKS_PER_MS; +} +#endif + +#ifdef CONFIG_PPC + +void setup_timers(void) +{ + /* nothing to do */ +} + +/* + * TODO: pass via lb table + */ + +unsigned long get_timer_freq() +{ + return 100000000 / 4; +} + +void udelay(unsigned int usecs) +{ + extern void _wait_ticks(unsigned long); + unsigned long ticksperusec = get_timer_freq() / 1000000; + _wait_ticks(ticksperusec * usecs); +} + +#endif + +void ndelay(unsigned int nsecs) +{ + udelay((nsecs + 999) / 1000); +} + +void mdelay(unsigned int msecs) +{ + udelay(msecs * 1000); +} diff --git a/drivers/timer.h b/drivers/timer.h new file mode 100644 index 0000000..c822665 --- /dev/null +++ b/drivers/timer.h @@ -0,0 +1,60 @@ +/* Taken from Etherboot */ +/* Defines for routines to implement a low-overhead timer for drivers */ + + /* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + */ + +#ifndef TIMER_H +#define TIMER_H + +/* Ports for the 8254 timer chip */ +#define TIMER2_PORT 0x42 +#define TIMER_MODE_PORT 0x43 + +/* Meaning of the mode bits */ +#define TIMER0_SEL 0x00 +#define TIMER1_SEL 0x40 +#define TIMER2_SEL 0x80 +#define READBACK_SEL 0xC0 + +#define LATCH_COUNT 0x00 +#define LOBYTE_ACCESS 0x10 +#define HIBYTE_ACCESS 0x20 +#define WORD_ACCESS 0x30 + +#define MODE0 0x00 +#define MODE1 0x02 +#define MODE2 0x04 +#define MODE3 0x06 +#define MODE4 0x08 +#define MODE5 0x0A + +#define BINARY_COUNT 0x00 +#define BCD_COUNT 0x01 + +/* Timers tick over at this rate */ +#define CLOCK_TICK_RATE 1193180U +#define TICKS_PER_MS (CLOCK_TICK_RATE/1000) + +/* Parallel Peripheral Controller Port B */ +#define PPC_PORTB 0x61 + +/* Meaning of the port bits */ +#define PPCB_T2OUT 0x20 /* Bit 5 */ +#define PPCB_SPKR 0x02 /* Bit 1 */ +#define PPCB_T2GATE 0x01 /* Bit 0 */ + +extern void setup_timers(void); +extern void ndelay(unsigned int nsecs); +extern void udelay(unsigned int usecs); +extern void mdelay(unsigned int msecs); +extern unsigned long currticks(void); +extern unsigned long get_timer_freq(void); + +#define TICKS_PER_SEC 1000 + +#endif /* TIMER_H */ diff --git a/forth/Kconfig b/forth/Kconfig new file mode 100644 index 0000000..87ff191 --- /dev/null +++ b/forth/Kconfig @@ -0,0 +1,9 @@ +# +# +# + +#menu "Packages" +# +#source "forth/packages/Kconfig" +# +#endmenu diff --git a/forth/admin/README b/forth/admin/README new file mode 100644 index 0000000..a2ac6af --- /dev/null +++ b/forth/admin/README @@ -0,0 +1,5 @@ +\ This directory contains code that implements +\ the Administration command group +\ (Chapter 7.4 in the IEEE 1275-1994) + + diff --git a/forth/admin/banner.fs b/forth/admin/banner.fs new file mode 100644 index 0000000..5439fc0 --- /dev/null +++ b/forth/admin/banner.fs @@ -0,0 +1,49 @@ +\ 7.4.10 Banner + +defer builtin-logo +defer builtin-banner +0 value suppress-banner? + +:noname + 0 0 +; to builtin-logo + +:noname + builddate s" built on " version s" Welcome to OpenBIOS v" pocket + tmpstrcat tmpstrcat tmpstrcat drop +; to builtin-banner + +: suppress-banner ( -- ) + 1 to suppress-banner? +; + +: banner ( -- ) + suppress-banner + stdout @ ?dup 0= if exit then + + \ draw logo if stdout is a "display" node + dup ihandle>phandle " device_type" rot get-package-property if 0 0 then + " display" strcmp if + drop + else + \ draw logo ( ihandle ) + dup ihandle>phandle " draw-logo" rot find-method if + ( ihandle xt ) + swap >r >r + 0 \ line # + oem-logo? if oem-logo else builtin-logo then + ( 0 addr logo-len ) + 200 = if + d# 64 d# 64 + r> r> call-package + else + r> r> 2drop 2drop + then + else + drop + then + then + + oem-banner? if oem-banner else builtin-banner then + type cr +; diff --git a/forth/admin/build.xml b/forth/admin/build.xml new file mode 100644 index 0000000..6654496 --- /dev/null +++ b/forth/admin/build.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/forth/admin/callback.fs b/forth/admin/callback.fs new file mode 100644 index 0000000..e318af2 --- /dev/null +++ b/forth/admin/callback.fs @@ -0,0 +1,10 @@ +\ 7.4.9 Client program callback + +: callback ( "service-name< >" "arguments" -- ) + ; + +: $callback ( argn ... arg1 nargs addr len -- retn ... ret2 Nreturns-1 ) + ; + +: sync ( -- ) + ; diff --git a/forth/admin/devices.fs b/forth/admin/devices.fs new file mode 100644 index 0000000..75962af --- /dev/null +++ b/forth/admin/devices.fs @@ -0,0 +1,356 @@ +\ tag: device tree administration +\ +\ this code implements IEEE 1275-1994 +\ +\ Copyright (C) 2003 Samuel Rydh, Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + + +\ 7.4.11.1 Device alias + +: devalias ( "{alias-name}< >{device-specifier}" -- ) + ; + +: nvalias ( "alias-name< >device-specifier" -- ) + ; + +: $nvalias ( name-str name-len dev-str dev-len -- ) + ; + +: nvunalias ( "alias-name< >" -- ) + ; + +: $nvunalias ( name-str name-len -- ) + ; + + +\ 7.4.11.2 Device tree browsing + +: dev ( "device-specifier" -- ) + bl parse + find-device +; + +: cd + dev +; + +\ find-device ( dev-str dev-len -- ) +\ implemented in pathres.fs + +: device-end ( -- ) + 0 active-package! + ; + +: ?active-package ( -- phandle ) + active-package dup 0= abort" no active device" +; + +\ ------------------------------------------------------- +\ path handling +\ ------------------------------------------------------- + +\ used if parent lacks an encode-unit method +: def-encode-unit ( unitaddr ... ) + pocket tohexstr +; + +: get-encode-unit-xt ( phandle.parent -- xt ) + >dn.parent @ + " encode-unit" rot find-method + 0= if ['] def-encode-unit then +; + +: get-nodename ( phandle -- str len ) + " name" rot get-package-property if " " else 1- then +; + +\ helper, return the node name in the format 'cpus@addr' +: pnodename ( phandle -- str len ) + dup get-nodename rot + dup " reg" rot get-package-property if drop exit then rot + + \ set active-package and clear my-self (decode-phys needs this) + my-self >r 0 to my-self + active-package >r + dup active-package! + + ( name len prop len phandle ) + get-encode-unit-xt + + ( name len prop len xt ) + depth >r >r + decode-phys r> execute + r> -rot >r >r depth! 3drop + + ( name len R: len str ) + r> r> " @" + here 20 + \ abuse dictionary for temporary storage + tmpstrcat >r + 2swap r> tmpstrcat drop + pocket tmpstrcpy drop + + r> active-package! + r> to my-self +; + +: inodename ( ihandle -- str len ) + my-self over to my-self >r + ihandle>phandle get-nodename + + \ nonzero unit number? + false >r + depth >r my-unit r> 1+ + begin depth over > while + swap 0<> if r> drop true >r then + repeat + drop + + \ if not... check for presence of "reg" property + r> ?dup 0= if + " reg" my-self ihandle>phandle get-package-property + if false else 2drop true then + then + + ( name len print-unit-flag ) + if + my-self ihandle>phandle get-encode-unit-xt + + ( name len xt ) + depth >r >r + my-unit r> execute + r> -rot >r >r depth! drop + r> r> + ( name len str len ) + here 20 + tmpstrcpy + " @" rot tmpstrcat drop + 2swap pocket tmpstrcat drop + then + + \ add :arguments + my-args dup if + " :" pocket tmpstrcat drop + 2swap pocket tmpstrcat drop + else + 2drop + then + + r> to my-self +; + +\ helper, also used by client interface (package-to-path) +: get-package-path ( phandle -- str len ) + ?dup 0= if 0 0 then + + dup >dn.parent @ 0= if drop " /" exit then + \ dictionary abused for temporary storage + >r 0 0 here 40 + + begin r> dup >dn.parent @ dup >r while + ( path len tempbuf phandle R: phandle.parent ) + pnodename rot tmpstrcat + " /" rot tmpstrcat + repeat + r> 3drop + pocket tmpstrcpy drop +; + +\ used by client interface (instance-to-path) +: get-instance-path ( ihandle -- str len ) + ?dup 0= if 0 0 then + + dup ihandle>phandle >dn.parent @ 0= if drop " /" exit then + + \ dictionary abused for temporary storage + >r 0 0 here 40 + + begin r> dup >in.my-parent @ dup >r while + ( path len tempbuf ihandle R: ihandle.parent ) + dup >in.interposed @ 0= if + inodename rot tmpstrcat + " /" rot tmpstrcat + else + drop + then + repeat + r> 3drop + pocket tmpstrcpy drop +; + +\ used by client interface (instance-to-interposed-path) +: get-instance-interposed-path ( ihandle -- str len ) + ?dup 0= if 0 0 then + + dup ihandle>phandle >dn.parent @ 0= if drop " /" exit then + + \ dictionary abused for temporary storage + >r 0 0 here 40 + + begin r> dup >in.my-parent @ dup >r while + ( path len tempbuf ihandle R: ihandle.parent ) + dup >r inodename rot tmpstrcat + r> >in.interposed @ if " /%" else " /" then + rot tmpstrcat + repeat + r> 3drop + pocket tmpstrcpy drop +; + +: pwd ( -- ) + ?active-package get-package-path type +; + +: ls ( -- ) + cr + ?active-package >dn.child @ + begin dup while + dup . dup pnodename type cr + >dn.peer @ + repeat + drop +; + + +\ ------------------------------------------- +\ property printing +\ ------------------------------------------- + +: .p-string? ( data len -- true | data len false ) + \ no trailing zero? + 2dup + 1- c@ if 0 exit then + + swap >r 0 + \ count zeros and detect unprintable characters? + over 1- begin 1- dup 0>= while + dup r@ + c@ + ( len zerocnt n ch ) + + ?dup 0= if + swap 1+ swap + else + dup 1b <= swap 80 >= or + if 2drop r> swap 0 exit then + then + repeat drop r> -rot + ( data len zerocnt ) + + \ simple string + 0= if + ascii " emit 1- type ascii " emit true exit + then + + \ make sure there are no double zeros (except possibly at the end) + 2dup over + swap + ( data len end ptr ) + begin 2dup <> while + dup c@ 0= if + 2dup 1+ <> if 2drop false exit then + then + dup cstrlen 1+ + + repeat + 2drop + + ." {" + 0 -rot over + swap + \ multistring ( cnt end ptr ) + begin 2dup <> while + rot dup if ." , " then 1+ -rot + dup cstrlen 2dup + ascii " emit type ascii " emit + 1+ + + repeat + ." }" + 3drop true +; + +: .p-int? ( data len -- 1 | data len 0 ) + dup 4 <> if false exit then + decode-int -rot 2drop true swap + dup 0>= if . exit then + dup -ff < if u. exit then + . +; + +: .p-bytes? ( data len -- 1 | data len 0 ) + ." -- " dup . ." : " + swap >r 0 + begin 2dup > while + dup r@ + c@ + ( len n ch ) + + pocket tohexstr type ." " + 1+ + repeat + 2drop r> drop 1 +; + +\ this function tries to heuristically determine the data format +: (.property) ( data len -- ) + dup 0= if 2drop ." " exit then + + .p-string? if exit then + .p-int? if exit then + .p-bytes? if exit then + 2drop ." " +; + +: .properties ( -- ) + ?active-package dup >r if + 0 0 + begin + r@ next-property + while + cr 2dup dup -rot type + begin ." " 1+ dup d# 26 >= until drop + 2dup active-package get-package-property drop (.property) + repeat + then + r> drop + cr +; + + +\ 7.4.11 Device tree + +: print-dev ( phandle -- phandle ) + dup . + dup get-package-path type + dup " device_type" rot get-package-property if + cr + else + ." (" decode-string type ." )" cr 2drop + then + ; + +: show-sub-devs ( subtree-phandle -- ) + print-dev + >dn.child @ + begin dup while + dup recurse + >dn.peer @ + repeat + drop + ; + +: show-all-devs ( -- ) + active-package + cr " /" find-device + ?active-package show-sub-devs + active-package! + ; + + +: show-devs ( "{device-specifier}" -- ) + active-package + cr " /" find-device + linefeed parse find-device + ?active-package show-sub-devs + active-package! + ; + + + +\ 7.4.11.3 Device probing + +: probe-all ( -- ) + ; diff --git a/forth/admin/help.fs b/forth/admin/help.fs new file mode 100644 index 0000000..e6e624b --- /dev/null +++ b/forth/admin/help.fs @@ -0,0 +1,51 @@ +\ tag: firmware help +\ +\ this code implements IEEE 1275-1994 ch. 7.4.1 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +hex + +: (help-generic) + ." Enter 'help command-name' or 'help category-name' for more help" cr + ." (Use ONLY the first word of a category description)" cr + ." Examples: help select -or- help line" cr cr + ." Categories:" cr + ." boot (Load and execute a client program)" cr + ." diag (Diagnostic routines)" cr + ; + +: (help-diag) + ." test Run the selftest method for specified device" cr + ." test-all Execute test for all devices using selftest method" cr + ; + +: (help-boot) + ." boot [:] [boot-arguments]" cr + ." Examples:" cr + ." boot Default boot (values specified in nvram variables)" cr + ." boot disk1:a Boot from disk1 partition a" cr + ." boot hd:1,\boot\vmlinuz root=/dev/hda1" cr + ; + +: help ( "{name}" -- ) + \ Provide information for category or specific command. + linefeed parse cr + dup 0= if + (help-generic) + 2drop + else + 2dup " diag" rot min comp not if + (help-diag) 2drop exit + then + 2dup " boot" rot min comp not if + (help-boot) 2drop exit + then + ." No help available for " type cr + then + ; + diff --git a/forth/admin/iocontrol.fs b/forth/admin/iocontrol.fs new file mode 100644 index 0000000..71558aa --- /dev/null +++ b/forth/admin/iocontrol.fs @@ -0,0 +1,139 @@ +\ tag: stdin/stdout handling +\ +\ Copyright (C) 2003 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ 7.4.5 I/O control + +variable stdout +variable stdin + +: input ( dev-str dev-len -- ) + 2dup find-dev 0= if + ." Input device " type ." not found." cr exit + then + + " read" rot find-method 0= if + type ." has no read method." cr exit + then + drop + + \ open stdin device + 2dup open-dev ?dup 0= if + ." Opening " type ." failed." cr exit + then + -rot 2drop + + \ call install-abort if present + dup " install-abort" rot ['] $call-method catch if 3drop then + + \ close old stdin + stdin @ ?dup if + dup " remove-abort" rot ['] $call-method catch if 3drop then + close-dev + then + stdin ! +; + +: output ( dev-str dev-len -- ) + 2dup find-dev 0= if + ." Output device " type ." not found." cr exit + then + + " write" rot find-method 0= if + type ." has no write method." cr exit + then + drop + + \ open stdin device + 2dup open-dev ?dup 0= if + ." Opening " type ." failed." cr exit + then + -rot 2drop + + \ close old stdout + stdout @ ?dup if close-dev then + stdout ! +; + +: io ( dev-str dev-len -- ) + 2dup input output +; + +\ key?, key and emit implementation +variable io-char +variable io-out-char + +: io-key? ( -- available? ) + io-char @ -1 <> if true exit then + io-char 1 " read" stdin @ $call-method + 1 = +; + +: io-key ( -- key ) + \ poll for key + begin io-key? until + io-char c@ -1 to io-char +; + +: io-emit ( char -- ) + io-out-char c! + io-out-char 1 " write" stdout @ $call-method drop +; + +variable CONSOLE-IN-list +variable CONSOLE-OUT-list + +: CONSOLE-IN-initializer ( xt -- ) + CONSOLE-IN-list list-add , +; +: CONSOLE-OUT-initializer ( xt -- ) + CONSOLE-OUT-list list-add , +; + +: install-console ( -- ) + + \ create screen alias + " /aliases" find-package if + >r + " screen" find-package if drop else + \ bad (or missing) screen alias + 0 " display" iterate-device-type ?dup if + ( display-ph R: alias-ph ) + get-package-path encode-string " screen" r@ (property) + then + then + r> drop + then + + output-device output + input-device input + + \ let arch determine a useful output device + CONSOLE-OUT-list begin list-get while + stdout @ if drop else @ execute then + repeat + + \ let arch determine a useful input device + CONSOLE-IN-list begin list-get while + stdin @ if drop else @ execute then + repeat + + \ activate console + stdout @ if + ['] io-emit to emit + then + + stdin @ if + -1 to io-char + ['] io-key? to key? + ['] io-key to key + then +; + +:noname + " screen" output +; CONSOLE-OUT-initializer diff --git a/forth/admin/nvram.fs b/forth/admin/nvram.fs new file mode 100644 index 0000000..3b7d3f7 --- /dev/null +++ b/forth/admin/nvram.fs @@ -0,0 +1,354 @@ +\ tag: nvram config handling +\ +\ this code implements IEEE 1275-1994 +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +struct ( config ) + 2 cells field >cf.name + 2 cells field >cf.default \ 0 -1 if no default + /n field >cf.check-xt + /n field >cf.exec-xt + /n field >cf.next +constant config-info.size + +0 value config-root + +\ -------------------------------------------------------- +\ config handling +\ -------------------------------------------------------- + +: find-config ( name-str len -- 0|configptr ) + config-root + begin ?dup while + -rot + 2dup 4 pick >cf.name 2@ + strcmp 0= if + 2drop exit + then + rot >cf.next @ + repeat + 2drop 0 +; + +: is-config-word ( configp -- ) + dup >cf.name 2@ $create , + does> @ + dup >cf.name 2@ + " /options" find-dev if + get-package-property if 0 -1 then + ( configp prop-str prop-len ) + \ drop trailing zero + ?dup if 1- then + else + 2drop 0 -1 + then + \ use default value if property is missing + dup 0< if 2drop dup >cf.default 2@ then + \ no default value, use empty string + dup 0< if 2drop 0 0 then + + rot >cf.exec-xt @ execute +; + +: new-config ( name-str name-len -- configp ) + 2dup find-config ?dup if + nip nip + 0 0 2 pick >cf.default 2! + else + dict-strdup + here config-info.size allot + dup config-info.size 0 fill + config-root over >cf.next ! + dup to config-root + dup >r >cf.name 2! r> + dup is-config-word + then + ( configp ) +; + +: config-default ( str len configp -- ) + -rot + dup 0> if dict-strdup then + rot >cf.default 2! +; + +: no-conf-def ( configp -- ) + 0 -1 +; + +\ -------------------------------------------------------- +\ config types +\ -------------------------------------------------------- + +: exec-str-conf ( str len -- str len ) + \ trivial +; +: check-str-conf ( str len -- str len valid? ) + \ nothing + true +; + +: str-config ( def-str len name len -- configp ) + new-config >r + ['] exec-str-conf r@ >cf.exec-xt ! + ['] check-str-conf r@ >cf.check-xt ! + r> config-default +; + +\ ------------------------------------------------------------ + +: exec-int-conf ( str len -- value ) + \ fixme + parse-hex +; +: check-int-conf ( str len -- str len valid? ) + true +; + +: int-config ( def-str len name len -- configp ) + new-config >r + ['] exec-int-conf r@ >cf.exec-xt ! + ['] check-int-conf r@ >cf.check-xt ! + r> config-default +; + +\ ------------------------------------------------------------ + +: exec-secmode-conf ( str len -- n ) + 2dup " command" strcmp 0= if 2drop 1 exit then + 2dup " full" strcmp 0= if 2drop 2 exit then + 2drop 0 +; +: check-secmode-conf ( str len -- str len valid? ) + 2dup " none" strcmp 0= if true exit then + 2dup " command" strcmp 0= if true exit then + 2dup " full" strcmp 0= if true exit then + false +; + +: secmode-config ( def-str len name len -- configp ) + new-config >r + ['] exec-secmode-conf r@ >cf.exec-xt ! + ['] check-secmode-conf r@ >cf.check-xt ! + r> config-default +; + +\ ------------------------------------------------------------ + +: exec-bool-conf ( str len -- value ) + 2dup " true" strcmp 0= if 2drop true exit then + 2dup " false" strcmp 0= if 2drop false exit then + 2dup " TRUE" strcmp 0= if 2drop false exit then + 2dup " FALSE" strcmp 0= if 2drop false exit then + parse-hex 0<> +; + +: check-bool-conf ( name len -- str len valid? ) + 2dup " true" strcmp 0= if true exit then + 2dup " false" strcmp 0= if true exit then + 2dup " TRUE" strcmp 0= if 2drop " true" true exit then + 2dup " FALSE" strcmp 0= if 2drop " false" true exit then + false +; + +: bool-config ( configp -- configp ) + new-config >r + ['] exec-bool-conf r@ >cf.exec-xt ! + ['] check-bool-conf r@ >cf.check-xt ! + r> config-default +; + + +\ -------------------------------------------------------- +\ 7.4.4 Nonvolatile memory +\ -------------------------------------------------------- + +: $setenv ( data-addr data-len name-str name-len -- ) + 2dup find-config ?dup if + >r 2swap r> + ( name len data len configptr ) + >cf.check-xt @ execute + 0= abort" Invalid value." + 2swap + else + \ create string config type + 2dup no-conf-def 2swap str-config + then + + 2swap encode-string 2swap + " /options" find-package drop + encode-property +; + +: setenv ( "nv-param< >new-value" -- ) + parse-word + \ XXX drop blanks + dup if linefeed parse else 0 0 then + + dup 0= abort" Invalid value." + 2swap $setenv +; + +: printenv ( "{param-name}" -- ) + \ XXX temporary implementation + linefeed parse 2drop + + active-package + " /options" find-device + .properties + active-package! +; + +: (set-default) ( configptr -- ) + dup >cf.default 2@ dup 0>= if + rot >cf.name 2@ $setenv + else + \ no default value + 3drop + then +; + +: set-default ( "param-name" -- ) + linefeed parse + find-config ?dup if + (set-default) + else + ." No such parameter." -2 throw + then +; + +: set-defaults ( -- ) + config-root + begin ?dup while + dup (set-default) + >cf.next @ + repeat +; + +( maxlen "new-name< >" -- ) ( E: -- addr len ) +: nodefault-bytes + ; + + +\ -------------------------------------------------------- +\ initialize config from nvram +\ -------------------------------------------------------- + +\ CHRP format (array of null-terminated strings, "variable=value") +: nvram-load-configs ( data len -- ) + \ XXX: no len checking performed... + drop + begin dup c@ while + ( data ) + dup cstrlen 2dup + 1+ -rot + ( next str len ) + ascii = left-split ( next val len name str ) + ['] $setenv catch if + 2drop 2drop + then + repeat drop +; + +: (nvram-store-one) ( buf len str len -- buf len success? ) + swap >r + 2dup < if r> 2drop 2drop false exit then + ( buf len strlen R: str ) + swap over - r> swap >r -rot + ( str buf strlen R: res_len ) + 2dup + >r move r> r> true +; + +: (make-configstr) ( configptr ph -- str len ) + >r + >cf.name 2@ + 2dup r> get-package-property if + 2drop 0 0 exit + else + dup if 1- then + then + ( name len value-str len ) + 2swap " =" 2swap + pocket tmpstrcat tmpstrcat drop + 2dup + 0 swap c! + 1+ +; + +: nvram-store-configs ( data len -- ) + 2 - \ make room for two trailing zeros + + " /options" find-dev 0= if 2drop exit then + >r + config-root + ( data len configptr R: phandle ) + begin ?dup while + r@ over >r (make-configstr) + ( buf len val len R: configptr phandle ) + (nvram-store-one) drop + r> >cf.next @ + repeat + \ null terminate + 2 + 0 fill + r> drop +; + + +\ -------------------------------------------------------- +\ NVRAM variables +\ -------------------------------------------------------- +\ fcode-debug? input-device output-device +" true" " auto-boot?" bool-config \ 7.4.3.5 +" boot" " boot-command" str-config \ 7.4.3.5 +" disk" " boot-device" str-config \ 7.4.3.5 +" " " boot-file" str-config \ 7.4.3.5 +" false" " diag-switch?" bool-config \ 7.4.3.5 +" net" " diag-device" str-config \ 7.4.3.5 +" diag" " diag-file" str-config \ 7.4.3.5 +" false" " fcode-debug?" bool-config \ 7.7 +" " " nvramrc" str-config \ 7.4.4.2 +" false" " oem-banner?" bool-config +" " " oem-banner" str-config +" false" " oem-logo?" bool-config +no-conf-def " oem-logo" str-config +" false" " use-nvramrc?" bool-config \ 7.4.4.2 +" keyboard" " input-device" str-config \ 7.4.5 +" screen" " output-device" str-config \ 7.4.5 +" 80" " screen-#columns" int-config \ 7.4.5 +" 24" " screen-#rows" int-config \ 7.4.5 +" 0" " selftest-#megs" int-config +no-conf-def " security-mode" secmode-config + +\ --- devices --- +" -1" " pci-probe-mask" int-config +" false" " default-mac-address" bool-config +" false" " skip-netboot?" bool-config +" true" " scroll-lock" bool-config + +[IFDEF] CONFIG_PPC +\ ---- PPC ---- +" false" " little-endian?" bool-config +" false" " real-mode?" bool-config +" -1" " real-base" int-config +" -1" " real-size" int-config +" 0x800000" " load-base" int-config +" -1" " virt-base" int-config +" -1" " virt-size" int-config +[THEN] + +[IFDEF] CONFIG_X86 +\ ---- X86 ---- +" true" " little-endian?" bool-config +[THEN] + +\ --- ??? --- +" " " boot-screen" str-config +" " " boot-script" str-config +" false" " use-generic?" bool-config +" " " boot-args" str-config \ ??? + +\ defers +['] fcode-debug? to _fcode-debug? diff --git a/forth/admin/reset.fs b/forth/admin/reset.fs new file mode 100644 index 0000000..a20fb62 --- /dev/null +++ b/forth/admin/reset.fs @@ -0,0 +1,5 @@ +\ 7.4.7 Reset + +: reset-all ( -- ) + ; + diff --git a/forth/admin/script.fs b/forth/admin/script.fs new file mode 100644 index 0000000..3c60901 --- /dev/null +++ b/forth/admin/script.fs @@ -0,0 +1,17 @@ +\ 7.4.4.2 The script + +: nvedit ( -- ) + ; + +: nvstore ( -- ) + ; + +: nvquit ( -- ) + ; + +: nvrecover ( -- ) + ; + +: nvrun ( -- ) + ; + diff --git a/forth/admin/security.fs b/forth/admin/security.fs new file mode 100644 index 0000000..9ccf96e --- /dev/null +++ b/forth/admin/security.fs @@ -0,0 +1,11 @@ +\ 7.4.6 Security + +: password ( -- ) + ; + +: security-password ( -- password-str password-len ) + ; + +: security-#badlogins ( -- n ) + ; + diff --git a/forth/admin/selftest.fs b/forth/admin/selftest.fs new file mode 100644 index 0000000..0ee0cd1 --- /dev/null +++ b/forth/admin/selftest.fs @@ -0,0 +1,50 @@ +\ tag: self-test +\ +\ this code implements IEEE 1275-1994 ch. 7.4.8 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ +\ 7.4.8 Self-test +\ + +: $test ( devname-addr devname-len -- ) + 2dup ." Testing device " type ." : " + find-dev if + s" self-test" rot find-method if + execute + else + ." no self-test method." + then + else + ." no such device." + then + cr +; + +: test ( "device-specifier"-- ) + linefeed parse cr $test + ; + +: test-sub-devs + >dn.child @ + begin dup while + dup get-package-path $test + dup recurse + >dn.peer @ + repeat + drop +; + +: test-all ( "{device-specifier}" -- ) + active-package + cr " /" find-device + linefeed parse find-device + ?active-package test-sub-devs + active-package! + ; + diff --git a/forth/admin/userboot.fs b/forth/admin/userboot.fs new file mode 100644 index 0000000..e648cab --- /dev/null +++ b/forth/admin/userboot.fs @@ -0,0 +1,20 @@ +\ 7.4.3.5 User commands for booting + +: boot ( "{param-text}" -- ) + linefeed parse cr + s" platform-boot" $find if + execute + else + 2drop + cr ." Booting " type cr + ." ... not supported on this system." cr + then +; + +\ : diagnostic-mode? ( -- diag? ) +\ ; + +\ : diag-switch? ( -- diag? ) +\ ; + + diff --git a/forth/bootstrap/bootstrap.fs b/forth/bootstrap/bootstrap.fs new file mode 100644 index 0000000..096e5c9 --- /dev/null +++ b/forth/bootstrap/bootstrap.fs @@ -0,0 +1,1500 @@ +\ tag: bootstrap of basic forth words +\ +\ Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ +\ this file contains almost all forth words described +\ by the open firmware user interface. Some more complex +\ parts are found in seperate files (memory management, +\ vocabulary support) +\ + +\ +\ often used constants (reduces dictionary size) +\ + +1 constant 1 +2 constant 2 +3 constant 3 +-1 constant -1 +0 constant 0 + +0 value my-self + +\ +\ 7.3.5.1 Numeric-base control +\ + +: decimal 10 base ! ; +: hex 16 base ! ; +: octal 8 base ! ; +hex + +\ +\ vocabulary words +\ + +variable current forth-last current ! + +: last + current @ + ; + +variable #order 0 #order ! + +defer context +0 value vocabularies? + +\ +\ 7.3.7 Flag constants +\ + +1 1 = constant true +0 1 = constant false + +\ +\ 7.3.9.2.2 Immediate words (part 1) +\ + +: (immediate) ( xt -- ) + 1 - dup c@ 1 or swap c! + ; + +: (compile-only) + 1 - dup c@ 2 or swap c! + ; + +: immediate + last @ (immediate) + ; + +: compile-only + last @ (compile-only) + ; + +: flags? ( xt -- flags ) + /n /c + - c@ 7f and + ; + +: immediate? ( xt -- true|false ) + flags? 1 and 1 = + ; + +: compile-only? ( xt -- true|false ) + flags? 2 and 2 = + ; + +: [ 0 state ! ; compile-only +: ] -1 state ! ; + + + +\ +\ 7.3.9.2.1 Data space allocation +\ + +: allot here + here! ; +: , here /n allot ! ; +: c, here /c allot c! ; + +: align + /n here /n 1 - and - \ how many bytes to next alignment + /n 1 - and allot \ mask out everything that is bigger + ; \ than cellsize-1 + +: null-align + here dup align here swap - 0 fill + ; + +: w, + here 1 and allot \ if here is not even, we have to align. + here /w allot w! + ; + +: l, + /l here /l 1 - and - \ same as in align, with /l + /l 1 - and \ if it's /l we are already aligned. + allot + here /l allot l! + ; + + +\ +\ 7.3.6 comparison operators (part 1) +\ + +: <> = invert ; + + +\ +\ 7.3.9.2.4 Miscellaneous dictionary (part 1) +\ + +: (to) ( xt-new xt-defer -- ) + /n + ! + ; + +: >body ( xt -- a-addr ) /n 1 lshift + ; +: body> ( a-addr -- xt ) /n 1 lshift - ; + +: reveal latest @ last ! ; +: recursive reveal ; immediate +: recurse latest @ /n + , ; immediate + +: noop ; + +defer environment? +: no-environment? + 2drop false + ; + +['] no-environment? ['] environment? (to) + + +\ +\ 7.3.8.1 Conditional branches +\ + +: resolve-orig here over /n + - swap ! ; +: (if) ['] do?branch , here 0 , ; compile-only +: (then) resolve-orig ; compile-only + +variable tmp-comp-depth -1 tmp-comp-depth ! +variable tmp-comp-buf 0 tmp-comp-buf ! + +: setup-tmp-comp ( -- ) + state @ 0 = (if) + here tmp-comp-buf @ here! , \ save here and switch to tmp directory + 1 , \ DOCOL + depth tmp-comp-depth ! \ save control depth + ] + (then) +; + +: execute-tmp-comp ( -- ) + depth tmp-comp-depth @ = + (if) + -1 tmp-comp-depth ! + ['] (semis) , + tmp-comp-buf @ + dup @ here! + 0 state ! + /n + execute + (then) +; + +: if setup-tmp-comp ['] do?branch , here 0 , ; immediate +: then resolve-orig execute-tmp-comp ; compile-only +: else ['] dobranch , here 0 , swap resolve-orig ; compile-only + +\ +\ 7.3.8.3 Conditional loops +\ + +\ some dummy words for see +: (begin) ; +: (again) ; +: (until) ; +: (while) ; +: (repeat) ; + +: resolve-dest here /n + - , ; + +: begin + setup-tmp-comp + ['] (begin) , + here + ; immediate + +: again + ['] (again) , + ['] dobranch , + resolve-dest + execute-tmp-comp + ; compile-only + +: until + ['] (until) , + ['] do?branch , + resolve-dest + execute-tmp-comp + ; compile-only + +: while + setup-tmp-comp + ['] (while) , + ['] do?branch , + here 0 , swap + ; immediate + +: repeat + ['] (repeat) , + ['] dobranch , + resolve-dest resolve-orig + execute-tmp-comp + ; compile-only + +\ +\ 7.3.8.4 Counted loops +\ + +variable leaves 0 leaves ! + +: resolve-loop + leaves @ + begin + ?dup + while + dup @ \ leaves -- leaves *leaves ) + swap \ -- *leaves leaves ) + here over - \ -- *leaves leaves here-leaves + swap ! \ -- *leaves + repeat + here - , + leaves ! + ; + +: do + setup-tmp-comp + leaves @ here + ['] (do) , + 0 leaves ! + ; immediate + +: ?do + setup-tmp-comp + leaves @ + ['] (?do) , + here + here leaves ! + 0 , + ; immediate + +: loop + ['] (loop) , + resolve-loop + execute-tmp-comp + ; compile-only + +: +loop + ['] (+loop) , + resolve-loop + execute-tmp-comp + ; compile-only + +\ Using primitive versions of i and j +\ speeds up loops by 300% +\ : i r> r@ swap >r ; +\ : j r> r> r> r@ -rot >r >r swap >r ; + +: unloop r> r> r> 2drop >r ; + +: leave + ['] unloop , + ['] dobranch , + leaves @ + here leaves ! + , + ; compile-only + +: ?leave if leave then ; + +\ +\ 7.3.8.2 Case statement +\ + +: case + setup-tmp-comp + 0 +; immediate + +: endcase + ['] drop , + 0 ?do + ['] then execute + loop + execute-tmp-comp +; compile-only + +: of + 1 + >r + ['] over , + ['] = , + ['] if execute + ['] drop , + r> + ; compile-only + +: endof + >r + ['] else execute + r> + ; compile-only + + +\ +\ 7.3.8.5 Other control flow commands +\ + +: exit r> drop ; + + +\ +\ 7.3.4.3 ASCII constants (part 1) +\ + +20 constant bl +07 constant bell +08 constant bs +0d constant carret +0a constant linefeed + + +\ +\ 7.3.1.1 - stack duplication +\ +: tuck swap over ; +: 3dup 2 pick 2 pick 2 pick ; + +\ +\ 7.3.1.2 - stack removal +\ +: clear 0 depth! ; +: 3drop 2drop drop ; + +\ +\ 7.3.1.3 - stack rearrangement +\ + +: 2rot >r >r 2swap r> r> 2swap ; + +\ +\ 7.3.2.1 - single precision integer arithmetic (part 1) +\ + +: u/mod 0 swap mu/mod drop ; +: 1+ 1 + ; +: 1- 1 - ; +: 2+ 2 + ; +: 2- 2 - ; +: even 1+ -2 and ; +: bounds over + swap ; + +\ +\ 7.3.2.2 bitwise logical operators +\ +: << lshift ; +: >> rshift ; +: 2* 1 lshift ; +: u2/ 1 rshift ; +: 2/ 1 >>a ; +: not invert ; + +\ +\ 7.3.2.3 double number arithmetic +\ + +: s>d dup 0 < ; +: dnegate 0 0 2swap d- ; +: dabs dup 0 < if dnegate then ; +: um/mod mu/mod drop ; + +\ symmetric division +: sm/rem ( d n -- rem quot ) + over >r >r dabs r@ abs um/mod r> 0 < + if + negate + then + r> 0 < if + negate swap negate swap + then + ; + +\ floored division +: fm/mod ( d n -- rem quot ) + dup >r 2dup xor 0 < >r sm/rem over 0 <> r> and if + 1 - swap r> + swap exit + then + r> drop + ; + +\ +\ 7.3.2.1 - single precision integer arithmetic (part 2) +\ + +: */mod ( n1 n2 n3 -- quot rem ) >r m* r> fm/mod ; +: */ ( n1 n2 n3 -- n1*n2/n3 ) */mod nip ; +: /mod >r s>d r> fm/mod ; +: mod /mod drop ; +: / /mod nip ; + + +\ +\ 7.3.2.4 Data type conversion +\ + +: lwsplit ( quad -- w.lo w.hi ) + dup ffff and swap 10 rshift ffff and +; + +: wbsplit ( word -- b.lo b.hi ) + dup ff and swap 8 rshift ff and +; + +: lbsplit ( quad -- b.lo b2 b3 b.hi ) + lwsplit swap wbsplit rot wbsplit +; + +: bwjoin ( b.lo b.hi -- word ) + ff and 8 lshift swap ff and or +; + +: wljoin ( w.lo w.hi -- quad ) + ffff and 10 lshift swap ffff and or +; + +: bljoin ( b.lo b2 b3 b.hi -- quad ) + bwjoin -rot bwjoin swap wljoin +; + +: wbflip ( word -- word ) \ flips bytes in a word + dup 8 rshift ff and swap ff and bwjoin +; + +: lwflip ( q1 -- q2 ) + dup 10 rshift ffff and swap ffff and wljoin +; + +: lbflip ( q1 -- q2 ) + dup 10 rshift ffff and wbflip swap ffff and wbflip wljoin +; + +\ +\ 7.3.2.5 address arithmetic +\ + +: /c* /c * ; +: /w* /w * ; +: /l* /l * ; +: /n* /n * ; +: ca+ /c* + ; +: wa+ /w* + ; +: la+ /l* + ; +: na+ /n* + ; +: ca1+ /c + ; +: wa1+ /w + ; +: la1+ /l + ; +: na1+ /n + ; +: aligned /n 1- + /n negate and ; +: char+ ca1+ ; +: cell+ na1+ ; +: chars /c* ; +: cells /n* ; +/n constant cell + +\ +\ 7.3.6 Comparison operators +\ + +: <= > not ; +: >= < not ; +: 0= 0 = ; +: 0<= 0 <= ; +: 0< 0 < ; +: 0<> 0 <> ; +: 0> 0 > ; +: 0>= 0 >= ; +: u<= u> not ; +: u>= u< not ; +: within >r over > swap r> >= or not ; +: between 1 + within ; + +\ +\ 7.3.3.1 Memory access +\ + +: 2@ dup cell+ @ swap @ ; +: 2! dup >r ! r> cell+ ! ; + +: = if 10000 - then ; + +: comp ( str1 str2 len -- 0|1|-1 ) + >r 0 -rot r> + bounds ?do + dup c@ i c@ - dup if + < if 1 else -1 then swap leave + then + drop ca1+ + loop + drop +; + +\ : +! tuck @ + swap ! ; +: off false swap ! ; +: on true swap ! ; +: blank bl fill ; +: erase 0 fill ; +: wbflips ( waddr len -- ) + bounds do i w@ wbflip i w! /w +loop +; + +: lwflips ( qaddr len -- ) + bounds do i l@ lwflip i l! /l +loop +; + +: lbflips ( qaddr len -- ) + bounds do i l@ lbflip i l! /l +loop +; + + +\ +\ 7.3.8.6 Error handling (part 1) +\ + +variable catchframe +0 catchframe ! + +: catch + my-self >r + depth >r + catchframe @ >r + rdepth catchframe ! + execute + r> catchframe ! + r> r> 2drop 0 + ; + +: throw + ?dup if + catchframe @ rdepth! + r> catchframe ! + r> swap >r depth! + drop r> + r> ['] my-self (to) + then + ; + +\ +\ 7.3.3.2 memory allocation +\ + +include memory.fs + + +\ +\ 7.3.4.4 Console output (part 1) +\ + +defer emit + +: type bounds ?do i c@ emit loop ; + +\ this one obviously only works when called +\ with a forth string as count fetches addr-1. +\ openfirmware has no such req. therefore it has to go: + +\ : type 0 do count emit loop drop ; + + +\ +\ 7.3.4.1 Text Input +\ + +0 value source-id +0 value ib +variable #ib 0 #ib ! +variable >in 0 >in ! + +: source ( -- addr len ) + ib #ib @ + ; + +: /string ( c-addr1 u1 n -- c-addr2 u2 ) + tuck - -rot + swap +; + + +\ +\ pockets implementation for 7.3.4.1 + +100 constant pocketsize +variable pockets 0 pockets ! +variable whichpocket 0 whichpocket ! + +\ allocate 2 pockets to begin with +: init-pockets ( -- ) + pocketsize 2* alloc-mem pockets ! + ; + +: pocket ( ?? -- ?? ) + pocketsize whichpocket @ * + pockets @ + + 1 whichpocket @ - + whichpocket ! + ; + +\ span variable from 7.3.4.2 +variable span 0 span ! + +\ if char is bl then any control character is matched +: findchar ( str len char -- offs true | false ) + swap 0 do + over i + c@ + over dup bl = if <= else = then if + 2drop i dup dup leave + \ i nip nip true exit \ replaces above + then + loop + = + \ drop drop false + ; + +: parse ( delim text -- str len ) + >r \ save delimiter + ib >in @ + + span @ >in @ - \ ib+offs len-offset. + 2dup r> \ ib+offs len-offset ib+offs len-offset delim + findchar if \ look for the delimiter. + nip dup 1+ + else + dup + then + >in +! + \ dup -1 = if drop 0 then \ workaround for negative length + ; + +: skipws ( -- ) + ib span @ ( -- ib recvchars ) + begin + dup >in @ > if ( -- recvchars>offs ) + over >in @ + + c@ bl <= + else + false + then + while + 1 >in +! + repeat + 2drop + ; + +: parse-word ( < >text< > -- str len ) + skipws bl parse + ; + +: word ( delim text -- pstr ) + pocket >r parse dup r@ c! bounds r> dup 2swap + do + char+ i c@ over c! + loop + drop + ; + +: ( 29 parse 2drop ; immediate +: \ span @ >in ! ; immediate + + + +\ +\ 7.3.4.7 String literals +\ + +: ", + bounds ?do + i c@ c, + loop + ; + +: (") ( -- addr len ) + r> dup + 2 cells + ( r-addr addr ) + over cell+ @ ( r-addr addr len ) + rot over + aligned cell+ >r ( addr len R: r-addr ) + ; + +: handle-text ( temp-addr len -- addr len ) + state @ if + ['] (") , dup , ", null-align + else + pocket swap + dup >r + 0 ?do + over i + c@ over i + c! + loop + nip r> + then + ; + +: s" + 22 parse handle-text + ; immediate + + + +\ +\ 7.3.4.4 Console output (part 2) +\ + +: ." + 22 parse handle-text + ['] type + state @ if + , + else + execute + then + ; immediate + +: .( + 29 parse handle-text + ['] type + state @ if + , + else + execute + then + ; immediate + + + +\ +\ 7.3.4.8 String manipulation +\ + +: count ( pstr -- str len ) 1+ dup 1- c@ ; + +: pack ( str len addr -- pstr ) + 2dup c! \ store len + 1+ swap 0 ?do + over i + c@ over i + c! + loop nip 1- + ; + +: lcc ( char1 -- char2 ) dup 41 5a between if 20 + then ; +: upc ( char1 -- char2 ) dup 61 7a between if 20 - then ; + +: -trailing ( str len1 -- str len2 ) + begin + dup 0<> if \ len != 0 ? + 2dup 1- + + c@ bl = + else + false + then + while + 1- + repeat + ; + + +\ +\ 7.3.4.5 Output formatting +\ + +: cr linefeed emit ; +: (cr carret emit ; +: space bl emit ; +: spaces 0 ?do space loop ; +variable #line 0 #line ! +variable #out 0 #out ! + + +\ +\ 7.3.9.2.3 Dictionary search +\ + +\ helper functions + +: lfa2name ( lfa -- name len ) + 1- \ skip flag byte + begin \ skip 0 padding + 1- dup c@ ?dup + until + 7f and \ clear high bit in length + + tuck - swap ( ptr-to-len len - name len ) + ; + +: comp-nocase ( str1 str2 len -- true|false ) + 0 do + 2dup i + c@ upc ( str1 str2 byteX ) + swap i + c@ upc ( str1 str2 byte1 byte2 ) + <> if + 0 leave + then + loop + if -1 else drop 0 then + swap drop + ; + +: comp-word ( b-str len lfa -- true | false ) + lfa2name ( str len str len -- ) + >r swap r> ( str str len len ) + over = if ( str str len ) + comp-nocase + else + drop drop drop false \ if len does not match, string does not match + then +; + +\ $find is an fcode word, but we place it here since we use it for find. + +: find-wordlist ( name-str name-len last -- xt true | name-str name-len false ) + + @ >r + + begin + 2dup r@ dup if comp-word dup false = then + while + r> @ >r drop + repeat + + r@ if \ successful? + -rot 2drop r> cell+ swap + else + r> drop drop drop false + then + + ; + +: $find ( name-str name-len -- xt true | name-str name-len false ) + vocabularies? if + #order @ 0 ?do + i cells context + @ + find-wordlist + ?dup if + unloop exit + then + loop + false + else + forth-last find-wordlist + then + ; + +\ look up a word in the current wordlist +: $find1 ( name-str name-len -- xt true | name-str name-len false ) + vocabularies? if + current @ + else + forth-last + then + find-wordlist + ; + + +: ' + parse-word $find 0= if + type 3a emit -13 throw + then + ; + +: ['] + parse-word $find 0= if + type 3a emit -13 throw + then + state @ if + ['] (lit) , , + then + ; immediate + +: find ( pstr -- xt n | pstr false ) + dup count $find \ pstr xt true | pstr name-str name-len false + if + nip true + over immediate? if + negate \ immediate returns 1 + then + else + 2drop false + then + ; + + +\ +\ 7.3.9.2.2 Immediate words (part 2) +\ + +: literal ['] (lit) , , ; immediate +: compile, , ; immediate +: compile r> cell+ dup @ , >r ; +: [compile] ['] ' execute , ; immediate + +: postpone + parse-word $find if + dup immediate? not if + ['] (lit) , , ['] , + then + , + else + s" undefined word " type type cr + then + ; immediate + + +\ +\ 7.3.9.2.4 Miscellaneous dictionary (part 2) +\ + +variable #instance + +: instance ( -- ) + true #instance ! +; + +: #instance-base + my-self dup if @ then +; + +: #instance-offs + my-self dup if na1+ then +; + +\ the following instance words are used internally +\ to implement variable instantiation. + +: instance-cfa? ( cfa -- true | false ) + b e within \ b,c and d are instance defining words +; + +: behavior ( xt-defer -- xt ) + dup @ instance-cfa? if + #instance-base ?dup if + swap na1+ @ + @ + else + 3 /n* + @ + then + else + na1+ @ + then +; + +: (ito) ( xt-new xt-defer -- ) + #instance-base ?dup if + swap na1+ @ + ! + else + 3 /n* + ! + then +; + +: to + ['] ' execute + dup @ instance-cfa? + state @ if + swap ['] (lit) , , if ['] (ito) else ['] (to) then , + else + if (ito) else /n + ! then + then + ; immediate + + +\ +\ 7.3.4.2 Console Input +\ + +defer key? +defer key + +: accept ( addr len -- len2 ) + tuck 0 do + key + dup linefeed = if + space drop drop drop i 0 leave + then + dup emit over c! 1 + + loop + drop ( cr ) + ; + +: expect ( addr len -- ) + accept span ! + ; + + +\ +\ 7.3.4.3 ASCII constants (part 2) +\ + +: handle-lit + state @ if + 2 = if + ['] (lit) , , + then + ['] (lit) , , + else + drop + then + ; + +: char + parse-word 0<> if c@ else s" Unexpected EOL." type cr then ; + ; + +: ascii char 1 handle-lit ; immediate +: [char] char 1 handle-lit ; immediate + +: control + char bl 1- and 1 handle-lit +; immediate + + + +\ +\ 7.3.8.6 Error handling (part 2) +\ + +: abort + -1 throw + ; + +: abort" + ['] if execute + 22 parse handle-text + ['] type , + ['] (lit) , + -2 , + ['] throw , + ['] then execute + ; compile-only + +\ +\ 7.5.3.1 Dictionary search +\ + +\ this does not belong here, but its nice for testing + +: words ( -- ) + last + begin @ + ?dup while + dup lfa2name + type space + repeat + cr + ; + +\ +\ 7.3.5.4 Numeric output primitives +\ + +false value capital-hex? + +: pad ( -- addr ) here 100 + ; + +: todigit ( num -- ascii ) + dup 9 > if + capital-hex? not if + 20 + + then + 7 + + then + 30 + + ; + +: <# pad dup ! ; +: hold pad dup @ 1- tuck swap ! c! ; +: sign + 0< if + 2d hold + then + ; + +: # base @ mu/mod rot todigit hold ; +: #s begin # 2dup or 0= until ; +: #> 2drop pad dup @ tuck - ; +: (.) <# dup >r abs 0 #s r> sign #> ; + +: u# base @ u/mod swap todigit hold ; +: u#s begin u# dup 0= until ; +: u#> 0 #> ; +: (u.) <# u#s u#> ; + +\ +\ 7.3.5.3 Numeric output +\ + +: . (.) type space ; +: s. . ; +: u. (u.) type space ; +: .r swap (.) rot 2dup < if over - spaces else drop then type ; +: u.r swap (u.) rot 2dup < if over - spaces else drop then type ; +: .d base @ swap decimal . base ! ; +: .h base @ swap hex . base ! ; + +: .s + 3c emit depth dup (.) type 3e emit space + 0 + ?do + depth i - 1- pick . + loop + cr + ; + +\ +\ 7.3.5.2 Numeric input +\ + +: digit ( char base -- n true | char false ) + swap dup upc dup + 41 5a ( A - Z ) between if + 7 - + else + dup 39 > if \ protect from : and ; + -rot 2drop false exit + then + then + + 30 ( number 0 ) - rot over swap 0 swap within if + nip true + else + drop false + then + ; + +: >number + begin + dup + while + over c@ base @ digit 0= if + drop exit + then >r 2swap r> swap base @ um* drop rot base @ um* d+ 2swap + 1 /string + repeat + ; + +: numdelim? + dup 2e = swap 2c = or +; + + +: $dnumber? + 0 0 2swap dup 0= if + 2drop 2drop 0 exit + then over c@ 2d = dup >r negate /string begin + >number dup 1 > + while + over c@ numdelim? 0= if + 2drop 2drop r> drop 0 exit + then 1 /string + repeat if + c@ 2e = if + true + else + 2drop r> drop 0 exit + then + else + drop false + then over or if + r> if + dnegate + then 2 + else + drop r> if + negate + then 1 + then +; + + +: $number ( ) + $dnumber? + case + 0 of true endof + 1 of false endof + 2 of drop false endof + endcase +; + +: d# + parse-word + base @ >r + + decimal + + $number if + s" illegal number" type cr 0 + then + r> base ! + 1 handle-lit + ; immediate + +: h# + parse-word + base @ >r + + hex + + $number if + s" illegal number" type cr 0 + then + r> base ! + 1 handle-lit + ; immediate + +: o# + parse-word + base @ >r + + octal + + $number if + s" illegal number" type cr 0 + then + r> base ! + 1 handle-lit + ; immediate + + +\ +\ 7.3.4.7 String Literals (part 2) +\ + +: " + pocket dup + begin + span @ >in @ > if + 22 parse >r ( pocket pocket str R: len ) + over r@ move \ copy string + r> + ( pocket nextdest ) + ib >in @ + c@ ( pocket nextdest nexchar ) + 1 >in +! + 28 = \ is nextchar a parenthesis? + span @ >in @ > \ more input? + and + else + false + then + while + 29 parse \ parse everything up to the next ')' + bounds ?do + i c@ 10 digit if + i 1+ c@ 10 digit if + swap 4 lshift or + else + drop + then + over c! 1+ + 2 + else + drop 1 + then + +loop + repeat + over - + state @ if + ['] (lit) , here 5 cells + , + ['] (lit) , dup , + ['] dobranch , + here -rot + /n allot + ", null-align resolve-orig + then +; immediate + + +\ +\ 7.3.3.1 Memory Access (part 2) +\ + +: dump ( addr len -- ) + over + swap + do i . space + 10 0 do + j i + c@ + dup 10 / todigit emit + 10 mod todigit emit + space + i 7 = if space then + loop + 3 spaces + 10 0 do + j i + c@ + dup 20 < if drop 2e then \ non-printables as dots? + emit + loop + cr + 10 +loop +; + + + +\ +\ 7.3.9.1 Defining words +\ + +: header ( name len -- ) + dup if \ might be a noname... + 2dup $find1 if + drop 2dup type s" isn't unique." type cr + else + 2drop + then + then + null-align + dup -rot ", 80 or c, \ write name and len + here /n 1- and 0= if 0 c, then \ pad and space for flags + null-align + 80 here 1- c! \ write flags byte + here last @ , latest ! \ write backlink and set latest + ; + + +: : + parse-word header + 1 , ] + ; + +: :noname + 0 0 header + here + 1 , ] + ; + +: ; + ['] (semis) , reveal ['] [ execute + ; immediate + +: constant + parse-word header + 3 , , \ compile DOCON and value + reveal + ; + +0 value active-package +: instance, ( size -- ) + \ first word of the device node holds the instance size + dup active-package @ dup rot + active-package ! + , , \ offset size +; + +: instance? ( -- flag ) + #instance @ dup if + false #instance ! + then +; + +: value + parse-word header + instance? if + /n b , instance, , \ DOIVAL + else + 3 , , + then + reveal + ; + +: variable + parse-word header + instance? if + /n c , instance, 0 , + else + 4 , 0 , + then + reveal + ; + +: $buffer: ( size str len -- where ) + header + instance? if + /n over /n 1- and - /n 1- and + \ align buffer size + dup c , instance, \ DOIVAR + else + 4 , + then + here swap + 2dup 0 fill \ zerofill + allot + reveal +; + +: buffer: ( size -- ) + parse-word $buffer: drop +; + +: (undefined-defer) ( -- ) + \ XXX: this does not work with behavior ... execute + r@ 2 cells - lfa2name + s" undefined defer word " type type cr ; + +: (undefined-idefer) ( -- ) + s" undefined idefer word " type cr ; + +: defer ( new-name< > -- ) + parse-word header + instance? if + 2 /n* d , instance, \ DOIDEFER + ['] (undefined-idefer) + else + 5 , + ['] (undefined-defer) + then + , + ['] (semis) , + reveal + ; + +: alias ( new-name< >old-name< > -- ) + parse-word + parse-word $find if + -rot \ move xt behind. + header + 1 , \ fixme we want our own cfa here. + , \ compile old name xt + ['] (semis) , + reveal + else + s" undefined word " type type space + 2drop + then + ; + +: $create + header 6 , + ['] noop , + reveal + ; + +: create + parse-word $create + ; + +: (does>) + r> cell+ \ get address of code to execute + latest @ \ backlink of just "create"d word + cell+ cell+ ! \ write code to execute after the + \ new word's CFA + ; + +: does> + ['] (does>) , \ compile does handling + 1 , \ compile docol + ; immediate + +0 constant struct + +: field + create + over , + + + does> + @ + + ; + +: 2constant + create , , + does> 2@ reveal + ; + +\ +\ initializer for the temporary compile buffer +\ + +: init-tmp-comp + 200 alloc-mem tmp-comp-buf ! +; + +\ the end diff --git a/forth/bootstrap/build.xml b/forth/bootstrap/build.xml new file mode 100644 index 0000000..d950a46 --- /dev/null +++ b/forth/bootstrap/build.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/forth/bootstrap/builtin.fs b/forth/bootstrap/builtin.fs new file mode 100644 index 0000000..f99d8ea --- /dev/null +++ b/forth/bootstrap/builtin.fs @@ -0,0 +1,30 @@ +\ tag: initialize builtin functionality +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + + + +: init-builtin-terminal ( -- ) + + \ define key, key? and emit + ['] (key) ['] key (to) + ['] (key?) ['] key? (to) + ['] (emit) ['] emit (to) + + \ 2 bytes band guard on each side + 100 #ib ! + #ib @ dup ( -- ibs ibs ) + cell+ alloc-mem ( -- ibs addr ) + dup -rot ( -- addr ibs addr ) + + /w + ['] ib (to) \ assign input buffer + 0 fill \ erase tib + 0 ['] source-id (to) \ builtin terminal has id 0 + + ; + + diff --git a/forth/bootstrap/hayes.fs b/forth/bootstrap/hayes.fs new file mode 100644 index 0000000..e5a46f4 --- /dev/null +++ b/forth/bootstrap/hayes.fs @@ -0,0 +1,1064 @@ +\ From: John Hayes S1I +\ Subject: tester.fr +\ Date: Mon, 27 Nov 95 13:10:09 PST + +\ (C) 1995 JOHNS HOPKINS UNIVERSITY / APPLIED PHYSICS LABORATORY +\ MAY BE DISTRIBUTED FREELY AS LONG AS THIS COPYRIGHT NOTICE REMAINS. +\ VERSION 1.1 + +HEX + +\ switch output of hex values to capital letters +true to capital-hex? + + +\ SET THE FOLLOWING FLAG TO TRUE FOR MORE VERBOSE OUTPUT; THIS MAY +\ ALLOW YOU TO TELL WHICH TEST CAUSED YOUR SYSTEM TO HANG. + +VARIABLE VERBOSE + FALSE VERBOSE ! + +: EMPTY-STACK \ ( ... -- ) EMPTY STACK: HANDLES UNDERFLOWED STACK TOO. + DEPTH ?DUP IF DUP 0< IF NEGATE 0 DO 0 LOOP ELSE 0 DO DROP LOOP THEN THEN ; + +: ERROR \ ( C-ADDR U -- ) DISPLAY AN ERROR MESSAGE FOLLOWED BY + \ THE LINE THAT HAD THE ERROR. + \ TYPE SOURCE TYPE CR \ DISPLAY LINE CORRESPONDING TO ERROR + + \ FIXME beginagain wants the following for output: + TYPE SOURCE drop span @ TYPE CR \ DISPLAY LINE CORRESPONDING TO ERROR + EMPTY-STACK \ THROW AWAY EVERY THING ELSE + -99 SYS-DEBUG \ MAKE BEGINAGAIN BOOTSTRAP FAIL. +; + +VARIABLE ACTUAL-DEPTH \ STACK RECORD +CREATE ACTUAL-RESULTS 20 CELLS ALLOT + +: { \ ( -- ) SYNTACTIC SUGAR. + ; + +: -> \ ( ... -- ) RECORD DEPTH AND CONTENT OF STACK. + DEPTH DUP ACTUAL-DEPTH ! \ RECORD DEPTH + ?DUP IF \ IF THERE IS SOMETHING ON STACK + 0 DO ACTUAL-RESULTS I CELLS + ! LOOP \ SAVE THEM + THEN ; + +: } \ ( ... -- ) COMPARE STACK (EXPECTED) CONTENTS WITH SAVED + \ (ACTUAL) CONTENTS. + DEPTH ACTUAL-DEPTH @ = IF \ IF DEPTHS MATCH + DEPTH ?DUP IF \ IF THERE IS SOMETHING ON THE STACK + 0 DO \ FOR EACH STACK ITEM + ACTUAL-RESULTS I CELLS + @ \ COMPARE ACTUAL WITH EXPECTED + <> IF S" INCORRECT RESULT: " ERROR LEAVE THEN + LOOP + THEN + ELSE \ DEPTH MISMATCH + S" WRONG NUMBER OF RESULTS: " ERROR + THEN ; + +: TESTING \ ( -- ) TALKING COMMENT. + SOURCE VERBOSE @ + IF DUP >R TYPE CR R> >IN ! + ELSE >IN ! DROP + THEN + ; + +\ From: John Hayes S1I +\ Subject: core.fr +\ Date: Mon, 27 Nov 95 13:10 + +\ (C) 1995 JOHNS HOPKINS UNIVERSITY / APPLIED PHYSICS LABORATORY +\ MAY BE DISTRIBUTED FREELY AS LONG AS THIS COPYRIGHT NOTICE REMAINS. +\ VERSION 1.2 +\ THIS PROGRAM TESTS THE CORE WORDS OF AN ANS FORTH SYSTEM. +\ THE PROGRAM ASSUMES A TWO'S COMPLEMENT IMPLEMENTATION WHERE +\ THE RANGE OF SIGNED NUMBERS IS -2^(N-1) ... 2^(N-1)-1 AND +\ THE RANGE OF UNSIGNED NUMBERS IS 0 ... 2^(N)-1. +\ I HAVEN'T FIGURED OUT HOW TO TEST KEY, QUIT, ABORT, OR ABORT"... +\ I ALSO HAVEN'T THOUGHT OF A WAY TO TEST ENVIRONMENT?... + +TESTING CORE WORDS +HEX + +\ ------------------------------------------------------------------------ +TESTING BASIC ASSUMPTIONS + +{ -> } \ START WITH CLEAN SLATE +( TEST IF ANY BITS ARE SET; ANSWER IN BASE 1 ) +{ : BITSSET? IF 0 0 ELSE 0 THEN ; -> } +{ 0 BITSSET? -> 0 } ( ZERO IS ALL BITS CLEAR ) +{ 1 BITSSET? -> 0 0 } ( OTHER NUMBER HAVE AT LEAST ONE BIT ) +{ -1 BITSSET? -> 0 0 } + +\ ------------------------------------------------------------------------ +TESTING BOOLEANS: INVERT AND OR XOR + +{ 0 0 AND -> 0 } +{ 0 1 AND -> 0 } +{ 1 0 AND -> 0 } +{ 1 1 AND -> 1 } + +{ 0 INVERT 1 AND -> 1 } +{ 1 INVERT 1 AND -> 0 } + +0 CONSTANT 0S +0 INVERT CONSTANT 1S + +{ 0S INVERT -> 1S } +{ 1S INVERT -> 0S } + +{ 0S 0S AND -> 0S } +{ 0S 1S AND -> 0S } +{ 1S 0S AND -> 0S } +{ 1S 1S AND -> 1S } + +{ 0S 0S OR -> 0S } +{ 0S 1S OR -> 1S } +{ 1S 0S OR -> 1S } +{ 1S 1S OR -> 1S } + +{ 0S 0S XOR -> 0S } +{ 0S 1S XOR -> 1S } +{ 1S 0S XOR -> 1S } +{ 1S 1S XOR -> 0S } + +\ ------------------------------------------------------------------------ +TESTING 2* 2/ LSHIFT RSHIFT + +( WE TRUST 1S, INVERT, AND BITSSET?; WE WILL CONFIRM RSHIFT LATER ) +1S 1 RSHIFT INVERT CONSTANT MSB +{ MSB BITSSET? -> 0 0 } + +{ 0S 2* -> 0S } +{ 1 2* -> 2 } +{ 4000 2* -> 8000 } +{ 1S 2* 1 XOR -> 1S } +{ MSB 2* -> 0S } + +{ 0S 2/ -> 0S } +{ 1 2/ -> 0 } +{ 4000 2/ -> 2000 } +{ 1S 2/ -> 1S } \ MSB PROPOGATED +{ 1S 1 XOR 2/ -> 1S } +{ MSB 2/ MSB AND -> MSB } + +{ 1 0 LSHIFT -> 1 } +{ 1 1 LSHIFT -> 2 } +{ 1 2 LSHIFT -> 4 } +{ 1 F LSHIFT -> 8000 } \ BIGGEST GUARANTEED SHIFT +{ 1S 1 LSHIFT 1 XOR -> 1S } +{ MSB 1 LSHIFT -> 0 } + +{ 1 0 RSHIFT -> 1 } +{ 1 1 RSHIFT -> 0 } +{ 2 1 RSHIFT -> 1 } +{ 4 2 RSHIFT -> 1 } +{ 8000 F RSHIFT -> 1 } \ BIGGEST +{ MSB 1 RSHIFT MSB AND -> 0 } \ RSHIFT ZERO FILLS MSBS +{ MSB 1 RSHIFT 2* -> MSB } + +\ ------------------------------------------------------------------------ +TESTING COMPARISONS: 0= = 0< < > U< MIN MAX +0 INVERT CONSTANT MAX-UINT +0 INVERT 1 RSHIFT CONSTANT MAX-INT +0 INVERT 1 RSHIFT INVERT CONSTANT MIN-INT +0 INVERT 1 RSHIFT CONSTANT MID-UINT +0 INVERT 1 RSHIFT INVERT CONSTANT MID-UINT+1 + +0S CONSTANT +1S CONSTANT + +{ 0 0= -> } +{ 1 0= -> } +{ 2 0= -> } +{ -1 0= -> } +{ MAX-UINT 0= -> } +{ MIN-INT 0= -> } +{ MAX-INT 0= -> } + +{ 0 0 = -> } +{ 1 1 = -> } +{ -1 -1 = -> } +{ 1 0 = -> } +{ -1 0 = -> } +{ 0 1 = -> } +{ 0 -1 = -> } + +{ 0 0< -> } +{ -1 0< -> } +{ MIN-INT 0< -> } +{ 1 0< -> } +{ MAX-INT 0< -> } + +{ 0 1 < -> } +{ 1 2 < -> } +{ -1 0 < -> } +{ -1 1 < -> } +{ MIN-INT 0 < -> } +{ MIN-INT MAX-INT < -> } +{ 0 MAX-INT < -> } +{ 0 0 < -> } +{ 1 1 < -> } +{ 1 0 < -> } +{ 2 1 < -> } +{ 0 -1 < -> } +{ 1 -1 < -> } +{ 0 MIN-INT < -> } +{ MAX-INT MIN-INT < -> } +{ MAX-INT 0 < -> } + +{ 0 1 > -> } +{ 1 2 > -> } +{ -1 0 > -> } +{ -1 1 > -> } +{ MIN-INT 0 > -> } +{ MIN-INT MAX-INT > -> } +{ 0 MAX-INT > -> } +{ 0 0 > -> } +{ 1 1 > -> } +{ 1 0 > -> } +{ 2 1 > -> } +{ 0 -1 > -> } +{ 1 -1 > -> } +{ 0 MIN-INT > -> } +{ MAX-INT MIN-INT > -> } +{ MAX-INT 0 > -> } + +{ 0 1 U< -> } +{ 1 2 U< -> } +{ 0 MID-UINT U< -> } +{ 0 MAX-UINT U< -> } +{ MID-UINT MAX-UINT U< -> } +{ 0 0 U< -> } +{ 1 1 U< -> } +{ 1 0 U< -> } +{ 2 1 U< -> } +{ MID-UINT 0 U< -> } +{ MAX-UINT 0 U< -> } +{ MAX-UINT MID-UINT U< -> } + +{ 0 1 MIN -> 0 } +{ 1 2 MIN -> 1 } +{ -1 0 MIN -> -1 } +{ -1 1 MIN -> -1 } +{ MIN-INT 0 MIN -> MIN-INT } +{ MIN-INT MAX-INT MIN -> MIN-INT } +{ 0 MAX-INT MIN -> 0 } +{ 0 0 MIN -> 0 } +{ 1 1 MIN -> 1 } +{ 1 0 MIN -> 0 } +{ 2 1 MIN -> 1 } +{ 0 -1 MIN -> -1 } +{ 1 -1 MIN -> -1 } +{ 0 MIN-INT MIN -> MIN-INT } +{ MAX-INT MIN-INT MIN -> MIN-INT } +{ MAX-INT 0 MIN -> 0 } + +{ 0 1 MAX -> 1 } +{ 1 2 MAX -> 2 } +{ -1 0 MAX -> 0 } +{ -1 1 MAX -> 1 } +{ MIN-INT 0 MAX -> 0 } +{ MIN-INT MAX-INT MAX -> MAX-INT } +{ 0 MAX-INT MAX -> MAX-INT } +{ 0 0 MAX -> 0 } +{ 1 1 MAX -> 1 } +{ 1 0 MAX -> 1 } +{ 2 1 MAX -> 2 } +{ 0 -1 MAX -> 0 } +{ 1 -1 MAX -> 1 } +{ 0 MIN-INT MAX -> 0 } +{ MAX-INT MIN-INT MAX -> MAX-INT } +{ MAX-INT 0 MAX -> MAX-INT } + +\ ------------------------------------------------------------------------ +TESTING STACK OPS: 2DROP 2DUP 2OVER 2SWAP ?DUP DEPTH DROP DUP OVER ROT SWAP + +{ 1 2 2DROP -> } +{ 1 2 2DUP -> 1 2 1 2 } +{ 1 2 3 4 2OVER -> 1 2 3 4 1 2 } +{ 1 2 3 4 2SWAP -> 3 4 1 2 } +{ 0 ?DUP -> 0 } +{ 1 ?DUP -> 1 1 } +{ -1 ?DUP -> -1 -1 } +{ DEPTH -> 0 } +{ 0 DEPTH -> 0 1 } +{ 0 1 DEPTH -> 0 1 2 } +{ 0 DROP -> } +{ 1 2 DROP -> 1 } +{ 1 DUP -> 1 1 } +{ 1 2 OVER -> 1 2 1 } +{ 1 2 3 ROT -> 2 3 1 } +{ 1 2 SWAP -> 2 1 } + +\ ------------------------------------------------------------------------ +TESTING >R R> R@ + +{ : GR1 >R R> ; -> } +{ : GR2 >R R@ R> DROP ; -> } +{ 123 GR1 -> 123 } +{ 123 GR2 -> 123 } +{ 1S GR1 -> 1S } ( RETURN STACK HOLDS CELLS ) + +\ ------------------------------------------------------------------------ +TESTING ADD/SUBTRACT: + - 1+ 1- ABS NEGATE + +{ 0 5 + -> 5 } +{ 5 0 + -> 5 } +{ 0 -5 + -> -5 } +{ -5 0 + -> -5 } +{ 1 2 + -> 3 } +{ 1 -2 + -> -1 } +{ -1 2 + -> 1 } +{ -1 -2 + -> -3 } +{ -1 1 + -> 0 } +{ MID-UINT 1 + -> MID-UINT+1 } + +{ 0 5 - -> -5 } +{ 5 0 - -> 5 } +{ 0 -5 - -> 5 } +{ -5 0 - -> -5 } +{ 1 2 - -> -1 } +{ 1 -2 - -> 3 } +{ -1 2 - -> -3 } +{ -1 -2 - -> 1 } +{ 0 1 - -> -1 } +{ MID-UINT+1 1 - -> MID-UINT } + +{ 0 1+ -> 1 } +{ -1 1+ -> 0 } +{ 1 1+ -> 2 } +{ MID-UINT 1+ -> MID-UINT+1 } + +{ 2 1- -> 1 } +{ 1 1- -> 0 } +{ 0 1- -> -1 } +{ MID-UINT+1 1- -> MID-UINT } + +{ 0 NEGATE -> 0 } +{ 1 NEGATE -> -1 } +{ -1 NEGATE -> 1 } +{ 2 NEGATE -> -2 } +{ -2 NEGATE -> 2 } + +{ 0 ABS -> 0 } +{ 1 ABS -> 1 } +{ -1 ABS -> 1 } +{ MIN-INT ABS -> MID-UINT+1 } + +\ ------------------------------------------------------------------------ +TESTING MULTIPLY: S>D * M* UM* + +{ 0 S>D -> 0 0 } +{ 1 S>D -> 1 0 } +{ 2 S>D -> 2 0 } +{ -1 S>D -> -1 -1 } +{ -2 S>D -> -2 -1 } +{ MIN-INT S>D -> MIN-INT -1 } +{ MAX-INT S>D -> MAX-INT 0 } + +{ 0 0 M* -> 0 S>D } +{ 0 1 M* -> 0 S>D } +{ 1 0 M* -> 0 S>D } +{ 1 2 M* -> 2 S>D } +{ 2 1 M* -> 2 S>D } +{ 3 3 M* -> 9 S>D } +{ -3 3 M* -> -9 S>D } +{ 3 -3 M* -> -9 S>D } +{ -3 -3 M* -> 9 S>D } +{ 0 MIN-INT M* -> 0 S>D } +{ 1 MIN-INT M* -> MIN-INT S>D } +{ 2 MIN-INT M* -> 0 1S } +{ 0 MAX-INT M* -> 0 S>D } +{ 1 MAX-INT M* -> MAX-INT S>D } +{ 2 MAX-INT M* -> MAX-INT 1 LSHIFT 0 } +{ MIN-INT MIN-INT M* -> 0 MSB 1 RSHIFT } +{ MAX-INT MIN-INT M* -> MSB MSB 2/ } +{ MAX-INT MAX-INT M* -> 1 MSB 2/ INVERT } + +{ 0 0 * -> 0 } \ TEST IDENTITIES +{ 0 1 * -> 0 } +{ 1 0 * -> 0 } +{ 1 2 * -> 2 } +{ 2 1 * -> 2 } +{ 3 3 * -> 9 } +{ -3 3 * -> -9 } +{ 3 -3 * -> -9 } +{ -3 -3 * -> 9 } + +{ MID-UINT+1 1 RSHIFT 2 * -> MID-UINT+1 } +{ MID-UINT+1 2 RSHIFT 4 * -> MID-UINT+1 } +{ MID-UINT+1 1 RSHIFT MID-UINT+1 OR 2 * -> MID-UINT+1 } + +{ 0 0 UM* -> 0 0 } +{ 0 1 UM* -> 0 0 } +{ 1 0 UM* -> 0 0 } +{ 1 2 UM* -> 2 0 } +{ 2 1 UM* -> 2 0 } +{ 3 3 UM* -> 9 0 } + +{ MID-UINT+1 1 RSHIFT 2 UM* -> MID-UINT+1 0 } +{ MID-UINT+1 2 UM* -> 0 1 } +{ MID-UINT+1 4 UM* -> 0 2 } +{ 1S 2 UM* -> 1S 1 LSHIFT 1 } +{ MAX-UINT MAX-UINT UM* -> 1 1 INVERT } + +\ ------------------------------------------------------------------------ +TESTING DIVIDE: FM/MOD SM/REM UM/MOD */ */MOD / /MOD MOD + +{ 0 S>D 1 FM/MOD -> 0 0 } +{ 1 S>D 1 FM/MOD -> 0 1 } +{ 2 S>D 1 FM/MOD -> 0 2 } +{ -1 S>D 1 FM/MOD -> 0 -1 } +{ -2 S>D 1 FM/MOD -> 0 -2 } +{ 0 S>D -1 FM/MOD -> 0 0 } +{ 1 S>D -1 FM/MOD -> 0 -1 } +{ 2 S>D -1 FM/MOD -> 0 -2 } +{ -1 S>D -1 FM/MOD -> 0 1 } +{ -2 S>D -1 FM/MOD -> 0 2 } +{ 2 S>D 2 FM/MOD -> 0 1 } +{ -1 S>D -1 FM/MOD -> 0 1 } +{ -2 S>D -2 FM/MOD -> 0 1 } +{ 7 S>D 3 FM/MOD -> 1 2 } +{ 7 S>D -3 FM/MOD -> -2 -3 } +{ -7 S>D 3 FM/MOD -> 2 -3 } +{ -7 S>D -3 FM/MOD -> -1 2 } +{ MAX-INT S>D 1 FM/MOD -> 0 MAX-INT } +{ MIN-INT S>D 1 FM/MOD -> 0 MIN-INT } +{ MAX-INT S>D MAX-INT FM/MOD -> 0 1 } +{ MIN-INT S>D MIN-INT FM/MOD -> 0 1 } +{ 1S 1 4 FM/MOD -> 3 MAX-INT } +{ 1 MIN-INT M* 1 FM/MOD -> 0 MIN-INT } +{ 1 MIN-INT M* MIN-INT FM/MOD -> 0 1 } +{ 2 MIN-INT M* 2 FM/MOD -> 0 MIN-INT } +{ 2 MIN-INT M* MIN-INT FM/MOD -> 0 2 } +{ 1 MAX-INT M* 1 FM/MOD -> 0 MAX-INT } +{ 1 MAX-INT M* MAX-INT FM/MOD -> 0 1 } +{ 2 MAX-INT M* 2 FM/MOD -> 0 MAX-INT } +{ 2 MAX-INT M* MAX-INT FM/MOD -> 0 2 } +{ MIN-INT MIN-INT M* MIN-INT FM/MOD -> 0 MIN-INT } +{ MIN-INT MAX-INT M* MIN-INT FM/MOD -> 0 MAX-INT } +{ MIN-INT MAX-INT M* MAX-INT FM/MOD -> 0 MIN-INT } +{ MAX-INT MAX-INT M* MAX-INT FM/MOD -> 0 MAX-INT } + +{ 0 S>D 1 SM/REM -> 0 0 } +{ 1 S>D 1 SM/REM -> 0 1 } +{ 2 S>D 1 SM/REM -> 0 2 } +{ -1 S>D 1 SM/REM -> 0 -1 } +{ -2 S>D 1 SM/REM -> 0 -2 } +{ 0 S>D -1 SM/REM -> 0 0 } +{ 1 S>D -1 SM/REM -> 0 -1 } +{ 2 S>D -1 SM/REM -> 0 -2 } +{ -1 S>D -1 SM/REM -> 0 1 } +{ -2 S>D -1 SM/REM -> 0 2 } +{ 2 S>D 2 SM/REM -> 0 1 } +{ -1 S>D -1 SM/REM -> 0 1 } +{ -2 S>D -2 SM/REM -> 0 1 } +{ 7 S>D 3 SM/REM -> 1 2 } +{ 7 S>D -3 SM/REM -> 1 -2 } +{ -7 S>D 3 SM/REM -> -1 -2 } +{ -7 S>D -3 SM/REM -> -1 2 } +{ MAX-INT S>D 1 SM/REM -> 0 MAX-INT } +{ MIN-INT S>D 1 SM/REM -> 0 MIN-INT } +{ MAX-INT S>D MAX-INT SM/REM -> 0 1 } +{ MIN-INT S>D MIN-INT SM/REM -> 0 1 } +{ 1S 1 4 SM/REM -> 3 MAX-INT } +{ 2 MIN-INT M* 2 SM/REM -> 0 MIN-INT } +{ 2 MIN-INT M* MIN-INT SM/REM -> 0 2 } +{ 2 MAX-INT M* 2 SM/REM -> 0 MAX-INT } +{ 2 MAX-INT M* MAX-INT SM/REM -> 0 2 } +{ MIN-INT MIN-INT M* MIN-INT SM/REM -> 0 MIN-INT } +{ MIN-INT MAX-INT M* MIN-INT SM/REM -> 0 MAX-INT } +{ MIN-INT MAX-INT M* MAX-INT SM/REM -> 0 MIN-INT } +{ MAX-INT MAX-INT M* MAX-INT SM/REM -> 0 MAX-INT } + +{ 0 0 1 UM/MOD -> 0 0 } +{ 1 0 1 UM/MOD -> 0 1 } +{ 1 0 2 UM/MOD -> 1 0 } +{ 3 0 2 UM/MOD -> 1 1 } +{ MAX-UINT 2 UM* 2 UM/MOD -> 0 MAX-UINT } +{ MAX-UINT 2 UM* MAX-UINT UM/MOD -> 0 2 } +{ MAX-UINT MAX-UINT UM* MAX-UINT UM/MOD -> 0 MAX-UINT } + +: IFFLOORED + [ -3 2 / -2 = INVERT ] LITERAL IF POSTPONE \ THEN ; +: IFSYM + [ -3 2 / -1 = INVERT ] LITERAL IF POSTPONE \ THEN ; + +\ THE SYSTEM MIGHT DO EITHER FLOORED OR SYMMETRIC DIVISION. +\ SINCE WE HAVE ALREADY TESTED M*, FM/MOD, AND SM/REM WE CAN USE THEM IN TEST. +IFFLOORED : T/MOD >R S>D R> FM/MOD ; +IFFLOORED : T/ T/MOD SWAP DROP ; +IFFLOORED : TMOD T/MOD DROP ; +IFFLOORED : T*/MOD >R M* R> FM/MOD ; +IFFLOORED : T*/ T*/MOD SWAP DROP ; +IFSYM : T/MOD >R S>D R> SM/REM ; +IFSYM : T/ T/MOD SWAP DROP ; +IFSYM : TMOD T/MOD DROP ; +IFSYM : T*/MOD >R M* R> SM/REM ; +IFSYM : T*/ T*/MOD SWAP DROP ; + +{ 0 1 /MOD -> 0 1 T/MOD } +{ 1 1 /MOD -> 1 1 T/MOD } +{ 2 1 /MOD -> 2 1 T/MOD } +{ -1 1 /MOD -> -1 1 T/MOD } +{ -2 1 /MOD -> -2 1 T/MOD } +{ 0 -1 /MOD -> 0 -1 T/MOD } +{ 1 -1 /MOD -> 1 -1 T/MOD } +{ 2 -1 /MOD -> 2 -1 T/MOD } +{ -1 -1 /MOD -> -1 -1 T/MOD } +{ -2 -1 /MOD -> -2 -1 T/MOD } +{ 2 2 /MOD -> 2 2 T/MOD } +{ -1 -1 /MOD -> -1 -1 T/MOD } +{ -2 -2 /MOD -> -2 -2 T/MOD } +{ 7 3 /MOD -> 7 3 T/MOD } +{ 7 -3 /MOD -> 7 -3 T/MOD } +{ -7 3 /MOD -> -7 3 T/MOD } +{ -7 -3 /MOD -> -7 -3 T/MOD } +{ MAX-INT 1 /MOD -> MAX-INT 1 T/MOD } +{ MIN-INT 1 /MOD -> MIN-INT 1 T/MOD } +{ MAX-INT MAX-INT /MOD -> MAX-INT MAX-INT T/MOD } +{ MIN-INT MIN-INT /MOD -> MIN-INT MIN-INT T/MOD } + +{ 0 1 / -> 0 1 T/ } +{ 1 1 / -> 1 1 T/ } +{ 2 1 / -> 2 1 T/ } +{ -1 1 / -> -1 1 T/ } +{ -2 1 / -> -2 1 T/ } +{ 0 -1 / -> 0 -1 T/ } +{ 1 -1 / -> 1 -1 T/ } +{ 2 -1 / -> 2 -1 T/ } +{ -1 -1 / -> -1 -1 T/ } +{ -2 -1 / -> -2 -1 T/ } +{ 2 2 / -> 2 2 T/ } +{ -1 -1 / -> -1 -1 T/ } +{ -2 -2 / -> -2 -2 T/ } +{ 7 3 / -> 7 3 T/ } +{ 7 -3 / -> 7 -3 T/ } +{ -7 3 / -> -7 3 T/ } +{ -7 -3 / -> -7 -3 T/ } +{ MAX-INT 1 / -> MAX-INT 1 T/ } +{ MIN-INT 1 / -> MIN-INT 1 T/ } +{ MAX-INT MAX-INT / -> MAX-INT MAX-INT T/ } +{ MIN-INT MIN-INT / -> MIN-INT MIN-INT T/ } + +{ 0 1 MOD -> 0 1 TMOD } +{ 1 1 MOD -> 1 1 TMOD } +{ 2 1 MOD -> 2 1 TMOD } +{ -1 1 MOD -> -1 1 TMOD } +{ -2 1 MOD -> -2 1 TMOD } +{ 0 -1 MOD -> 0 -1 TMOD } +{ 1 -1 MOD -> 1 -1 TMOD } +{ 2 -1 MOD -> 2 -1 TMOD } +{ -1 -1 MOD -> -1 -1 TMOD } +{ -2 -1 MOD -> -2 -1 TMOD } +{ 2 2 MOD -> 2 2 TMOD } +{ -1 -1 MOD -> -1 -1 TMOD } +{ -2 -2 MOD -> -2 -2 TMOD } +{ 7 3 MOD -> 7 3 TMOD } +{ 7 -3 MOD -> 7 -3 TMOD } +{ -7 3 MOD -> -7 3 TMOD } +{ -7 -3 MOD -> -7 -3 TMOD } +{ MAX-INT 1 MOD -> MAX-INT 1 TMOD } +{ MIN-INT 1 MOD -> MIN-INT 1 TMOD } +{ MAX-INT MAX-INT MOD -> MAX-INT MAX-INT TMOD } +{ MIN-INT MIN-INT MOD -> MIN-INT MIN-INT TMOD } + +{ 0 2 1 */ -> 0 2 1 T*/ } +{ 1 2 1 */ -> 1 2 1 T*/ } +{ 2 2 1 */ -> 2 2 1 T*/ } +{ -1 2 1 */ -> -1 2 1 T*/ } +{ -2 2 1 */ -> -2 2 1 T*/ } +{ 0 2 -1 */ -> 0 2 -1 T*/ } +{ 1 2 -1 */ -> 1 2 -1 T*/ } +{ 2 2 -1 */ -> 2 2 -1 T*/ } +{ -1 2 -1 */ -> -1 2 -1 T*/ } +{ -2 2 -1 */ -> -2 2 -1 T*/ } +{ 2 2 2 */ -> 2 2 2 T*/ } +{ -1 2 -1 */ -> -1 2 -1 T*/ } +{ -2 2 -2 */ -> -2 2 -2 T*/ } +{ 7 2 3 */ -> 7 2 3 T*/ } +{ 7 2 -3 */ -> 7 2 -3 T*/ } +{ -7 2 3 */ -> -7 2 3 T*/ } +{ -7 2 -3 */ -> -7 2 -3 T*/ } +{ MAX-INT 2 MAX-INT */ -> MAX-INT 2 MAX-INT T*/ } +{ MIN-INT 2 MIN-INT */ -> MIN-INT 2 MIN-INT T*/ } + +{ 0 2 1 */MOD -> 0 2 1 T*/MOD } +{ 1 2 1 */MOD -> 1 2 1 T*/MOD } +{ 2 2 1 */MOD -> 2 2 1 T*/MOD } +{ -1 2 1 */MOD -> -1 2 1 T*/MOD } +{ -2 2 1 */MOD -> -2 2 1 T*/MOD } +{ 0 2 -1 */MOD -> 0 2 -1 T*/MOD } +{ 1 2 -1 */MOD -> 1 2 -1 T*/MOD } +{ 2 2 -1 */MOD -> 2 2 -1 T*/MOD } +{ -1 2 -1 */MOD -> -1 2 -1 T*/MOD } +{ -2 2 -1 */MOD -> -2 2 -1 T*/MOD } +{ 2 2 2 */MOD -> 2 2 2 T*/MOD } +{ -1 2 -1 */MOD -> -1 2 -1 T*/MOD } +{ -2 2 -2 */MOD -> -2 2 -2 T*/MOD } +{ 7 2 3 */MOD -> 7 2 3 T*/MOD } +{ 7 2 -3 */MOD -> 7 2 -3 T*/MOD } +{ -7 2 3 */MOD -> -7 2 3 T*/MOD } +{ -7 2 -3 */MOD -> -7 2 -3 T*/MOD } +{ MAX-INT 2 MAX-INT */MOD -> MAX-INT 2 MAX-INT T*/MOD } +{ MIN-INT 2 MIN-INT */MOD -> MIN-INT 2 MIN-INT T*/MOD } + +\ ------------------------------------------------------------------------ +TESTING HERE , @ ! CELL+ CELLS C, C@ C! CHARS 2@ 2! ALIGN ALIGNED +! ALLOT + +HERE 1 ALLOT +HERE +CONSTANT 2NDA +CONSTANT 1STA +{ 1STA 2NDA U< -> } \ HERE MUST GROW WITH ALLOT +{ 1STA 1+ -> 2NDA } \ ... BY ONE ADDRESS UNIT +( MISSING TEST: NEGATIVE ALLOT ) + +HERE 1 , +HERE 2 , +CONSTANT 2ND +CONSTANT 1ST +{ 1ST 2ND U< -> } \ HERE MUST GROW WITH ALLOT +{ 1ST CELL+ -> 2ND } \ ... BY ONE CELL +{ 1ST 1 CELLS + -> 2ND } +{ 1ST @ 2ND @ -> 1 2 } +{ 5 1ST ! -> } +{ 1ST @ 2ND @ -> 5 2 } +{ 6 2ND ! -> } +{ 1ST @ 2ND @ -> 5 6 } +{ 1ST 2@ -> 6 5 } +{ 2 1 1ST 2! -> } +{ 1ST 2@ -> 2 1 } +{ 1S 1ST ! 1ST @ -> 1S } \ CAN STORE CELL-WIDE VALUE + +HERE 1 C, +HERE 2 C, +CONSTANT 2NDC +CONSTANT 1STC +{ 1STC 2NDC U< -> } \ HERE MUST GROW WITH ALLOT +{ 1STC CHAR+ -> 2NDC } \ ... BY ONE CHAR +{ 1STC 1 CHARS + -> 2NDC } +{ 1STC C@ 2NDC C@ -> 1 2 } +{ 3 1STC C! -> } +{ 1STC C@ 2NDC C@ -> 3 2 } +{ 4 2NDC C! -> } +{ 1STC C@ 2NDC C@ -> 3 4 } + +ALIGN 1 ALLOT HERE ALIGN HERE 3 CELLS ALLOT +CONSTANT A-ADDR CONSTANT UA-ADDR +{ UA-ADDR ALIGNED -> A-ADDR } +{ 1 A-ADDR C! A-ADDR C@ -> 1 } +{ 1234 A-ADDR ! A-ADDR @ -> 1234 } +{ 123 456 A-ADDR 2! A-ADDR 2@ -> 123 456 } +{ 2 A-ADDR CHAR+ C! A-ADDR CHAR+ C@ -> 2 } +{ 3 A-ADDR CELL+ C! A-ADDR CELL+ C@ -> 3 } +{ 1234 A-ADDR CELL+ ! A-ADDR CELL+ @ -> 1234 } +{ 123 456 A-ADDR CELL+ 2! A-ADDR CELL+ 2@ -> 123 456 } + +: BITS ( X -- U ) + 0 SWAP BEGIN DUP WHILE DUP MSB AND IF >R 1+ R> THEN 2* REPEAT DROP ; +( CHARACTERS >= 1 AU, <= SIZE OF CELL, >= 8 BITS ) +{ 1 CHARS 1 < -> } +{ 1 CHARS 1 CELLS > -> } +( TBD: HOW TO FIND NUMBER OF BITS? ) + +( CELLS >= 1 AU, INTEGRAL MULTIPLE OF CHAR SIZE, >= 16 BITS ) +{ 1 CELLS 1 < -> } +{ 1 CELLS 1 CHARS MOD -> 0 } +{ 1S BITS 10 < -> } + +{ 0 1ST ! -> } +{ 1 1ST +! -> } +{ 1ST @ -> 1 } +{ -1 1ST +! 1ST @ -> 0 } + +\ ------------------------------------------------------------------------ +TESTING CHAR [CHAR] [ ] BL S" + +{ BL -> 20 } +{ CHAR X -> 58 } +{ CHAR HELLO -> 48 } +{ : GC1 [CHAR] X ; -> } +{ : GC2 [CHAR] HELLO ; -> } +{ GC1 -> 58 } +{ GC2 -> 48 } +{ : GC3 [ GC1 ] LITERAL ; -> } +{ GC3 -> 58 } +{ : GC4 S" XY" ; -> } +{ GC4 SWAP DROP -> 2 } +{ GC4 DROP DUP C@ SWAP CHAR+ C@ -> 58 59 } + +\ ------------------------------------------------------------------------ +TESTING ' ['] FIND EXECUTE IMMEDIATE COUNT LITERAL POSTPONE STATE + +{ : GT1 123 ; -> } +{ ' GT1 EXECUTE -> 123 } +{ : GT2 ['] GT1 ; IMMEDIATE -> } +{ GT2 EXECUTE -> 123 } +HERE 3 C, CHAR G C, CHAR T C, CHAR 1 C, CONSTANT GT1STRING +HERE 3 C, CHAR G C, CHAR T C, CHAR 2 C, CONSTANT GT2STRING +{ GT1STRING FIND -> ' GT1 -1 } +{ GT2STRING FIND -> ' GT2 1 } +( HOW TO SEARCH FOR NON-EXISTENT WORD? ) +{ : GT3 GT2 LITERAL ; -> } +{ GT3 -> ' GT1 } +{ GT1STRING COUNT -> GT1STRING CHAR+ 3 } + +{ : GT4 POSTPONE GT1 ; IMMEDIATE -> } +{ : GT5 GT4 ; -> } +{ GT5 -> 123 } +{ : GT6 345 ; IMMEDIATE -> } +{ : GT7 POSTPONE GT6 ; -> } +{ GT7 -> 345 } + +{ : GT8 STATE @ ; IMMEDIATE -> } +{ GT8 -> 0 } +{ : GT9 GT8 LITERAL ; -> } +{ GT9 0= -> } + +\ ------------------------------------------------------------------------ +TESTING IF ELSE THEN BEGIN WHILE REPEAT UNTIL RECURSE + +{ : GI1 IF 123 THEN ; -> } +{ : GI2 IF 123 ELSE 234 THEN ; -> } +{ 0 GI1 -> } +{ 1 GI1 -> 123 } +{ -1 GI1 -> 123 } +{ 0 GI2 -> 234 } +{ 1 GI2 -> 123 } +{ -1 GI1 -> 123 } + +{ : GI3 BEGIN DUP 5 < WHILE DUP 1+ REPEAT ; -> } +{ 0 GI3 -> 0 1 2 3 4 5 } +{ 4 GI3 -> 4 5 } +{ 5 GI3 -> 5 } +{ 6 GI3 -> 6 } + +{ : GI4 BEGIN DUP 1+ DUP 5 > UNTIL ; -> } +{ 3 GI4 -> 3 4 5 6 } +{ 5 GI4 -> 5 6 } +{ 6 GI4 -> 6 7 } + +{ : GI5 BEGIN DUP 2 > WHILE DUP 5 < WHILE DUP 1+ REPEAT 123 ELSE 345 THEN ; -> } +{ 1 GI5 -> 1 345 } +{ 2 GI5 -> 2 345 } +{ 3 GI5 -> 3 4 5 123 } +{ 4 GI5 -> 4 5 123 } +{ 5 GI5 -> 5 123 } + +{ : GI6 ( N -- 0,1,..N ) DUP IF DUP >R 1- RECURSE R> THEN ; -> } +{ 0 GI6 -> 0 } +{ 1 GI6 -> 0 1 } +{ 2 GI6 -> 0 1 2 } +{ 3 GI6 -> 0 1 2 3 } +{ 4 GI6 -> 0 1 2 3 4 } + +\ ------------------------------------------------------------------------ +TESTING DO LOOP +LOOP I J UNLOOP LEAVE EXIT + +{ : GD1 DO I LOOP ; -> } +{ 4 1 GD1 -> 1 2 3 } +{ 2 -1 GD1 -> -1 0 1 } +{ MID-UINT+1 MID-UINT GD1 -> MID-UINT } + +{ : GD2 DO I -1 +LOOP ; -> } +{ 1 4 GD2 -> 4 3 2 1 } +{ -1 2 GD2 -> 2 1 0 -1 } +{ MID-UINT MID-UINT+1 GD2 -> MID-UINT+1 MID-UINT } + +{ : GD3 DO 1 0 DO J LOOP LOOP ; -> } +{ 4 1 GD3 -> 1 2 3 } +{ 2 -1 GD3 -> -1 0 1 } +{ MID-UINT+1 MID-UINT GD3 -> MID-UINT } + +{ : GD4 DO 1 0 DO J LOOP -1 +LOOP ; -> } +{ 1 4 GD4 -> 4 3 2 1 } +{ -1 2 GD4 -> 2 1 0 -1 } +{ MID-UINT MID-UINT+1 GD4 -> MID-UINT+1 MID-UINT } + +{ : GD5 123 SWAP 0 DO I 4 > IF DROP 234 LEAVE THEN LOOP ; -> } +{ 1 GD5 -> 123 } +{ 5 GD5 -> 123 } +{ 6 GD5 -> 234 } + +{ : GD6 ( PAT: {0 0},{0 0}{1 0}{1 1},{0 0}{1 0}{1 1}{2 0}{2 1}{2 2} ) + 0 SWAP 0 DO + I 1+ 0 DO I J + 3 = IF I UNLOOP I UNLOOP EXIT THEN 1+ LOOP + LOOP ; -> } +{ 1 GD6 -> 1 } +{ 2 GD6 -> 3 } +{ 3 GD6 -> 4 1 2 } + +\ ------------------------------------------------------------------------ +TESTING DEFINING WORDS: : ; CONSTANT VARIABLE CREATE DOES> >BODY + +{ 123 CONSTANT X123 -> } +{ X123 -> 123 } +{ : EQU CONSTANT ; -> } +{ X123 EQU Y123 -> } +{ Y123 -> 123 } + +{ VARIABLE V1 -> } +{ 123 V1 ! -> } +{ V1 @ -> 123 } + +{ : NOP : POSTPONE ; ; -> } +{ NOP NOP1 NOP NOP2 -> } +{ NOP1 -> } +{ NOP2 -> } + +{ : DOES1 DOES> @ 1 + ; -> } +{ : DOES2 DOES> @ 2 + ; -> } +{ CREATE CR1 -> } +{ CR1 -> HERE } +{ ' CR1 >BODY -> HERE } +{ 1 , -> } +{ CR1 @ -> 1 } +{ DOES1 -> } +{ CR1 -> 2 } +{ DOES2 -> } +{ CR1 -> 3 } + +{ : WEIRD: CREATE DOES> 1 + DOES> 2 + ; -> } +{ WEIRD: W1 -> } +{ ' W1 >BODY -> HERE } +{ W1 -> HERE 1 + } +{ W1 -> HERE 2 + } + +\ ------------------------------------------------------------------------ +TESTING EVALUATE + +: GE1 S" 123" ; IMMEDIATE +: GE2 S" 123 1+" ; IMMEDIATE +: GE3 S" : GE4 345 ;" ; +: GE5 EVALUATE ; IMMEDIATE + +{ GE1 EVALUATE -> 123 } ( TEST EVALUATE IN INTERP. STATE ) +{ GE2 EVALUATE -> 124 } +{ GE3 EVALUATE -> } +{ GE4 -> 345 } + +{ : GE6 GE1 GE5 ; -> } ( TEST EVALUATE IN COMPILE STATE ) +{ GE6 -> 123 } +{ : GE7 GE2 GE5 ; -> } +{ GE7 -> 124 } + +\ ------------------------------------------------------------------------ +TESTING SOURCE >IN WORD + +: GS1 S" SOURCE" 2DUP EVALUATE + >R SWAP >R = R> R> = ; +{ GS1 -> } + +VARIABLE SCANS +: RESCAN? -1 SCANS +! SCANS @ IF 0 >IN ! THEN ; + +{ 2 SCANS ! +345 RESCAN? +-> 345 345 } + +: GS2 5 SCANS ! S" 123 RESCAN?" EVALUATE ; +{ GS2 -> 123 123 123 123 123 } + +: GS3 WORD COUNT SWAP C@ ; +{ BL GS3 HELLO -> 5 CHAR H } +{ CHAR " GS3 GOODBYE" -> 7 CHAR G } +{ BL GS3 +DROP -> 0 } \ BLANK LINE RETURN ZERO-LENGTH STRING + +: GS4 SOURCE >IN ! DROP ; +{ GS4 123 456 +-> } + +\ ------------------------------------------------------------------------ +TESTING <# # #S #> HOLD SIGN BASE >NUMBER HEX DECIMAL + +: S= \ ( ADDR1 C1 ADDR2 C2 -- T/F ) COMPARE TWO STRINGS. + >R SWAP R@ = IF \ MAKE SURE STRINGS HAVE SAME LENGTH + R> ?DUP IF \ IF NON-EMPTY STRINGS + 0 DO + OVER C@ OVER C@ - IF 2DROP UNLOOP EXIT THEN + SWAP CHAR+ SWAP CHAR+ + LOOP + THEN + 2DROP \ IF WE GET HERE, STRINGS MATCH + ELSE + R> DROP 2DROP \ LENGTHS MISMATCH + THEN ; + +: GP1 <# 41 HOLD 42 HOLD 0 0 #> S" BA" S= ; +{ GP1 -> } + +: GP2 <# -1 SIGN 0 SIGN -1 SIGN 0 0 #> S" --" S= ; +{ GP2 -> } + +: GP3 <# 1 0 # # #> S" 01" S= ; +{ GP3 -> } + +: GP4 <# 1 0 #S #> S" 1" S= ; +{ GP4 -> } + +24 CONSTANT MAX-BASE \ BASE 2 .. 36 +: COUNT-BITS + 0 0 INVERT BEGIN DUP WHILE >R 1+ R> 2* REPEAT DROP ; +COUNT-BITS 2* CONSTANT #BITS-UD \ NUMBER OF BITS IN UD + +: GP5 + BASE @ + MAX-BASE 1+ 2 DO \ FOR EACH POSSIBLE BASE + I BASE ! \ TBD: ASSUMES BASE WORKS + I 0 <# #S #> S" 10" S= AND + LOOP + SWAP BASE ! ; +{ GP5 -> } + +: GP6 + BASE @ >R 2 BASE ! + MAX-UINT MAX-UINT <# #S #> \ MAXIMUM UD TO BINARY + R> BASE ! \ S: C-ADDR U + DUP #BITS-UD = SWAP + 0 DO \ S: C-ADDR FLAG + OVER C@ [CHAR] 1 = AND \ ALL ONES + >R CHAR+ R> + LOOP SWAP DROP ; +{ GP6 -> } + +: GP7 + BASE @ >R MAX-BASE BASE ! + + A 0 DO + I 0 <# #S #> + 1 = SWAP C@ I 30 + = AND AND + LOOP + MAX-BASE A DO + I 0 <# #S #> + 1 = SWAP C@ 41 I A - + = AND AND + LOOP + R> BASE ! ; + +{ GP7 -> } + +\ >NUMBER TESTS +CREATE GN-BUF 0 C, +: GN-STRING GN-BUF 1 ; +: GN-CONSUMED GN-BUF CHAR+ 0 ; +: GN' [CHAR] ' WORD CHAR+ C@ GN-BUF C! GN-STRING ; + +{ 0 0 GN' 0' >NUMBER -> 0 0 GN-CONSUMED } +{ 0 0 GN' 1' >NUMBER -> 1 0 GN-CONSUMED } +{ 1 0 GN' 1' >NUMBER -> BASE @ 1+ 0 GN-CONSUMED } +{ 0 0 GN' -' >NUMBER -> 0 0 GN-STRING } \ SHOULD FAIL TO CONVERT THESE +{ 0 0 GN' +' >NUMBER -> 0 0 GN-STRING } +{ 0 0 GN' .' >NUMBER -> 0 0 GN-STRING } + +: >NUMBER-BASED + BASE @ >R BASE ! >NUMBER R> BASE ! ; + +{ 0 0 GN' 2' 10 >NUMBER-BASED -> 2 0 GN-CONSUMED } +{ 0 0 GN' 2' 2 >NUMBER-BASED -> 0 0 GN-STRING } +{ 0 0 GN' F' 10 >NUMBER-BASED -> F 0 GN-CONSUMED } +{ 0 0 GN' G' 10 >NUMBER-BASED -> 0 0 GN-STRING } +{ 0 0 GN' G' MAX-BASE >NUMBER-BASED -> 10 0 GN-CONSUMED } +{ 0 0 GN' Z' MAX-BASE >NUMBER-BASED -> 23 0 GN-CONSUMED } + +: GN1 \ ( UD BASE -- UD' LEN ) UD SHOULD EQUAL UD' AND LEN SHOULD BE ZERO. + BASE @ >R BASE ! + <# #S #> + 0 0 2SWAP >NUMBER SWAP DROP \ RETURN LENGTH ONLY + R> BASE ! ; +{ 0 0 2 GN1 -> 0 0 0 } +{ MAX-UINT 0 2 GN1 -> MAX-UINT 0 0 } +{ MAX-UINT DUP 2 GN1 -> MAX-UINT DUP 0 } +{ 0 0 MAX-BASE GN1 -> 0 0 0 } +{ MAX-UINT 0 MAX-BASE GN1 -> MAX-UINT 0 0 } +{ MAX-UINT DUP MAX-BASE GN1 -> MAX-UINT DUP 0 } + +: GN2 \ ( -- 16 10 ) + BASE @ >R HEX BASE @ DECIMAL BASE @ R> BASE ! ; +{ GN2 -> 10 A } + +\ ------------------------------------------------------------------------ +TESTING FILL MOVE + +CREATE FBUF 00 C, 00 C, 00 C, +CREATE SBUF 12 C, 34 C, 56 C, +: SEEBUF FBUF C@ FBUF CHAR+ C@ FBUF CHAR+ CHAR+ C@ ; + +{ FBUF 0 20 FILL -> } +{ SEEBUF -> 00 00 00 } + +{ FBUF 1 20 FILL -> } +{ SEEBUF -> 20 00 00 } + +{ FBUF 3 20 FILL -> } +{ SEEBUF -> 20 20 20 } + +{ FBUF FBUF 3 CHARS MOVE -> } \ BIZARRE SPECIAL CASE +{ SEEBUF -> 20 20 20 } + +{ SBUF FBUF 0 CHARS MOVE -> } +{ SEEBUF -> 20 20 20 } + +{ SBUF FBUF 1 CHARS MOVE -> } +{ SEEBUF -> 12 20 20 } + +{ SBUF FBUF 3 CHARS MOVE -> } +{ SEEBUF -> 12 34 56 } + +{ FBUF FBUF CHAR+ 2 CHARS MOVE -> } +{ SEEBUF -> 12 12 34 } + +{ FBUF CHAR+ FBUF 2 CHARS MOVE -> } +{ SEEBUF -> 12 34 34 } + +\ ------------------------------------------------------------------------ +TESTING OUTPUT: . ." CR EMIT SPACE SPACES TYPE U. + +: OUTPUT-TEST + ." YOU SHOULD SEE THE STANDARD GRAPHIC CHARACTERS:" CR + 41 BL DO I EMIT LOOP CR + 61 41 DO I EMIT LOOP CR + 7F 61 DO I EMIT LOOP CR + ." YOU SHOULD SEE 0-9 SEPARATED BY A SPACE:" CR + 9 1+ 0 DO I . LOOP CR + ." YOU SHOULD SEE 0-9 (WITH NO SPACES):" CR + [CHAR] 9 1+ [CHAR] 0 DO I 0 SPACES EMIT LOOP CR + ." YOU SHOULD SEE A-G SEPARATED BY A SPACE:" CR + [CHAR] G 1+ [CHAR] A DO I EMIT SPACE LOOP CR + ." YOU SHOULD SEE 0-5 SEPARATED BY TWO SPACES:" CR + 5 1+ 0 DO I [CHAR] 0 + EMIT 2 SPACES LOOP CR + ." YOU SHOULD SEE TWO SEPARATE LINES:" CR + S" LINE 1" TYPE CR S" LINE 2" TYPE CR + ." YOU SHOULD SEE THE NUMBER RANGES OF SIGNED AND UNSIGNED NUMBERS:" CR + ." SIGNED: " MIN-INT . MAX-INT . CR + ." UNSIGNED: " 0 U. MAX-UINT U. CR +; + +{ OUTPUT-TEST -> } + +\ ------------------------------------------------------------------------ +TESTING INPUT: ACCEPT + +CREATE ABUF 80 CHARS ALLOT + +: ACCEPT-TEST + CR ." PLEASE TYPE UP TO 80 CHARACTERS:" CR + ABUF 80 ACCEPT + CR ." RECEIVED: " [CHAR] " EMIT + ABUF SWAP TYPE [CHAR] " EMIT CR +; + +{ ACCEPT-TEST -> } + +\ ------------------------------------------------------------------------ +TESTING DICTIONARY SEARCH RULES + +{ : GDX 123 ; : GDX GDX 234 ; -> } + +{ GDX -> 123 234 } + + +\ test suite finished. leaving engine. + +bye diff --git a/forth/bootstrap/interpreter.fs b/forth/bootstrap/interpreter.fs new file mode 100644 index 0000000..de66c5c --- /dev/null +++ b/forth/bootstrap/interpreter.fs @@ -0,0 +1,174 @@ +\ tag: forth interpreter +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + + +\ +\ 7.3.4.6 Display pause +\ + +0 value interactive? + +: exit? + interactive? 0= if + false exit + then + false \ FIXME we should check whether to interrupt output + \ and ask the user how to proceed. + ; + + +\ +\ 7.3.9.1 Defining words +\ + +: forget + s" This word is obsolescent." type cr + ['] ' execute + cell - dup + @ dup + last ! latest ! + here! + ; + +\ +\ 7.3.9.2.4 Miscellaneous dictionary +\ + +\ interpreter. This word checks whether the interpreted word +\ is a word in dictionary or a number. It honours compile mode +\ and immediate/compile-only words. + +: interpret + 0 >in ! + begin + parse-word dup 0> \ was there a word at all? + while + $find + if + dup flags? 0<> state @ 0= or if + execute + else + , \ compile mode && !immediate + then + else \ word is not known. maybe it's a number + 2dup $number + if + span @ >in ! \ if we encountered an error, don't continue parsing + type 3a emit + -13 throw + else + -rot 2drop 1 handle-lit + then + then + depth 200 >= if -3 throw then + depth 0< if -4 throw then + rdepth 200 >= if -5 throw then + rdepth 0< if -6 throw then + repeat + 2drop + ; + +: refill ( -- ) + ib #ib @ expect 0 >in ! ; + +: print-status ( exception -- ) + space + ?dup if + dup sys-debug \ system debug hook + case + -1 of s" Aborted." type endof + -2 of s" Aborted." type endof + -3 of s" Stack Overflow." type 0 depth! endof + -4 of s" Stack Underflow." type 0 depth! endof + -5 of s" Return Stack Overflow." type endof + -6 of s" Return Stack Underflow." type endof + -13 of s" undefined word." type endof + -15 of s" out of memory." type endof + -21 of s" undefined method." type endof + -22 of s" no such device." type endof + dup s" Exception #" type . + endcase + else + state @ 0= if + s" ok" + else + s" compiled" + then + type + then + cr + ; + +defer status +['] noop ['] status (to) + +: print-prompt + status + depth . 3e emit space + ; + +defer outer-interpreter +:noname + cr + begin + print-prompt + source 0 fill \ clean input buffer + refill + + ['] interpret catch print-status + again +; ['] outer-interpreter (to) + +\ +\ 7.3.8.5 Other control flow commands +\ + +: save-source ( -- ) + r> \ fetch our caller + ib >r #ib @ >r \ save current input buffer + source-id >r \ and all variables + span @ >r \ associated with it. + >in @ >r + >r \ move back our caller + ; + +: restore-source ( -- ) + r> + r> >in ! + r> span ! + r> ['] source-id (to) + r> #ib ! + r> ['] ib (to) + >r + ; + +: (evaluate) ( str len -- ??? ) + save-source + -1 ['] source-id (to) + dup + #ib ! span ! + ['] ib (to) + interpret + restore-source + ; + +: evaluate ( str len -- ?? ) + 2dup + -rot + over + over do + i c@ 0a = if + i over - + (evaluate) + i 1+ + then + loop + swap over - (evaluate) + ; + +: eval evaluate ; + + diff --git a/forth/bootstrap/memory.fs b/forth/bootstrap/memory.fs new file mode 100644 index 0000000..a37cbec --- /dev/null +++ b/forth/bootstrap/memory.fs @@ -0,0 +1,218 @@ +\ tag: forth memory allocation +\ +\ Copyright (C) 2002-2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ 7.3.3.2 memory allocation + +\ these need to be initialized by the forth kernel by now. +variable start-mem 0 start-mem ! \ start of memory +variable end-mem 0 end-mem ! \ end of memory +variable free-list 0 free-list ! \ free list head + +\ initialize necessary variables and write a valid +\ free-list entry containing all of the memory. +\ start-mem: pointer to start of memory. +\ end-mem: pointer to end of memory. +\ free-list: head of linked free list + +: init-mem ( start-addr size ) + over dup + start-mem ! \ write start-mem + free-list ! \ write first freelist entry + 2dup /n - swap ! \ write 'len' entry + over cell+ 0 swap ! \ write 'next' entry + + end-mem ! \ write end-mem + ; + +\ -------------------------------------------------------------------- + +\ return pointer to smallest free block that contains +\ at least nb bytes and the block previous the the +\ actual block. On failure the pointer to the smallest +\ free block is 0. + +: smallest-free-block ( nb -- prev ptr | 0 0 ) + 0 free-list @ + fffffff 0 0 >r >r >r + begin + dup + while + ( nb prev pp R: best_nb best_pp ) + dup @ 3 pick r@ within if + ( nb prev pp ) + r> r> r> 3drop \ drop old smallest + 2dup >r >r dup @ >r \ new smallest + then + nip dup \ prev = pp + cell + @ \ pp = pp->next + repeat + 3drop r> drop r> r> +; + + +\ -------------------------------------------------------------------- + +\ allocate size bytes of memory +\ return pointer to memory (or throws an exception on failure). + +: alloc-mem ( size -- addr ) + + \ make it legal (and fast) to allocate 0 bytes + dup 0= if exit then + + aligned \ keep memory aligned. + dup smallest-free-block \ look up smallest free block. + + dup 0= if + \ 2drop + -15 throw \ out of memory + then + + ( al-size prev addr ) + + \ If the smallest fitting block found is bigger than + \ the size of the requested block plus 2*cellsize we + \ can split the block in 2 parts. otherwise return a + \ slightly bigger block than requested. + + dup @ ( d->len ) 3 pick cell+ cell+ > if + + \ splitting the block in 2 pieces. + \ new block = old block + len field + size of requested mem + dup 3 pick cell+ + ( al-size prev addr nd ) + + \ new block len = old block len - req. mem size - 1 cell + over @ ( al-size prev addr nd addr->len ) + 4 pick ( ... al-size ) + cell+ - ( al-size prev addr nd nd nd->len ) + over ! ( al-size prev addr nd ) + + over cell+ @ ( al-size prev addr nd addr->next ) + \ write addr->next to nd->next + over cell+ ! ( al-size prev addr nd ) + over 4 pick swap ! + else + \ don't split the block, it's too small. + dup cell+ @ + then + + ( al-size prev addr nd ) + + \ If the free block we got is the first one rewrite free-list + \ pointer instead of the previous entry's next field. + rot dup 0= if drop free-list else cell+ then + ( al-size addr nd prev->next|fl ) + ! + nip cell+ \ remove al-size and skip len field of returned pointer + + ; + + +\ -------------------------------------------------------------------- + +\ free block given by addr. The length of the +\ given block is stored at addr - cellsize. +\ +\ merge with blocks to the left and right +\ immediately, if they are free. + +: free-mem ( addr len -- ) + + \ we define that it is legal to free 0-byte areas + 0= if drop exit then + ( addr ) + + \ check if the address to free is somewhere within + \ our available memory. This fails badly on discontigmem + \ architectures. If we need more RAM than fits on one + \ contiguous memory area we are too bloated anyways. ;) + + dup start-mem @ end-mem @ within 0= if + \ ." free-mem: no such memory: 0x" u. cr + exit + then + + /n - \ get real block address + 0 free-list @ ( addr prev l ) + + begin \ now scan the free list + dup 0<> if \ only check len, if block ptr != 0 + dup dup @ cell+ + 3 pick < + else + false + then + while + nip dup \ prev=l + cell+ @ \ l=l->next + repeat + + ( addr prev l ) + + dup 0<> if \ do we have free memory to merge with? + + dup dup @ cell+ + 3 pick = if \ hole hit. adding bytes. + \ freeaddr = end of current block -> merge + ( addr prev l ) + rot @ cell+ ( prev l f->len+cellsize ) + over @ + \ add l->len + over ! ( prev l ) + swap over cell+ @ \ f = l; l = l->next; + + \ The free list is sorted by addresses. When merging at the + \ start of our block we might also want to merge at the end + \ of it. Therefore we fall through to the next border check + \ instead of returning. + true \ fallthrough value + else + false \ no fallthrough + then + >r \ store fallthrough on ret stack + + ( addr prev l ) + + dup 3 pick dup @ cell+ + = if \ hole hit. real merging. + \ current block starts where block to free ends. + \ end of free block addr = current block -> merge and exit + ( addr prev l ) + 2 pick dup @ ( f f->len ) + 2 pick @ cell+ + ( f newlen ) + swap ! ( addr prev l ) + 3dup drop + 0= if + free-list + else + 2 pick cell+ + then ( value prev->next|free-list ) + ! ( addr prev l ) + cell+ @ rot ( prev l->next addr ) + cell+ ! drop + r> drop exit \ clean up return stack + then + + r> if 3drop exit then \ fallthrough? -> exit + then + + \ loose block - hang it before current. + + ( addr prev l ) + + \ hang block to free in front of the current entry. + dup 3 pick cell+ ! \ f->next = l; + free-list @ = if \ is block to free new list head? + over free-list ! + then + + ( addr prev ) + dup 0<> if \ if (prev) prev->next=f + cell+ ! + else + 2drop \ no fixup needed. clean up. + then + + ; + + diff --git a/forth/bootstrap/start.fs b/forth/bootstrap/start.fs new file mode 100644 index 0000000..9aabfa2 --- /dev/null +++ b/forth/bootstrap/start.fs @@ -0,0 +1,69 @@ +\ tag: forth bootstrap starter. +\ +\ Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +include bootstrap.fs \ all base words +include interpreter.fs \ interpreter +include builtin.fs \ builtin terminal. + +: include ( >filename -- ) + linefeed parse $include +; + +: encode-file ( >filename< > -- dictptr size ) + parse-word $encode-file +; + +: bye + s" Farewell!" cr type cr cr + 0 rdepth! + ; + +\ quit starts the outer interpreter of the forth system. +\ zech describes quit as being the outer interpreter, but +\ we split it apart to keep the interpreter elsewhere. + +: quit ( -- ) + 2 rdepth! + outer-interpreter +; + +\ initialize is the first forth word run by the kernel. +\ this word is automatically executed by the C core on start +\ and it's never left unless something goes really wrong or +\ the user decides to leave the engine. + +variable init-chain + +\ :noname ; initializer +: initializer ( xt -- ) + here swap , 0 , \ xt, next + init-chain + begin dup @ while @ na1+ repeat + ! +; + +: initialize-forth ( startmem endmem -- ) + over - init-mem + init-pockets + init-tmp-comp + init-builtin-terminal + + init-chain @ \ execute initializers + begin dup while + dup @ execute + na1+ @ + repeat + drop +; + +\ compiler entrypoint +: initialize ( startmem endmem -- ) + initialize-forth + s" OpenBIOS kernel started." type cr + quit +; diff --git a/forth/build.xml b/forth/build.xml new file mode 100644 index 0000000..7ce91f7 --- /dev/null +++ b/forth/build.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/forth/debugging/build.xml b/forth/debugging/build.xml new file mode 100644 index 0000000..3b9a0ca --- /dev/null +++ b/forth/debugging/build.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/forth/debugging/client.fs b/forth/debugging/client.fs new file mode 100644 index 0000000..151be8d --- /dev/null +++ b/forth/debugging/client.fs @@ -0,0 +1,111 @@ +\ 7.6 Client Program Debugging command group + + +\ 7.6.1 Registers display + +: ctrace ( -- ) + ; + +: .registers ( -- ) + ; + +: .fregisters ( -- ) + ; + +\ to ( param [old-name< >] -- ) + + +\ 7.6.2 Program download and execute + +: load ( "{params}" -- ) + ; + +: go ( -- ) + ; + +: state-valid ( -- a-addr ) + ; + +: init-program ( -- ) + ; + + +\ 7.6.3 Abort and resume + +\ already defined !? +\ : go ( -- ) +\ ; + + +\ 7.6.4 Disassembler + +: dis ( addr -- ) + ; + +: +dis ( -- ) + ; + +\ 7.6.5 Breakpoints +: .bp ( -- ) + ; + +: +bp ( addr -- ) + ; + +: -bp ( addr -- ) + ; + +: --bp ( -- ) + ; + +: bpoff ( -- ) + ; + +: step ( -- ) + ; + +: steps ( n -- ) + ; + +: hop ( -- ) + ; + +: hops ( n -- ) + ; + +\ already defined +\ : go ( -- ) +\ ; + +: gos ( n -- ) + ; + +: till ( addr -- ) + ; + +: return ( -- ) + ; + +: .breakpoint ( -- ) + ; + +: .step ( -- ) + ; + +: .instruction ( -- ) + ; + + +\ 7.6.6 Symbolic debugging +: .adr ( addr -- ) + ; + +: sym ( "name< >" -- n ) + ; + +: sym>value ( addr len -- addr len false | n true ) + ; + +: value>sym ( n1 -- n1 false | n2 addr len true ) + ; + diff --git a/forth/debugging/fcode.fs b/forth/debugging/fcode.fs new file mode 100644 index 0000000..2421092 --- /dev/null +++ b/forth/debugging/fcode.fs @@ -0,0 +1,31 @@ +\ 7.7 FCode Debugging command group + +\ The user interface versions of these FCode functions allow +\ the user to debug FCode programs by providing named commands +\ corresponding to FCode functions. + +: headerless ( -- ) + ; + +: headers ( -- ) + ; + +: begin-package ( arg-str arg-len reg-str reg-len dev-str dev-len -- ) + open-dev dup 0= abort" failed opening parent." + dup to my-self + ihandle>phandle active-package! + new-device + set-args +; + +: end-package ( -- ) + my-parent >r + finish-device + 0 active-package! + 0 to my-self + r> close-dev +; + +: apply ( ... "method-name< >device-specifier< >" -- ??? ) + ; + diff --git a/forth/debugging/firmware.fs b/forth/debugging/firmware.fs new file mode 100644 index 0000000..3000e51 --- /dev/null +++ b/forth/debugging/firmware.fs @@ -0,0 +1,83 @@ +\ 7.5 Firmware Debugging command group + + +\ 7.5.1 Automatic stack display + +: (.s + depth 0 ?do + depth i - 1- pick . + loop + depth 0<> if ascii < emit space then + ; + +: showstack ( -- ) + ['] (.s to status + ; + +: noshowstack ( -- ) + ['] noop to status + ; + +\ 7.5.2 Serial download + +: dl ( -- ) + ; + + +\ 7.5.3 Dictionary + +\ 7.5.3.1 Dictionary search +: .calls ( xt -- ) + ; + +: $sift ( text-addr text-len -- ) + ; + +: sifting ( "text< >" -- ) + ; + +\ : words ( -- ) +\ \ Implemented in forth bootstrap. +\ ; + + +\ 7.5.3.2 Decompiler + +\ implemented in see.fs + +\ : see ( "old-name< >" -- ) +\ ; + +\ : (see) ( xt -- ) +\ ; + + +\ 7.5.3.3 Patch + +: patch ( "new-name< >old-name< >word-to-patch< >" -- ) + ; + +: (patch) ( new-n1 num1? old-n2 num2? xt -- ) + ; + + +\ 7.5.3.4 Forth source-level debugger + +: debug ( "old-name< >" -- ) + ; + +: (debug ( xt -- ) + ; + +: stepping ( -- ) + ; + +: tracing ( -- ) + ; + +: debug-off ( -- ) + ; + +: resume ( -- ) + ; + diff --git a/forth/debugging/see.fs b/forth/debugging/see.fs new file mode 100644 index 0000000..628459d --- /dev/null +++ b/forth/debugging/see.fs @@ -0,0 +1,114 @@ +\ tag: Forth Decompiler +\ +\ this code implements IEEE 1275-1994 ch. 7.5.3.2 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +1 value (see-indent) + +: (see-cr) + cr (see-indent) spaces + ; + +: indent+ + (see-indent) 2+ to (see-indent) + ; + +: indent- + (see-indent) 2- to (see-indent) + ; + +: (see-colon) + dup ." : " cell - lfa2name type (see-cr) + begin + cell+ dup @ dup ['] (semis) <> + while + space + dup + case + + ['] do?branch of + ." if" (see-cr) indent+ + drop cell+ + endof + + ['] dobranch of + ." then" indent- (see-cr) + drop cell+ + endof + + ['] (begin) of + ." begin" indent+ (see-cr) + drop + endof + + ['] (again) of + ." again" (see-cr) + drop + endof + + ['] (until) of + ." until" (see-cr) + drop + endof + + ['] (while) of + indent- (see-cr) + ." while" + indent+ (see-cr) + drop 2 cells + + endof + + ['] (repeat) of + indent- (see-cr) + ." repeat" + (see-cr) + drop 2 cells + + endof + + ['] (lit) of + ." (lit)" + drop 1 cells + + endof + + ['] (") of + 22 emit space drop dup cell+ @ + 2dup swap 2 cells + swap type + 22 emit + + aligned cell+ + endof + + cell - lfa2name type + endcase + repeat + cr ." ;" + 2drop + ; + +: (see) ( xt -- ) + cr + dup @ case + 1 of + (see-colon) + endof + 3 of + ." constant " dup cell - lfa2name type ." = " execute . + endof + 4 of + ." variable " dup cell - lfa2name type ." = " execute @ . + endof + 5 of + ." defer " dup cell - lfa2name type cr + ." is " cell+ @ cell - lfa2name type cr + endof + ." primword " swap cell - lfa2name type + endcase + cr + ; + +: see ' (see) ; + diff --git a/forth/device/README.device b/forth/device/README.device new file mode 100644 index 0000000..4232829 --- /dev/null +++ b/forth/device/README.device @@ -0,0 +1,23 @@ +The code you find here implements the IEEE 1275-1994 Open Firmware +device interface. + +Chapter File Comment + structures.fs generic structures used by 5.3 +5.3.2 defined in user interface +5.3.3 fcode.fs complete, partly untested +5.3.4 package.fs incomplete +5.3.5 property.fs incomplete +5.3.6 display.fs incomplete +5.3.7 other.fs incomplete + +H2 and +5.3.1.1.1 preof.fs pre-IEEE-1275-1994 words + split.fs + pathres.fs path resolution + + table.fs fcode evaluator + feval.fs (byte-load) + + +2003/11/12 Stefan Reinauer + diff --git a/forth/device/build.xml b/forth/device/build.xml new file mode 100644 index 0000000..1154496 --- /dev/null +++ b/forth/device/build.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forth/device/builtin.fs b/forth/device/builtin.fs new file mode 100644 index 0000000..4b57551 --- /dev/null +++ b/forth/device/builtin.fs @@ -0,0 +1,32 @@ +\ tag: builtin devices +\ +\ this code implements IEEE 1275-1994 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ nodes it's children: + +" /" find-device + +new-device + " builtin" device-name + external + : open true ; + : close ; + +new-device + " console" device-name + external + : open true ; + : close ; + : write dup >r bounds ?do i c@ (emit) loop r> ; + : read dup >r bounds ?do (key) i c! loop r> ; +finish-device + +\ clean up afterwards +finish-device +0 active-package! diff --git a/forth/device/device.fs b/forth/device/device.fs new file mode 100644 index 0000000..708bfa0 --- /dev/null +++ b/forth/device/device.fs @@ -0,0 +1,191 @@ +\ tag: Package creation and deletion +\ +\ this code implements IEEE 1275-1994 +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +variable device-tree + +\ make defined words globally visible +\ +: external ( -- ) + active-package ?dup if + >dn.methods @ set-current + then +; + +\ make the private wordlist active (not an OF word) +\ +: private ( -- ) + active-package ?dup if + >r + forth-wordlist r@ >dn.methods @ r@ >dn.priv-methods @ 3 set-order + r> >dn.priv-methods @ set-current + then +; + +\ set activate package and make the world visible package wordlist +\ the current one. +\ +: active-package! ( phandle -- ) + dup to active-package + \ locally defined words are not available + ?dup if + forth-wordlist over >dn.methods @ 2 set-order + >dn.methods @ set-current + else + forth-wordlist dup 1 set-order set-current + then +; + + +\ new-device ( -- ) +\ +\ Start new package, as child of active package. +\ Create a new device node as a child of the active package and make the +\ new node the active package. Create a new instance and make it the current +\ instance; the instance that invoked new-device becomes the parent instance +\ of the new instance. +\ Subsequently, newly defined Forth words become the methods of the new node +\ and newly defined data items (such as types variable, value, buffer:, and +\ defer) are allocated and stored within the new instance. + +: new-device ( -- ) + align-tree dev-node.size alloc-tree >r + active-package + dup r@ >dn.parent ! + + \ ( parent ) hook up at the end of the peer list + ?dup if + >dn.child + begin dup @ while @ >dn.peer repeat + r@ swap ! + else + \ we are the root node! + r@ to device-tree + then + + \ ( -- ) fill in device node stuff + inst-node.size r@ >dn.isize ! + + \ create two wordlists + wordlist r@ >dn.methods ! + wordlist r@ >dn.priv-methods ! + + \ initialize template data + r@ >dn.itemplate + r@ over >in.device-node ! + my-self over >in.my-parent ! + + \ make it the active package and current instance + to my-self + r@ active-package! + + \ swtich to private wordlist + private + r> drop +; + +\ helpers for finish-device (OF does not actually define words +\ for device node deletion) + +: (delete-device) \ ( phandle ) + >r + r@ >dn.parent @ + ?dup if + >dn.child \ ( &first-child ) + begin dup @ r@ <> while @ >dn.peer repeat + r@ >dn.peer @ swap ! + else + \ root node + 0 to device-tree + then + + \ XXX: free any memory related to this node. + \ we could have a list with free device-node headers... + r> drop +; + +: delete-device \ ( phandle ) + >r + \ first, get rid of any children + begin r@ >dn.child @ dup while + (delete-device) + repeat + drop + + \ then free this node + r> (delete-device) +; + +\ finish-device ( -- ) +\ +\ Finish this package, set active package to parent. +\ Complete a device node that was created by new-device, as follows: If the +\ device node has no "name" property, remove the device node from the device +\ tree. Otherwise, save the current values of the current instance's +\ initialized data items within the active package for later use in +\ initializing the data items of instances created from that node. In any +\ case, destroy the current instance, make its parent instance the current +\ instance, and select the parent node of the device node just completed, +\ making the parent node the active package again. + +: finish-device \ ( -- ) + my-self + dup >in.device-node @ >r + >in.my-parent @ to my-self + + ( -- ) + r@ >dn.parent @ active-package! + s" name" r@ get-package-property if + \ delete the node (and any children) + r@ delete-device + else + 2drop + \ node OK + then + r> drop +; + + +\ helper function which creates and initializes an instance. +\ open is not called. The current instance is not changed. +\ +: create-instance ( phandle -- ihandle|0 ) + dup >dn.isize @ ['] alloc-mem catch if 2drop 0 exit then + >r + \ we need to save the size in order to be able to release it properly + dup >dn.isize @ r@ >in.alloced-size ! + + \ clear memory (we only need to clear the head; all other data is copied) + r@ inst-node.size 0 fill + + ( phandle R: ihandle ) + + \ instantiate data + dup >dn.methods @ r@ instance-init + dup >dn.priv-methods @ r@ instance-init + + \ instantiate + dup >dn.itemplate r@ inst-node.size move + r@ r@ >in.instance-data ! + my-self r@ >in.my-parent ! + drop + + r> +; + +\ helper function which tears down and frees an instance +: destroy-instance ( ihandle ) + ?dup if + \ free arguments + dup >in.arguments 2@ free-mem + \ and the instance block + dup >in.alloced-size @ + free-mem + then +; diff --git a/forth/device/display.fs b/forth/device/display.fs new file mode 100644 index 0000000..f056754 --- /dev/null +++ b/forth/device/display.fs @@ -0,0 +1,367 @@ +\ tag: Display device management +\ +\ this code implements IEEE 1275-1994 ch. 5.3.6 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +hex + +\ +\ 5.3.6.1 Terminal emulator routines +\ + +\ The following values are used and set by the terminal emulator +\ defined and described in 3.8.4.2 +0 value line# ( -- line# ) +0 value column# ( -- column# ) +0 value inverse? ( -- white-on-black? ) +0 value inverse-screen? ( -- black? ) +0 value #lines ( -- rows ) +0 value #columns ( -- columns ) + +\ The following values are used internally by both the 1-bit and the +\ 8-bit frame-buffer support routines. + +0 value frame-buffer-adr ( -- addr ) +0 value screen-height ( -- height ) +0 value screen-width ( -- width ) +0 value window-top ( -- border-height ) +0 value window-left ( -- border-width ) +0 value char-height ( -- height ) +0 value char-width ( -- width ) +0 value fontbytes ( -- bytes ) + +\ these values are used internally and do not represent any +\ official open firmware words +0 value char-min +0 value char-num +0 value font + +0 value foreground-color +0 value background-color + + +\ The following wordset is called the "defer word interface" of the +\ terminal-emulator support package. It gets overloaded by fb1-install +\ or fb8-install (initiated by the framebuffer fcode driver) + +defer draw-character ( char -- ) +defer reset-screen ( -- ) +defer toggle-cursor ( -- ) +defer erase-screen ( -- ) +defer blink-screen ( -- ) +defer invert-screen ( -- ) +defer insert-characters ( n -- ) +defer delete-characters ( n -- ) +defer insert-lines ( n -- ) +defer delete-lines ( n -- ) +defer draw-logo ( line# addr width height -- ) + +defer fb-emit ( x -- ) + +\ +\ 5.3.6.2 Frame-buffer support routines +\ + +: default-font ( -- addr width height advance min-char #glyphs ) + (romfont-8x16) 8 10 10 0 100 + ; + +: set-font ( addr width height advance min-char #glyphs -- ) + to char-num + to char-min + to fontbytes + to char-height + to char-width + to font + ; + +: >font ( char -- addr ) + char-min - + char-num min + fontbytes * + font + + ; + +\ +\ 5.3.6.3 Display device support +\ + +\ +\ 5.3.6.3.1 Frame-buffer package interface +\ + +: is-install ( xt -- ) + external + \ Create open and other methods for this display device. + \ Methods to be created: open, write, draw-logo, restore + s" open" header + 1 , \ colon definition + , + ['] (semis) , + reveal + s" : write dup >r bounds do i c@ fb-emit loop r> ; " evaluate + s" : draw-logo draw-logo ; " evaluate + s" : restore reset-screen ; " evaluate + ; + +: is-remove ( xt -- ) + external + \ Create close method for this display device. + s" close" header + 1 , \ colon definition + , + ['] (semis) , + reveal + ; + +: is-selftest ( xt -- ) + external + \ Create selftest method for this display device. + s" selftest" header + 1 , \ colon definition + , + ['] (semis) , + reveal + ; + + +\ 5.3.6.3.2 Generic one-bit frame-buffer support (optional) + +: fb1-nonimplemented + ." Monochrome framebuffer support is not implemented." cr + end0 + ; + +: fb1-draw-character fb1-nonimplemented ; \ historical +: fb1-reset-screen fb1-nonimplemented ; +: fb1-toggle-cursor fb1-nonimplemented ; +: fb1-erase-screen fb1-nonimplemented ; +: fb1-blink-screen fb1-nonimplemented ; +: fb1-invert-screen fb1-nonimplemented ; +: fb1-insert-characters fb1-nonimplemented ; +: fb1-delete-characters fb1-nonimplemented ; +: fb1-insert-lines fb1-nonimplemented ; +: fb1-delete-lines fb1-nonimplemented ; +: fb1-slide-up fb1-nonimplemented ; +: fb1-draw-logo fb1-nonimplemented ; +: fb1-install fb1-nonimplemented ; + + +\ 5.3.6.3.3 Generic eight-bit frame-buffer support + +\ The following two functions are unrolled for speed. + + +\ blit 8 continuous pixels described by the 8bit +\ value in bitmask8. The most significant bit is +\ painted first. + +\ this function should honour fg and bg colors + +: fb8-write-mask8 ( bitmask8 faddr -- ) + over 1 and 0<> over 7 + c! + over 2 and 0<> over 6 + c! + over 4 and 0<> over 5 + c! + over 8 and 0<> over 4 + c! + over 10 and 0<> over 3 + c! + over 20 and 0<> over 2 + c! + over 40 and 0<> over 1 + c! + over 80 and 0<> over 0 + c! + 2drop + ; + +: fb8-blitmask ( fbaddr mask-addr width height -- ) + over >r \ save width ( -- R: width ) + * 3 >> \ fbaddr mask-addr width*height/8 + bounds \ fbaddr mask-end mask + r> 0 2swap \ fbaddr width 0 mask-end mask + ?do \ ( fbaddr width l-cnt ) + 2 pick over + \ fbaddr-current + i c@ \ bitmask8 + swap fb8-write-mask8 + ( fbaddr width l-cnt ) + 8 + 2dup = if + drop swap screen-width + + swap 0 + then + ( fbaddr width l-cnt ) + loop + 2drop drop + ; + +: fb8-line2addr ( line -- addr ) + window-top + + screen-width * + frame-buffer-adr + + window-left + +; + +: fb8-copy-line ( from to -- ) + fb8-line2addr swap + fb8-line2addr swap + #columns char-width * move +; + +: fb8-clear-line ( line -- ) + fb8-line2addr + #columns char-width * + background-color fill +\ 0 fill +; + +: fb8-draw-character ( char -- ) + \ draw the character: + >font + line# char-height * window-top + screen-width * + column# char-width * window-left + + frame-buffer-adr + + swap char-width char-height + fb8-blitmask + \ now advance the position + column# 1+ + dup #columns = if + drop 0 to column# + line# 1+ + dup #lines = if + drop + \ FIXME move up screen (and keep position) + else + to #lines + then + else + to column# + then + ; + +: fb8-reset-screen ( -- ) + false to inverse? + false to inverse-screen? + 0 to foreground-color + d# 15 to background-color + ; + +: fb8-toggle-cursor ( -- ) + line# char-height * window-top + screen-width * + column# char-width * window-left + + frame-buffer-adr + + char-height 0 ?do + char-width 0 ?do + dup i + dup c@ invert ff and swap c! + loop + screen-width + + loop + drop + ; + +: fb8-erase-screen ( -- ) + frame-buffer-adr + screen-height screen-width * + inverse-screen? if + foreground-color + else + background-color + then + fill + ; + +: fb8-invert-screen ( -- ) + frame-buffer-adr + screen-height screen-width * + bounds ?do + i c@ case + foreground-color of background-color endof + background-color of foreground-color endof + dup + endcase + i c! + loop + ; + +: fb8-blink-screen ( -- ) + fb8-invert-screen fb8-invert-screen + ; + +: fb8-insert-characters ( n -- ) + ; + +: fb8-delete-characters ( n -- ) + ; + +: fb8-insert-lines ( n -- ) + ; + +: fb8-delete-lines ( n -- ) + \ numcopy = ( #lines - ( line# + n )) * char-height + #lines over #line + - char-height * + + ( numcopy ) 0 ?do + dup line# + char-height * i + + line# char-height * i + + swap fb8-copy-line + loop + + #lines over - char-height * + over char-height * + 0 ?do + dup i + fb8-clear-line + loop + + 2drop +; + + +: fb8-draw-logo ( line# addr width height -- ) + 2swap swap + char-height * window-top + + screen-width * window-left + + frame-buffer-adr + + swap 2swap + \ in-fb-start-adr logo-adr logo-width logo-height + + fb8-blitmask ( fbaddr mask-addr width height -- ) +; + + +: fb8-install ( width height #columns #lines -- ) + + \ set state variables + to #lines + to #columns + to screen-height + to screen-width + + screen-width #columns char-width * - 2/ to window-left + screen-height #lines char-height * - 2/ to window-top + + 0 to column# + 0 to line# + 0 to inverse? + 0 to inverse-screen? + + \ set defer functions to 8bit versions + + ['] fb8-draw-character to draw-character + ['] fb8-toggle-cursor to toggle-cursor + ['] fb8-erase-screen to erase-screen + ['] fb8-blink-screen to blink-screen + ['] fb8-invert-screen to invert-screen + ['] fb8-insert-characters to insert-characters + ['] fb8-delete-characters to delete-characters + ['] fb8-insert-lines to insert-lines + ['] fb8-delete-lines to delete-lines + ['] fb8-draw-logo to draw-logo + ['] fb8-reset-screen to reset-screen + + \ recommended practice + s" iso6429-1983-colors" get-my-property if + 0 ff + else + 2drop d# 15 0 + then + to foreground-color to background-color + +; + diff --git a/forth/device/extra.fs b/forth/device/extra.fs new file mode 100644 index 0000000..9ca6b78 --- /dev/null +++ b/forth/device/extra.fs @@ -0,0 +1,103 @@ +\ tag: Useful device related functions +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + + +: parent ( phandle -- parent.phandle|0 ) + >dn.parent @ +; + +\ ------------------------------------------------------------------- +\ property helpers +\ ------------------------------------------------------------------- + +: int-property ( value name-str name-len -- ) + rot encode-int 2swap property +; + +\ ------------------------------------------------------------------------- +\ property utils +\ ------------------------------------------------------------------------- + +\ like property (except it takes a phandle as an argument) +: encode-property ( buf len propname propname-len phandle -- ) + dup 0= abort" null phandle" + + my-self >r 0 to my-self + active-package >r active-package! + + property + + r> active-package! + r> to my-self +; + +\ ------------------------------------------------------------------- +\ device tree iteration +\ ------------------------------------------------------------------- + +: iterate-tree ( phandle -- phandle|0 ) + ?dup 0= if device-tree @ exit then + + \ children first + dup child if + child exit + then + + \ then peers + dup peer if + peer exit + then + + \ then peer of a parent + begin >dn.parent @ dup while + dup peer if peer exit then + repeat +; + +: iterate-tree-begin ( -- first_node ) + device-tree @ +; + + +\ ------------------------------------------------------------------- +\ device tree iteration +\ ------------------------------------------------------------------- + +: iterate-device-type ( lastph|0 type-str type-len -- 0|nextph ) + rot + begin iterate-tree ?dup while + >r + 2dup " device_type" r@ get-package-property if 0 0 then + dup 0> if 1- then + strcmp 0= if 2drop r> exit then + r> + repeat + 2drop 0 +; + +\ ------------------------------------------------------------------- +\ device tree "cut and paste" +\ ------------------------------------------------------------------- + +\ add a subtree to the current device node +: link-nodes ( phandle -- ) + \ reparent phandle and peers + dup begin ?dup while + dup >dn.parent active-package ! + >dn.peer @ + repeat + + \ add to list of children + active-package >dn.child + begin dup @ while @ >dn.peer repeat dup . ! +; + +: link-node ( phandle -- ) + 0 over >dn.peer ! + link-nodes +; diff --git a/forth/device/fcode.fs b/forth/device/fcode.fs new file mode 100644 index 0000000..17bf8f0 --- /dev/null +++ b/forth/device/fcode.fs @@ -0,0 +1,521 @@ +\ tag: FCode implementation functions +\ +\ this code implements IEEE 1275-1994 ch. 5.3.3 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +hex + +0 value fcode-sys-table \ table with built-in fcodes (0-0x7ff) + +true value ?fcode-offset16 \ fcode offsets are 16 instead of 8 bit? +1 value fcode-spread \ fcode spread (1, 2 or 4) +0 value fcode-table \ pointer to fcode table +false value ?fcode-verbose \ do verbose fcode execution? + +defer _fcode-debug? \ If true, save names for FCodes with headers +true value fcode-headers? \ If true, possibly save names for FCodes. + +0 value fcode-stream-start \ start address of fcode stream +0 value fcode-stream \ current fcode stream address + +variable fcode-end \ state variable, if true, fcode program terminates. +defer fcode-c@ \ get byte + +: fcode-push-state ( -- ) + ?fcode-offset16 + fcode-spread + fcode-table + fcode-headers? + fcode-stream-start + fcode-stream + fcode-end @ + ['] fcode-c@ behavior +; + +: fcode-pop-state ( -- ) + to fcode-c@ + fcode-end ! + to fcode-stream + to fcode-stream-start + to fcode-headers? + to fcode-table + to fcode-spread + to ?fcode-offset16 +; + +\ +\ fcode access helper functions +\ + +\ fcode-ptr +\ convert FCode number to pointer to xt in FCode table. + +: fcode-ptr ( u16 -- *xt ) + cells + fcode-table ?dup if + exit then + + \ we are not parsing fcode at the moment + dup 800 cells u>= abort" User FCODE# referenced." + fcode-sys-table + +; + +\ fcode>xt +\ get xt according to an FCode# + +: fcode>xt ( u16 -- xt ) + fcode-ptr @ + ; + +\ fcode-num8 +\ get 8bit from FCode stream, taking spread into regard. + +: fcode-num8 ( -- c ) ( F: c -- ) + fcode-stream + dup fcode-spread + to fcode-stream + fcode-c@ + ; + +\ fcode-num16 +\ get 16bit from FCode stream + +: fcode-num16 ( -- num16 ) + fcode-num8 fcode-num8 swap bwjoin + ; + +\ fcode-num32 +\ get 32bit from FCode stream + +: fcode-num32 ( -- num32 ) + fcode-num8 fcode-num8 + fcode-num8 fcode-num8 + swap 2swap swap bljoin + ; + +\ fcode# +\ Get an FCode# from FCode stream + +: fcode# ( -- fcode# ) + fcode-num8 + dup 1 f between if + fcode-num8 swap bwjoin + then + ; + +\ fcode-offset +\ get offset from FCode stream. + +: fcode-offset ( -- offset ) + ?fcode-offset16 if + fcode-num16 + else + fcode-num8 + then + ; + +\ fcode-string +\ get a string from FCode stream, store in pocket. + +: fcode-string ( -- addr len ) + pocket dup + fcode-num8 + dup rot c! + 2dup bounds ?do + fcode-num8 i c! + loop + ; + +\ fcode-header +\ retrieve FCode header from FCode stream + +: fcode-header + fcode-num8 + fcode-num16 + fcode-num32 + ?fcode-verbose if + ." Found FCode header:" cr rot + ." Format : " u. cr swap + ." Checksum : " u. cr + ." Length : " u. cr + else + 3drop + then + \ TODO checksum + ; + +\ writes currently created word as fcode# read from stream +\ + +: fcode! ( F:FCode# -- ) + here fcode# fcode-ptr ! + ; + + +\ +\ 5.3.3.1 Defining new FCode functions. +\ + +\ instance ( -- ) +\ Mark next defining word as instance specific. +\ (defined in bootstrap.fs) + +\ instance-init ( wid buffer -- ) +\ Copy template from specified wordlist to instance +\ + +: instance-init + swap + begin @ dup 0<> while + dup /n + @ instance-cfa? if \ buffer dict + 2dup 2 /n* + @ + \ buffer dict dest + over 3 /n* + @ \ buffer dict dest size + 2 pick 4 /n* + \ buffer dict dest size src + -rot + move + then + repeat + 2drop + ; + + +\ new-token ( F:/FCode#/ -- ) +\ Create a new unnamed FCode function + +: new-token + 0 0 header + fcode! + ; + + +\ named-token (F:FCode-string FCode#/ -- ) +\ Create a new possibly named FCode function. + +: named-token + fcode-string + _fcode-debug? not if + 2drop 0 0 + then + header + fcode! + ; + + +\ external-token (F:/FCode-string FCode#/ -- ) +\ Create a new named FCode function + +: external-token + fcode-string header + fcode! + ; + + +\ b(;) ( -- ) +\ End an FCode colon definition. + +: b(;) + ['] ; execute + ; immediate + + +\ b(:) ( -- ) ( E: ... -- ??? ) +\ Defines type of new FCode function as colon definition. + +: b(:) + 1 , ] + ; + + +\ b(buffer:) ( size -- ) ( E: -- a-addr ) +\ Defines type of new FCode function as buffer:. + +: b(buffer:) + 4 , allot + reveal + ; + +\ b(constant) ( nl -- ) ( E: -- nl ) +\ Defines type of new FCode function as constant. + +: b(constant) + 3 , , + reveal + ; + + +\ b(create) ( -- ) ( E: -- a-addr ) +\ Defines type of new FCode function as create word. + +: b(create) + 6 , + ['] noop , + reveal + ; + + +\ b(defer) ( -- ) ( E: ... -- ??? ) +\ Defines type of new FCode function as defer word. + +: b(defer) + 5 , + ['] (undefined-defer) , + ['] (semis) , + reveal + ; + + +\ b(field) ( offset size -- offset+size ) ( E: addr -- addr+offset ) +\ Defines type of new FCode function as field. + +: b(field) + $create + over , + + + does> + @ + + ; + + +\ b(value) ( x -- ) (E: -- x ) +\ Defines type of new FCode function as value. + +: b(value) + 3 , , reveal + ; + + +\ b(variable) ( -- ) ( E: -- a-addr ) +\ Defines type of new FCode function as variable. + +: b(variable) + 4 , 0 , + reveal + ; + + +\ (is-user-word) ( name-str name-len xt -- ) ( E: ... -- ??? ) +\ Create a new named user interface command. + +: (is-user-word) + ; + + +\ get-token ( fcode# -- xt immediate? ) +\ Convert FCode number to function execution token. + +: get-token + fcode>xt dup immediate? + ; + + +\ set-token ( xt immediate? fcode# -- ) +\ Assign FCode number to existing function. + +: set-token + nip \ TODO we use the xt's immediate state for now. + fcode-ptr ! + ; + + + + +\ +\ 5.3.3.2 Literals +\ + + +\ b(lit) ( -- n1 ) +\ Numeric literal FCode. Followed by FCode-num32. + +: b(lit) + fcode-num32 + state @ if + ['] (lit) , , + then + ; immediate + + +\ b(') ( -- xt ) +\ Function literal FCode. Followed by FCode# + +: b(') + fcode# fcode>xt + state @ if + ['] (lit) , , + then + ; immediate + + +\ b(") ( -- str len ) +\ String literal FCode. Followed by FCode-string. + +: b(") + fcode-string + state @ if + \ only run handle-text in compile-mode, + \ otherwise we would waste a pocket. + handle-text + then + ; immediate + + +\ +\ 5.3.3.3 Controlling values and defers +\ + +\ behavior ( defer-xt -- contents-xt ) +\ defined in bootstrap.fs + +\ b(to) ( new-value -- ) +\ FCode for setting values and defers. Followed by FCode#. + +: b(to) + fcode# fcode>xt + 1 handle-lit + ['] (to) + state @ if + , + else + execute + then + ; immediate + + + +\ +\ 5.3.3.4 Control flow +\ + + +\ offset16 ( -- ) +\ Makes subsequent FCode-offsets use 16-bit (not 8-bit) form. + +: offset16 + true to ?fcode-offset16 + ; + + +\ bbranch ( -- ) +\ Unconditional branch FCode. Followed by FCode-offset. + +: bbranch + ['] dobranch , + fcode-offset 0< if \ if we jump backwards, we can forsee where it goes + resolve-dest + else + here + 0 , + then + ; immediate + + +\ b?branch ( continue? -- ) +\ Conditional branch FCode. Followed by FCode-offset. + +: b?branch + ['] do?branch , + fcode-offset 0< if \ if we jump backwards, we can forsee where it goes + resolve-dest + else + here + 0 , + then + ; immediate + + +\ b(resolve) ( -- ) +\ Target of forward branches. + +: b(>resolve) + resolve-orig + ; immediate + + +\ b(loop) ( -- ) +\ End FCode do..loop. Followed by FCode-offset. + +: b(loop) + fcode-offset drop + postpone loop + ; immediate + + +\ b(+loop) ( delta -- ) +\ End FCode do..+loop. Followed by FCode-offset. + +: b(+loop) + fcode-offset drop + postpone +loop + ; immediate + + +\ b(do) ( limit start -- ) +\ Begin FCode do..loop. Followed by FCode-offset. + +: b(do) + fcode-offset drop + postpone do + ; immediate + + +\ b(?do) ( limit start -- ) +\ Begin FCode ?do..loop. Followed by FCode-offset. + +: b(?do) + fcode-offset drop + postpone ?do + ; immediate + + +\ b(leave) ( -- ) +\ Exit from a do..loop. + +: b(leave) + postpone leave + ; immediate + + +\ b(case) ( sel -- sel ) +\ Begin a case (multiple selection) statement. + +: b(case) + postpone case + ; immediate + + +\ b(endcase) ( sel | -- ) +\ End a case (multiple selection) statement. + +: b(endcase) + postpone endcase + ; immediate + + +\ b(of) ( sel of-val -- sel | ) +\ FCode for of in case statement. Followed by FCode-offset. + +: b(of) + fcode-offset drop + postpone of + ; immediate + +\ b(endof) ( -- ) +\ FCode for endof in case statement. Followed by FCode-offset. + +: b(endof) + fcode-offset drop + postpone endof + ; immediate + + diff --git a/forth/device/feval.fs b/forth/device/feval.fs new file mode 100644 index 0000000..e603da2 --- /dev/null +++ b/forth/device/feval.fs @@ -0,0 +1,82 @@ +\ tag: FCode evaluator +\ +\ this code implements an fcode evaluator +\ as described in IEEE 1275-1994 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +defer init-fcode-table + +: alloc-fcode-table + 4096 cells alloc-mem to fcode-table + ?fcode-verbose if + ." fcode-table at 0x" fcode-table . cr + then + init-fcode-table + ; + +: free-fcode-table + fcode-table 4096 cells free-mem + 0 to fcode-table + ; + +: (debug-feval) ( fcode# -- fcode# ) + dup fcode>xt cell - lfa2name type + dup ." [ 0x" . ." ]" cr + ; + +: (feval) ( -- ?? ) + begin + fcode# + ?fcode-verbose if + (debug-feval) + then + fcode>xt + dup flags? 0<> state @ 0= or if + execute + else + , + then + fcode-end @ until +; + +: byte-load ( addr xt -- ) + ?fcode-verbose if + cr ." byte-load: evaluating fcode at 0x" over . cr + then + + \ save state + >r >r fcode-push-state r> r> + + \ set fcode-c@ defer + dup 1 = if drop ['] c@ then \ FIXME: uses c@ rather than rb@ for now... + to fcode-c@ + dup to fcode-stream-start + to fcode-stream + 1 to fcode-spread + false to ?fcode-offset16 + alloc-fcode-table + false fcode-end ! + + \ protect against stack overflow/underflow + 0 0 0 0 0 0 depth >r + + ['] (feval) catch if + cr ." byte-load: exception caught!" cr + then + + depth r@ <> if + cr ." byte-load: stack overflow, diff " depth r@ - . cr + then + + r> depth! 3drop 3drop + + free-fcode-table + + \ restore state + fcode-pop-state +; diff --git a/forth/device/font.fs b/forth/device/font.fs new file mode 100644 index 0000000..00538ae --- /dev/null +++ b/forth/device/font.fs @@ -0,0 +1,13 @@ +\ tag: 8x16 bitmap font +\ +\ Terminus font +\ +\ The Terminus Font is developed by and is a property +\ of Dimitar Toshkov Zhekov +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +encode-file romfont.bin +drop value (romfont-8x16) diff --git a/forth/device/logo.fs b/forth/device/logo.fs new file mode 100644 index 0000000..4867470 --- /dev/null +++ b/forth/device/logo.fs @@ -0,0 +1,99 @@ +\ tag: monochrome logo +\ +\ simple monochrome logo +\ as described in IEEE 1275-1994 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + + +\ FIXME : This is currently just a test file, it contains +\ a Pi symbol of size 64x64, not really nicely streched. + +\ To use an XBM (X Bitmap), the bits in the bitmap array +\ have to be reversed, i.e. like this: +\ +\ int main(void) +\ { +\ int i,j; unsigned char bit, bitnew; +\ for (i=0; i<512; i++) { +\ bit=openbios_bits[i]; bitnew=0; +\ for (j=0; j<8; j++) +\ if (bit & (1<font + * is-install + * is-remove + * is-selftest + +5.3.7 Other + * cpeek + * wpeek + * lpeek + * cpoke + * wpoke + * lpoke + * rb@ + * rw@ + * rl@ + * rb! + * rw! + * rl! + * get-msecs + * ms + * alarm + * user-abort + * mac-address + * display-status + * memory-test-suite + * mask + * diagnostic-mode? + * suspend-fcode + * set-args + diff --git a/forth/device/other.fs b/forth/device/other.fs new file mode 100644 index 0000000..0d88d21 --- /dev/null +++ b/forth/device/other.fs @@ -0,0 +1,179 @@ +\ tag: Other FCode functions +\ +\ this code implements IEEE 1275-1994 ch. 5.3.7 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ +\ 5.3.7 Other FCode functions +\ + +hex + +\ 5.3.7.1 Peek/poke + +: cpeek ( addr -- false | byte true ) + ; + +: wpeek ( waddr -- false | w true ) + ; + +: lpeek ( qaddr -- false | quad true ) + ; + +: cpoke ( byte addr -- okay? ) + ; + +: wpoke ( w waddr -- okay? ) + ; + +: lpoke ( quad qaddr -- okay? ) + ; + + +\ 5.3.7.2 Device-register access + +: rb@ ( addr -- byte ) + ; + +: rw@ ( waddr -- w ) + ; + +: rl@ ( qaddr -- quad ) + ; + +: rb! ( byte addr -- ) + ; + +: rw! ( w waddr -- ) + ; + +: rl! ( quad qaddr -- ) + ; + + +\ 5.3.7.3 Time + +: get-msecs ( -- n ) + ; + +: ms ( n -- ) + ; + +: alarm ( xt n -- ) + ; + +: user-abort ( ... -- ) ( R: ... -- ) + ; + + +\ 5.3.7.4 System information +0003.0000 value fcode-revision ( -- n ) + +: mac-address ( -- mac-str mac-len ) + ; + + +\ 5.3.7.5 FCode self-test +: display-status ( n -- ) + ; + +: memory-test-suite ( addr len -- fail? ) + ; + +: mask ( -- a-addr ) + ; + +: diagnostic-mode? ( -- diag? ) + ; + +\ 5.3.7.6 Start and end. + +\ Begin program with spread 0 followed by FCode-header. +: start0 ( -- ) + 0 fcode-spread ! + offset16 + fcode-header + ; + +\ Begin program with spread 1 followed by FCode-header. +: start1 ( -- ) + 1 to fcode-spread + offset16 + fcode-header + ; + +\ Begin program with spread 2 followed by FCode-header. +: start2 ( -- ) + 2 to fcode-spread + offset16 + fcode-header + ; + +\ Begin program with spread 4 followed by FCode-header. +: start4 ( -- ) + 4 to fcode-spread + offset16 + fcode-header + ; + +\ Begin program with spread 1 followed by FCode-header. +: version1 ( -- ) + 1 to fcode-spread + fcode-header + ; + +\ Cease evaluating this FCode program. +: end0 ( -- ) + true fcode-end ! + ; + +\ Cease evaluating this FCode program. +: end1 ( -- ) + end0 + ; + +\ Standard FCode number for undefined FCode functions. +: ferror ( -- ) + ." undefined fcode# encountered." cr + true fcode-end ! + ; + +\ Pause FCode evaluation if desired; can resume later. +: suspend-fcode ( -- ) + \ NOT YET IMPLEMENTED. + ; + + +\ Evaluate FCode beginning at location addr. + +\ : byte-load ( addr xt -- ) +\ \ this word is implemented in feval.fs +\ ; + +\ Set address and arguments of new device node. +: set-args ( arg-str arg-len unit-str unit-len -- ) + ?my-self drop + + depth 1- >r + " decode-unit" ['] $call-parent catch if + 2drop 2drop + then + + my-self ihandle>phandle >dn.probe-addr \ offset + begin depth r@ > while + dup na1+ >r ! r> + repeat + r> 2drop + + my-self >in.arguments 2@ free-mem + strdup my-self >in.arguments 2! +; + +: dma-alloc + s" dma-alloc" $call-parent + ; diff --git a/forth/device/package.fs b/forth/device/package.fs new file mode 100644 index 0000000..0e1bb21 --- /dev/null +++ b/forth/device/package.fs @@ -0,0 +1,256 @@ +\ tag: Package access. +\ +\ this code implements IEEE 1275-1994 ch. 5.3.4 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ variable last-package 0 last-package ! +\ 0 value active-package + + +\ +\ 5.3.4.1 Open/Close packages (part 1) +\ + +\ 0 value my-self ( -- ihandle ) +: ?my-self + my-self dup 0= abort" no current instance." + ; + +: my-parent ( -- ihandle ) + ?my-self >in.my-parent @ +; + +: ihandle>phandle ( ihandle -- phandle ) + >in.device-node @ +; + +\ next-property +\ defined in property.c + +: peer ( phandle -- phandle.sibling ) + ?dup if + >dn.peer @ + else + device-tree @ + then +; + +: child ( phandle.parent -- phandle.child ) + >dn.child @ +; + + +\ +\ 5.3.4.2 Call methods from other packages +\ + +: find-method ( method-str method-len phandle -- false | xt true ) + \ should we search the private wordlist too? I don't think so... + >dn.methods @ find-wordlist if + true + else + 2drop false + then +; + +: call-package ( ... xt ihandle -- ??? ) + my-self >r + to my-self + execute + r> to my-self +; + + +: $call-method ( ... method-str method-len ihandle -- ??? ) + dup >r >in.device-node @ find-method if + r> call-package + else + -21 throw + then +; + +: $call-parent ( ... method-str method-len -- ??? ) + my-parent $call-method +; + + +\ +\ 5.3.4.1 Open/Close packages (part 2) +\ + +\ find-dev ( dev-str dev-len -- false | phandle true ) +\ find-rel-dev ( dev-str dev-len phandle -- false | phandle true ) +\ +\ These function works just like find-device but without +\ any side effects (or exceptions). +\ +defer find-dev + +: find-rel-dev ( dev-str dev-len phandle -- false | phandle true ) + active-package >r active-package! + find-dev + r> active-package! +; + +: find-package ( name-str name-len -- false | phandle true ) +\ Locate the support package named by name string. +\ If the package can be located, return its phandle and true; otherwise, +\ return false. +\ Interpret the name in name string relative to the "packages" device node. +\ If there are multiple packages with the same name (within the "packages" +\ node), return the phandle for the most recently created one. + + \ This does the full path resolution stuff (including + \ alias expansion. If we don't want that, then we should just + \ iterade the children of /packages. + " /packages" find-dev 0= if 2drop false exit then + find-rel-dev 0= if false exit then + + \ Find the most recent node that match. One could make life + \ simple and add nodes at the head but I prefer it this way. + >r + " name" r@ get-package-property if " " then + r@ begin >dn.peer @ dup while + 3dup + " name" rot get-package-property if " " then + strcmp + 0= if r> drop dup >r then + repeat 3drop + r> true +; + +: open-package ( arg-str arg-len phandle -- ihandle | 0 ) +\ Open the package indicated by phandle. +\ Create an instance of the package identified by phandle, save in that +\ instance the instance-argument specified by arg-string and invoke the +\ package's open method. +\ Return the instance handle ihandle of the new instance, or 0 if the package +\ could not be opened. This could occur either because that package has no +\ open method, or because its open method returned false, indicating an error. +\ The parent instance of the new instance is the instance that invoked +\ open-package. The current instance is not changed. + + create-instance dup 0= if + 3drop 0 exit + then + >r + + \ clone arg-str + strdup r@ >in.arguments 2! + + \ open the package + " open" r@ ['] $call-method catch if 3drop false then + if + r> + else + r> destroy-instance false + then +; + + +: $open-package ( arg-str arg-len name-str name-len -- ihandle | 0 ) + \ Open the support package named by name string. + find-package if + open-package + else + 2drop false + then +; + + +: close-package ( ihandle -- ) +\ Close the instance identified by ihandle by calling the package's close +\ method and then destroying the instance. + dup " close" rot ['] $call-method catch if 3drop then + destroy-instance +; + +\ +\ 5.3.4.3 Get local arguments +\ + +: my-address ( -- phys.lo ... ) + ?my-self >in.device-node @ + >dn.probe-addr + my-#acells tuck cells + swap 1- 0 + ?do + cell - dup @ swap + loop + drop + ; + +: my-space ( -- phys.hi ) + ?my-self >in.device-node @ + >dn.probe-addr @ + ; + +: my-unit ( -- phys.lo ... phys.hi ) + ?my-self >in.my-unit + my-#acells tuck cells + swap 0 ?do + cell - dup @ swap + loop + drop + ; + +: my-args ( -- arg-str arg-len ) + ?my-self >in.arguments 2@ + ; + +\ char is not included. If char is not found, then R-len is zero +: left-parse-string ( str len char -- R-str R-len L-str L-len ) + left-split +; + +\ parse ints "hi,...,lo" separated by comma +: parse-ints ( str len num -- val.lo .. val.hi ) + -rot 2 pick -rot + begin + rot 1- -rot 2 pick 0>= + while + ( num n str len ) + 2dup ascii , strchr ?dup if + ( num n str len p ) + 1+ -rot + 2 pick 2 pick - ( num n p str len len1+1 ) + dup -rot - ( num n p str len1+1 len2 ) + -rot 1- ( num n p len2 str len1 ) + else + 0 0 2swap + then + $number if 0 then >r + repeat + 3drop + + ( num ) + begin 1- dup 0>= while r> swap repeat + drop +; + +: parse-2int ( str len -- val.lo val.hi ) + 2 parse-ints +; + + +\ +\ 5.3.4.4 Mapping tools +\ + +: map-low ( phys.lo ... size -- virt ) + my-space swap s" map-in" $call-parent + ; + +: free-virtual ( virt size -- ) + over s" address" get-my-property 0= if + decode-int -rot 2drop = if + s" address" delete-property + then + else + drop + then + s" map-out" $call-parent + ; diff --git a/forth/device/pathres.fs b/forth/device/pathres.fs new file mode 100644 index 0000000..39cd690 --- /dev/null +++ b/forth/device/pathres.fs @@ -0,0 +1,517 @@ +\ tag: Path resolution +\ +\ this code implements IEEE 1275-1994 path resolution +\ +\ Copyright (C) 2003 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +0 value interpose-ph +0 0 create interpose-args , , + +: expand-alias ( alias-addr alias-len -- exp-addr exp-len expanded? ) + 2dup + " /aliases" find-dev 0= if 2drop false exit then + get-package-property if + false + else + 2swap 2drop + \ drop trailing 0 from string + dup if 1- then + true + then +; + +\ +\ 4.3.1 Resolve aliases +\ + +\ the returned string is allocated with alloc-mem +: pathres-resolve-aliases ( path-addr path-len -- path-addr path-len ) + over c@ 2f <> if + 200 here + >r \ abuse dictionary for temporary storage + + \ If the pathname does not begin with "/", and its first node name + \ component is an alias, replace the alias with its expansion. + ascii / split-before \ (PATH_NAME, "/") -> (TAIL HEAD) + ascii : split-before \ (HEAD, ":") -> (ALIAS_ARGS AL_NAME) + expand-alias ( TAIL ALIAS_ARGS EXP_ALIAS_NAME expanded? ) + if + 2 pick 0<> if \ If ALIAS_ARGS is not empty + ascii / split-after \ (ALIAS_NAME, "/") -> (AL_TAIL AL_HEAD/) + 2swap ( TAIL AL_HEAD/ AL_TAIL ) + ascii : split-before \ (AL_TAIL, ":") -> (DEAD_ARGS AL_TAIL) + 2swap 2drop ( TAIL AL_ARGS AL_HEAD ALIAS_TAIL ) + 2swap ( TAIL AL_ARGS AL_TAIL AL_HEAD ) + r> tmpstrcat tmpstrcat >r + else + 2swap 2drop \ drop ALIAS_ARGS + then + r> tmpstrcat drop + else + \ put thing back together again + r> tmpstrcat tmpstrcat drop + then + then + + strdup + ( path-addr path-len ) +; + +\ +\ search struct +\ + +struct ( search information ) + 2 cells field >si.path + 2 cells field >si.arguments + 2 cells field >si.unit_addr + 2 cells field >si.node_name + 2 cells field >si.free_me + 4 cells field >si.unit_phys + /n field >si.unit_phys_len + /n field >si.save-ihandle + /n field >si.save-phandle + /n field >si.top-ihandle + /n field >si.top-opened \ set after successful open + /n field >si.child \ node to match +constant sinfo.size + + +\ +\ 4.3.6 node name match criteria +\ + +: match-nodename ( childname len sinfo -- match? ) + >r + 2dup r@ >si.node_name 2@ + ( [childname] [childname] [nodename] ) + strcmp 0= if r> 3drop true exit then + + \ does NODE_NAME contain a comma? + r@ >si.node_name 2@ ascii , strchr + if r> 3drop false exit then + + ( [childname] ) + ascii , left-split 2drop r@ >si.node_name 2@ + r> drop + strcmp if false else true then +; + + +\ +\ 4.3.4 exact match child node +\ + +\ If NODE_NAME is not empty, make sure it matches the name property +: common-match ( sinfo -- ) + >r + \ a) NODE_NAME nonempty + r@ >si.node_name 2@ nip if + " name" r@ >si.child @ get-package-property if -1 throw then + \ name is supposed to be null-terminated + dup 0> if 1- then + \ exit if NODE_NAME does not match + r@ match-nodename 0= if -2 throw then + then + r> drop +; + +: (exact-match) ( sinfo -- ) + >r + \ a) If NODE_NAME is not empty, make sure it matches the name property + r@ common-match + + \ b) UNIT_PHYS nonempty? + r@ >si.unit_phys_len @ cells ?dup if + \ check if unit_phys matches + " reg" r@ >si.child @ get-package-property if -3 throw then + ( unitbytes propaddr proplen ) + rot r@ >si.unit_phys -rot + ( propaddr unit_phys proplen unitbytes ) + swap over < if -4 throw then + comp if -5 throw then + else + \ c) both NODE_NAME and UNIT_PHYS empty? + r@ >si.node_name 2@ nip 0= if -6 throw then + then + + r> drop +; + +: exact-match ( sinfo -- match? ) + ['] (exact-match) catch if drop false exit then + true +; + +\ +\ 4.3.5 wildcard match child node +\ + +: (wildcard-match) ( sinfo -- match? ) + >r + \ a) If NODE_NAME is not empty, make sure it matches the name property + r@ common-match + + \ b) Fail if "reg" property exist + " reg" r@ >si.child @ get-package-property 0= if -7 throw then + + \ c) Fail if both NODE_NAME and UNIT_ADDR are both empty + r@ >si.unit_phys_len @ + r@ >si.node_name 2@ nip + or 0= if -1 throw then + + \ SUCCESS + r> drop +; + +: wildcard-match ( sinfo -- match? ) + ['] (wildcard-match) catch if drop false exit then + true +; + + +\ +\ 4.3.3 match child node +\ + +: find-child ( sinfo -- phandle ) + >r + \ decode unit address string + r@ >si.unit_addr 2@ dup if + ( str len ) + " decode-unit" active-package find-method + if + depth 3 - >r execute depth r@ - r> swap + ( ... a_lo ... a_hi olddepth n ) + 4 min 0 max + dup r@ >si.unit_phys_len ! + ( ... a_lo ... a_hi olddepth n ) + r@ >si.unit_phys >r + begin 1- dup 0>= while + rot r> dup na1+ >r ! + repeat + r> 2drop + depth! + else + \ no decode-unit method... failure + -99 throw + then + else + 2drop + \ clear unit_phys + 0 r@ >si.unit_phys_len ! + \ r@ >si.unit_phys 4 cells 0 fill + then + + ( R: sinfo ) + ['] exact-match + begin dup while + active-package >dn.child @ + begin ?dup while + dup r@ >si.child ! + ( xt phandle R: sinfo ) + r@ 2 pick execute if 2drop r> >si.child @ exit then + >dn.peer @ + repeat + ['] exact-match = if ['] wildcard-match else 0 then + repeat + + -99 throw +; + + +\ +\ 4.3.2 Create new linked instance procedure +\ + +: link-one ( sinfo -- ) + >r + active-package create-instance + dup 0= if -99 throw then + + \ change instance parent + r@ >si.top-ihandle @ over >in.my-parent ! + dup r@ >si.top-ihandle ! + to my-self + + \ b) set my-args field + r@ >si.arguments 2@ strdup my-self >in.arguments 2! + + \ e) set my-unit field + r@ >si.unit_addr 2@ nip if + \ copy UNIT_PHYS to the my-unit field + r@ >si.unit_phys my-self >in.my-unit 4 cells move + else + \ set unit-addr from reg property + " reg" active-package get-package-property 0= if + \ ( ihandle prop proplen ) + \ copy address to my-unit + 4 cells min my-self >in.my-unit swap move + else + \ clear my-unit + my-self >in.my-unit 4 cells 0 fill + then + then + + \ top instance has not been opened (yet) + false r> >si.top-opened ! +; + +: invoke-open ( sinfo -- ) + " open" my-self ['] $call-method + catch if 3drop false then + 0= if -99 throw then + + true swap >si.top-opened ! +; + +\ +\ 4.3.7 Handle interposers procedure (supplement) +\ + +: handle-interposers ( sinfo -- ) + >r + begin + interpose-ph ?dup + while + 0 to interpose-ph + active-package swap active-package! + + \ clear unit address and set arguments + 0 0 r@ >si.unit_addr 2! + interpose-args 2@ r@ >si.arguments 2! + r@ link-one + true my-self >in.interposed ! + interpose-args 2@ free-mem + r@ invoke-open + + active-package! + repeat + + r> drop +; + +\ +\ 4.3.1 Path resolution procedure +\ + +\ close-dev ( ihandle -- ) +\ +: close-dev + begin + dup + while + dup >in.my-parent @ + swap close-package + repeat + drop +; + +: path-res-cleanup ( sinfo close? ) + + \ tear down all instances if close? is set + if + dup >si.top-opened @ if + dup >si.top-ihandle @ + ?dup if close-dev then + else + dup >si.top-ihandle @ dup + ( sinfo ihandle ihandle ) + dup if >in.my-parent @ swap then + ( sinfo parent ihandle ) + ?dup if destroy-instance then + ?dup if close-dev then + then + then + + \ restore active-package and my-self + dup >si.save-ihandle @ to my-self + dup >si.save-phandle @ active-package! + + \ free any allocated memory + dup >si.free_me 2@ free-mem + sinfo.size free-mem +; + +: (path-resolution) ( context sinfo -- ) + >r r@ >si.path 2@ + ( context pathstr pathlen ) + + \ this allocates a copy of the string + pathres-resolve-aliases + 2dup r@ >si.free_me 2! + + \ If the pathname, after possible alias expansion, begins with "/", + \ begin the search at the root node. Otherwise, begin at the active + \ package. + + dup if \ make sure string is not empty + over c@ 2f = if + swap char+ swap /c - \ Remove the "/" from PATH_NAME. + \ Set the active package to the root node. + device-tree @ active-package! + then + then + + r@ >si.path 2! + 0 0 r@ >si.unit_addr 2! + 0 0 r@ >si.arguments 2! + 0 r@ >si.top-ihandle ! + + \ If there is no active package, exit this procedure, returning false. + ( context ) + active-package 0= if -99 throw then + + \ Begin the creation of an instance chain. + \ NOTE--If, at this step, the active package is not the root node and + \ we are in open-dev or execute-device-method contexts, the instance + \ chain that results from the path resolution process may be incomplete. + + active-package swap + ( virt-active-node context ) + begin + r@ >si.path 2@ nip \ nonzero path? + while + \ ( active-node context ) + \ is this open-dev or execute-device-method context? + dup if + r@ link-one + over active-package <> my-self >in.interposed ! + r@ invoke-open + r@ handle-interposers + then + over active-package! + + r@ >si.path 2@ ( PATH ) + + ascii / left-split ( PATH COMPONENT ) + ascii : left-split ( PATH ARGS NODE_ADDR ) + ascii @ left-split ( PATH ARGS UNIT_ADDR NODE_NAME ) + + r@ >si.node_name 2! + r@ >si.unit_addr 2! + r@ >si.arguments 2! + r@ >si.path 2! + + ( virt-active-node context ) + + \ 4.3.1 i) pathname has a leading %? + r@ >si.node_name 2@ 2dup 2dup ascii % strchr nip = if + 1- swap 1+ swap r@ >si.node_name 2! + " /packages" find-dev drop active-package! + r@ find-child + else + 2drop + nip r@ find-child swap over + ( new-node context new-node ) + then + + \ (optional: open any nodes between parent and child ) + + active-package! + repeat + + ( virt-active-node type ) + dup if r@ link-one then + 1 = if + dup active-package <> my-self >in.interposed ! + r@ invoke-open + r@ handle-interposers + then + active-package! + + r> drop +; + +: path-resolution ( context path-addr path-len -- sinfo true | false ) + \ allocate and clear the search block + sinfo.size alloc-mem >r + r@ sinfo.size 0 fill + + \ store path + r@ >si.path 2! + + \ save ihandle and phandle + my-self r@ >si.save-ihandle ! + active-package r@ >si.save-phandle ! + + \ save context (if we take an exception) + dup + + r@ ['] (path-resolution) + catch ?dup if + ( context xxx xxx error ) + r> true path-res-cleanup + + \ rethrow everything except our "cleanup throw" + dup -99 <> if throw then + 3drop + + \ ( context ) throw an exception if this is find-device context + if false else -22 throw then + exit + then + + \ ( context ) + drop r> true + ( sinfo true ) +; + + +: open-dev ( dev-str dev-len -- ihandle | 0 ) + 1 -rot path-resolution 0= if false exit then + + ( sinfo ) + my-self swap + false path-res-cleanup + + ( ihandle ) +; + +: execute-device-method +( ... dev-str dev-len met-str met-len -- ... false | ?? true ) + 2swap + 2 -rot path-resolution 0= if 2drop false exit then + ( method-str method-len sinfo ) + >r + my-self ['] $call-method catch + if 3drop false else true then + r> true path-res-cleanup +; + +: find-device ( dev-str dev-len -- ) + 2dup " .." strcmp 0= if + 2drop + active-package dup if >dn.parent @ then + \ ".." in root note? + dup 0= if -22 throw then + active-package! + exit + then + 0 -rot path-resolution 0= if false exit then + ( sinfo ) + active-package swap + true path-res-cleanup + active-package! +; + +\ find-device, but without side effects +: (find-dev) ( dev-str dev-len -- phandle true | false ) + active-package -rot + ['] find-device catch if 3drop false exit then + active-package swap active-package! true +; + +\ Tuck on a node at the end of the chain being created. +\ This implementation follows the interpose recommended practice +\ (v0.2 draft). + +: interpose ( arg-str arg-len phandle -- ) + to interpose-ph + strdup interpose-args 2! +; + +['] (find-dev) to find-dev diff --git a/forth/device/preof.fs b/forth/device/preof.fs new file mode 100644 index 0000000..f6d95a7 --- /dev/null +++ b/forth/device/preof.fs @@ -0,0 +1,50 @@ +\ tag: historical and pre open firmware fcode functions +\ +\ this code implements IEEE 1275-1994 ch. H.2.2 and 5.3.1.1.1 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ H.2.2 Non-implemented FCodes +\ Pre-Open Firmware systems assigned the following FCode numbers, +\ but the functions were not supported. These FCode numbers stay +\ reserved to avoid confusion. + +: non-implemented + ." Non-implemented historical or pre-Open Firmware FCode occured." cr + end0 + ; + +: adr-mask non-implemented ; +: b(code) non-implemented ; +: 4-byte-id non-implemented ; +: convert non-implemented ; +: frame-buffer-busy? non-implemented ; +: poll-packet non-implemented ; +: return-buffer non-implemented ; +: set-token-table non-implemented ; +: set-table non-implemented ; +: xmit-packet non-implemented ; + +\ historical fcode words defined by 5.3.1.1.1 + +30000 constant fcode-version \ this opcode is considered obsolete +30000 constant firmware-version \ this opcode is considered obsolete + +\ historical - Returns the type of processor. +\ 0x5 indicates SPARC, other values are not used. +\ ?? this could be set by the kernel during bootstrap. +deadbeef constant processor-type ( -- processor-type ) + +: memmap non-implemented ; +: >physical non-implemented ; +: my-params non-implemented ; +: intr non-implemented ; +: driver non-implemented ; +: group-code non-implemented ; +: probe non-implemented ; +: probe-virtual non-implemented ; + diff --git a/forth/device/property.fs b/forth/device/property.fs new file mode 100644 index 0000000..18d295f --- /dev/null +++ b/forth/device/property.fs @@ -0,0 +1,324 @@ +\ tag: Property management +\ +\ this code implements IEEE 1275-1994 ch. 5.3.5 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ small helpers.. these should go elsewhere. +: bigendian? + 10 here ! here c@ 10 <> + ; + +: l!-be ( val addr ) + 3 bounds swap do + dup ff and i c! + 8 rshift + -1 +loop + drop + ; + +: l@-be ( addr ) + 0 swap 4 bounds do + i c@ swap 8 << or + loop + ; + +\ allocate n bytes for device tree information +\ until I know where to put this, I put it in the +\ dictionary. + +: alloc-tree ( n -- addr ) + dup >r \ save len + here swap allot + dup r> 0 fill \ clear memory + ; + +: align-tree ( -- ) + null-align + ; + +: no-active true abort" no active package." ; + +\ +\ 5.3.5 Property management +\ + +\ Helper function +: find-property ( name len phandle -- &&prop|0 ) + >dn.properties + begin + dup @ + while + dup @ >prop.name @ ( name len prop propname ) + 2over comp0 ( name len prop equal? ) + 0= if nip nip exit then + >prop.next @ + repeat + ( name len false ) + 3drop false + ; + +\ From package (5.3.4.1) +: next-property +( previous-str previous-len phandle -- false | name-str name-len true ) + >r + 2dup 0= swap 0= or if + 2drop r> >dn.properties @ + else + r> find-property dup if @ then + ?dup if >prop.next @ then + then + + ?dup if + >prop.name @ dup cstrlen true + ( phandle name-str name-len true ) + else + false + then +; + + +\ +\ 5.3.5.4 Property value access +\ + +\ Return value for name string property in package phandle. +: get-package-property + ( name-str name-len phandle -- true | prop-addr prop-len false ) + find-property ?dup if + @ dup >prop.addr @ + swap >prop.len @ + false + else + true + then + ; + +\ Return value for given property in the current instance or its parents. +: get-inherited-property + ( name-str name-len -- true | prop-addr prop-len false ) + my-self + begin + ?dup + while + dup >in.device-node @ ( str len ihandle phandle ) + 2over rot find-property ?dup if + @ + ( str len ihandle prop ) + nip nip nip ( prop ) + dup >prop.addr @ swap >prop.len @ + false + exit + then + ( str len ihandle ) + >in.my-parent @ + repeat + 2drop + true + ; + +\ Return value for given property in this package. +: get-my-property ( name-str name-len -- true | prop-addr prop-len false ) + my-self >in.device-node @ ( -- phandle ) + get-package-property + ; + + +\ +\ 5.3.5.2 Property array decoding +\ + +: decode-int ( prop-addr1 prop-len1 -- prop-addr2 prop-len2 n ) + dup 0> if + dup 4 min >r ( addr1 len1 R:minlen ) + over r@ + swap ( addr1 addr2 len1 R:minlen ) + r> - ( addr1 addr2 len2 ) + rot l@-be + else + 0 + then + ; + +\ HELPER: get #address-cell value (from parent) +\ Legal values are 1..4 (we may optionally support longer addresses) +: my-#acells ( -- #address-cells ) + my-self ?dup if >in.device-node @ else active-package then + ?dup if >dn.parent @ then + ?dup if + " #address-cells" rot get-package-property if 2 exit then + \ we don't have to support more than 4 (and 0 is illegal) + decode-int nip nip 4 min 1 max + else + 2 + then +; + +: decode-string ( prop-addr1 prop-len1 -- prop-addr2 prop-len2 str len ) + dup 0> if + 2dup bounds \ check property for 0 bytes + 0 -rot \ initial string len is 0 + do + i c@ 0= if + leave + then + 1+ + loop ( prop-addr1 prop-len1 len ) + 1+ rot >r ( prop-len1 len R: prop-addr1 ) + over min 2dup - ( prop-len1 nlen prop-len2 R: prop-addr1 ) + r@ 2 pick + ( prop-len1 nlen prop-len2 prop-addr2 ) + >r >r >r ( R: prop-addr1 prop-addr2 prop-len2 nlen ) + drop + r> r> r> ( nlen prop-len2 prop-addr2 ) + -rot swap ( prop-addr2 prop-len2 nlen ) + r> swap ( prop-addr2 prop-len2 str len ) + else + 0 0 + then + ; + +: decode-bytes ( addr1 len1 #bytes -- addr len2 addr1 #bytes ) + tuck - ( addr1 #bytes len2 ) + r> 2dup + ( addr1 #bytes addr2 ) ( R: len2 ) + r> 2swap + ; + +: decode-phys + ( prop-addr1 prop-len1 -- prop-addr2 prop-len2 phys.lo ... phys.hi ) + my-#acells 0 ?do + decode-int r> r> rot >r >r >r + loop + my-#acells 0 ?do + r> r> r> -rot >r >r + loop + ; + + +\ +\ 5.3.5.1 Property array encoding +\ + +: encode-int ( n -- prop-addr prop-len ) + /l alloc-tree tuck l!-be /l + ; + +: encode-string ( str len -- prop-addr prop-len ) + \ we trust len here. should probably check string? + tuck char+ alloc-tree ( len str prop-addr ) + tuck 3 pick move ( len prop-addr ) + swap 1+ + ; + +: encode-bytes ( data-addr data-len -- prop-addr prop-len ) + tuck alloc-tree ( len str prop-addr ) + tuck 3 pick move + swap + ; + +: encode+ ( prop-addr1 prop-len1 prop-addr2 prop-len2 -- prop-addr3 prop-len3 ) + nip + + ; + +: encode-phys ( phys.lo ... phys.hi -- prop-addr prop-len ) + encode-int my-#acells 1- 0 ?do + rot encode-int encode+ + loop + ; + +defer sbus-intr>cpu ( sbus-intr# -- cpu-intr# ) +: (sbus-intr>cpu) ." No SBUS present on this machine." cr ; +['] (sbus-intr>cpu) to sbus-intr>cpu + + +\ +\ 5.3.5.3 Property declaration +\ + +: (property) ( prop-addr prop-len name-str name-len dnode -- ) + >r 2dup r@ + align-tree + find-property ?dup if + \ If a property with that property name already exists in the + \ package in which the property would be created, replace its + \ value with the new value. + @ r> drop \ don't need the device node anymore. + -rot 2drop tuck \ drop property name + >prop.len ! \ overwrite old values + >prop.addr ! + exit + then + + ( prop-addr prop-len name-str name-len R: dn ) + prop-node.size alloc-tree + dup >prop.next off + + dup r> >dn.properties + begin dup @ while @ >prop.next repeat ! + >r + + ( prop-addr prop-len name-str name-len R: prop ) + + \ create copy of property name + dup char+ alloc-tree + dup >r swap move r> + ( prop-addr prop-len new-name R: prop ) + r@ >prop.name ! + r@ >prop.len ! + r> >prop.addr ! + align-tree + ; + +: property ( prop-addr prop-len name-str name-len -- ) + my-self ?dup if + >in.device-node @ + else + active-package + then + dup if + (property) + else + no-active + then + ; + +: (delete-property) ( name len dnode -- ) + find-property ?dup if + dup @ >prop.next @ swap ! + \ maybe we should try to reclaim the space? + then +; + +: delete-property ( name-str name-len -- ) + active-package ?dup if + (delete-property) + else + 2drop + then + ; + +\ Create the "name" property; value is indicated string. +: device-name ( str len -- ) + encode-string " name" property + ; + +\ Create "device_type" property, value is indicated string. +: device-type ( str len -- ) + encode-string " device_type" property + ; + +\ Create the "reg" property with the given values. +: reg ( phys.lo ... phys.hi size -- ) + >r ( phys.lo ... phys.hi ) encode-phys ( addr len ) + r> ( addr1 len1 size ) encode-int ( addr1 len1 addr2 len2 ) + encode+ ( addr len ) + " reg" property + ; + +\ Create the "model" property; value is indicated string. +: model ( str len -- ) + encode-string " model" property + ; + diff --git a/forth/device/romfont.bin b/forth/device/romfont.bin new file mode 100644 index 0000000000000000000000000000000000000000..0b60b6fb41d2a790d97a00a253d26aa1373585f2 GIT binary patch literal 4096 zcmZ`+y=x;!6dx90mSD`FY766A#1<-2h*aWO#Ig)V7!w>5cSjH=MT#rTRU#})PE`mg zgt+EHFr2|5@qciT`u>g->CdFiVdwWgW_D-q@@z@_oA>5@&YPLdttsoeZtmzH>1)X6@?wA4KogG#~NR_2v1=vE~E%DITJd_?n-9H9rAsegf9~1WY`YS7$b9gV5uB9u$?G>cOp+jy6_&#aSO_x}4(LcHu8vNjU?_(t@-1XRSM0EAEakphE%re>P^$(Hs4=jU8?dXTAeMO%9AN3^?&p3Znt3)eNf-)XRaTa4E7~9(jf92KiDT_!UMwZ?3LKQ%3l2+ zv|)UGSa(l9V>C^ciGJ~IclT~1xUPv;6te#sGwfelFH}9B&$+Zqo@+j;D$gx?W~B9> zOZ%j$@a@!zolksI#xV6GPMIv=^+Lvx7*2t&KSn79m9HO`I!On4=GUmY*7tzBm68Mz2Wq4H4qVaF8giT|n}qf%n^4_M=aW|P6`Y`yJgcex>_` z`WyR?`EA@kF(1i|G|yhceh(Ke+#d4JOQw9uR-Do`C3t-}>`CEAo7eJ!leQa=239 zqgtSTijD{;G%1r+$^vs&&6ds;*@!pvK{iRGefj$K&F$-#qJKUrU1_>rA&GIZ+%AhT zJqlru^pEn}trgPu_V(=`x1ujN?d9ou;-B@GS15J`hFOu?zP9-&>z&MWAN-hjMIC=H zTSiO0{$dR32@V#SaCoWN8Rsj=a&8ClQ}9Ru%jBzk0v9L8KOJ!r6z8YAQF;W4zwB!K zcaM*9QY*tnjcQm=su!r4Yab+g2S!xkiSF4I0uyfh|B%~iF@gIwn zO#FCv5&xM_<$vBh1oPc$mwJ$v2dp;`E0nKC|2$=SZ{Ev;T!gKCl%Uv0zk4ibj*dU^ z^A+F6_%SGuIlQ>ppJ3Qe!0)HV{%81cNUA3I>;3Wmdw&ObX!42YtG;`Whrg6w6P@?; zhSNX)=?$lk=?$lk(ZLa>H^4q09y}kv!2a}HeF^sm*;?fdtGh4A8&-$OJ`SUBpCEgE zjQKN;O3#110Y(^afDv8}@YGJD`vBsT`+%Ou;SEsxCAin.instance-data \ must go first + /n field >in.alloced-size \ alloced size + /n field >in.device-node + /n field >in.my-parent + /n field >in.interposed + 4 cells field >in.my-unit + 2 cells field >in.arguments + \ instance-data should be null during packet initialization + \ this diverts access to instance variables to the dictionary +constant inst-node.size + +struct ( device node ) + /n field >dn.isize \ instance size (must go first) + /n field >dn.parent + /n field >dn.child + /n field >dn.peer + /n field >dn.properties + /n field >dn.methods + /n field >dn.priv-methods + /n field >dn.#acells + /n field >dn.probe-addr + inst-node.size field >dn.itemplate +constant dev-node.size + +struct ( property ) + /n field >prop.next + /n field >prop.name + /n field >prop.addr + /n field >prop.len +constant prop-node.size + +struct ( active package ) + /n field >ap.device-str +constant active-package.size diff --git a/forth/device/table.fs b/forth/device/table.fs new file mode 100644 index 0000000..f22283a --- /dev/null +++ b/forth/device/table.fs @@ -0,0 +1,428 @@ +\ tag: FCode table setup +\ +\ this code implements an fcode evaluator +\ as described in IEEE 1275-1994 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +hex + +: undefined-fcode ." undefined fcode word." cr ; +: reserved-fcode ." reserved fcode word." cr ; + +: ['], ( -- ) + ' , +; + +: n['], ( n -- ) + ' swap 0 do + dup , + loop + drop +; + +\ the table used +create fcode-master-table + ['], end0 + f n['], reserved-fcode + ['], b(lit) + ['], b(') + ['], b(") + ['], bbranch + ['], b?branch + ['], b(loop) + ['], b(+loop) + ['], b(do) + ['], b(?do) + ['], i + ['], j + ['], b(leave) + ['], b(of) + ['], execute + ['], + + ['], - + ['], * + ['], / + ['], mod + ['], and + ['], or + ['], xor + ['], invert + ['], lshift + ['], rshift + ['], >>a + ['], /mod + ['], u/mod + ['], negate + ['], abs + ['], min + ['], max + ['], >r + ['], r> + ['], r@ + ['], exit + ['], 0= + ['], 0<> + ['], 0< + ['], 0<= + ['], 0> + ['], 0>= + ['], < + ['], > + ['], = + ['], <> + ['], u> + ['], u<= + ['], u< + ['], u>= + ['], >= + ['], <= + ['], between + ['], within + ['], drop + ['], dup + ['], over + ['], swap + ['], rot + ['], -rot + ['], tuck + ['], nip + ['], pick + ['], roll + ['], ?dup + ['], depth + ['], 2drop + ['], 2dup + ['], 2over + ['], 2swap + ['], 2rot + ['], 2/ + ['], u2/ + ['], 2* + ['], /c + ['], /w + ['], /l + ['], /n + ['], ca+ + ['], wa+ + ['], la+ + ['], na+ + ['], char+ + ['], wa1+ + ['], la1+ + ['], cell+ + ['], chars + ['], /w* + ['], /l* + ['], cells + ['], on + ['], off + ['], +! + ['], @ + ['], l@ + ['], w@ + ['], + ['], >body + ['], fcode-revision + ['], span + ['], unloop + ['], expect + ['], alloc-mem + ['], free-mem + ['], key? + ['], key + ['], emit + ['], type + ['], (cr + ['], cr + ['], #out + ['], #line + ['], hold + ['], <# + ['], u#> + ['], sign + ['], u# + ['], u#s + ['], u. + ['], u.r + ['], . + ['], .r + ['], .s + ['], base + ['], convert \ reserved (compatibility) + ['], $number + ['], digit + ['], -1 + ['], 0 + ['], 1 + ['], 2 + ['], 3 + ['], bl + ['], bs + ['], bell + ['], bounds + ['], here + ['], aligned + ['], wbsplit + ['], bwjoin + ['], b(resolve) + ['], set-token-table + ['], set-table + ['], new-token + ['], named-token + ['], b(:) + ['], b(value) + ['], b(variable) + ['], b(constant) + ['], b(create) + ['], b(defer) + ['], b(buffer:) + ['], b(field) + ['], b(code) + ['], instance + ['], reserved-fcode + ['], b(;) + ['], b(to) + ['], b(case) + ['], b(endcase) + ['], b(endof) + ['], # + ['], #s + ['], #> + ['], external-token + ['], $find + ['], offset16 + ['], evaluate + ['], reserved-fcode + ['], reserved-fcode + ['], c, + ['], w, + ['], l, + ['], , + ['], um* + ['], um/mod + ['], reserved-fcode + ['], reserved-fcode + ['], d+ + ['], d- + ['], get-token + ['], set-token + ['], state + ['], compile, + ['], behavior + 11 n['], reserved-fcode + ['], start0 + ['], start1 + ['], start2 + ['], start4 + 8 n['], reserved-fcode + ['], ferror + ['], version1 + ['], 4-byte-id + ['], end1 + ['], reserved-fcode + ['], dma-alloc + ['], my-address + ['], my-space + ['], memmap + ['], free-virtual + ['], >physical + 8 n['], reserved-fcode + ['], my-params + ['], property + ['], encode-int + ['], encode+ + ['], encode-phys + ['], encode-string + ['], encode-bytes + ['], reg + ['], intr + ['], driver + ['], model + ['], device-type + ['], parse-2int + ['], is-install + ['], is-remove + ['], is-selftest + ['], new-device + ['], diagnostic-mode? + ['], display-status + ['], memory-test-suite + ['], group-code + ['], mask + ['], get-msecs + ['], ms + ['], finish-device + ['], decode-phys \ 128 + 2 n['], reserved-fcode + ['], interpose \ extension (recommended practice) + 4 n['], reserved-fcode + ['], map-low + ['], sbus-intr>cpu + 1e n['], reserved-fcode + ['], #lines + ['], #columns + ['], line# + ['], column# + ['], inverse? + ['], inverse-screen? + ['], frame-buffer-busy? + ['], draw-character + ['], reset-screen + ['], toggle-cursor + ['], erase-screen + ['], blink-screen + ['], invert-screen + ['], insert-characters + ['], delete-characters + ['], insert-lines + ['], delete-lines + ['], draw-logo + ['], frame-buffer-adr + ['], screen-height + ['], screen-width + ['], window-top + ['], window-left + 3 n['], reserved-fcode + ['], default-font + ['], set-font + ['], char-height + ['], char-width + ['], >font + ['], fontbytes + 10 n['], reserved-fcode \ fb1 words + ['], fb8-draw-character + ['], fb8-reset-screen + ['], fb8-toggle-cursor + ['], fb8-erase-screen + ['], fb8-blink-screen + ['], fb8-invert-screen + ['], fb8-insert-characters + ['], fb8-delete-characters + ['], fb8-insert-lines + ['], fb8-delete-lines + ['], fb8-draw-logo + ['], fb8-install + 4 n['], reserved-fcode \ reserved + 7 n['], reserved-fcode \ VME-bus support + 9 n['], reserved-fcode \ reserved + ['], return-buffer + ['], xmit-packet + ['], poll-packet + ['], reserved-fcode + ['], mac-address + 5c n['], reserved-fcode \ 1a5-200 reserved + ['], device-name + ['], my-args + ['], my-self + ['], find-package + ['], open-package + ['], close-package + ['], find-method + ['], call-package + ['], $call-parent + ['], my-parent + ['], ihandle>phandle + ['], reserved-fcode + ['], my-unit + ['], $call-method + ['], $open-package + ['], processor-type + ['], firmware-version + ['], fcode-version + ['], alarm + ['], (is-user-word) + ['], suspend-fcode + ['], abort + ['], catch + ['], throw + ['], user-abort + ['], get-my-property + ['], decode-int + ['], decode-string + ['], get-inherited-property + ['], delete-property + ['], get-package-property + ['], cpeek + ['], wpeek + ['], lpeek + ['], cpoke + ['], wpoke + ['], lpoke + ['], lwflip + ['], lbflip + ['], lbflips + ['], adr-mask + 6 n['], reserved-fcode \ 22a-22f + ['], rb@ + ['], rb! + ['], rw@ + ['], rw! + ['], rl@ + ['], rl! + ['], wbflips + ['], lwflips + ['], probe + ['], probe-virtual + ['], reserved-fcode + ['], child + ['], peer + ['], next-property + ['], byte-load + ['], set-args + ['], left-parse-string \ 240 + +here fcode-master-table - constant fcode-master-table-size + + +: nreserved ( fcode-table-ptr first last xt -- ) + -rot 1+ swap do + 2dup swap i cells + ! + loop + 2drop +; + +:noname + 800 cells alloc-mem to fcode-sys-table + + fcode-sys-table + dup 0 5ff ['] reserved-fcode nreserved \ built-in fcodes + dup 600 7ff ['] undefined-fcode nreserved \ vendor fcodes + + \ copy built-in fcodes + fcode-master-table swap fcode-master-table-size move +; initializer + +: (init-fcode-table) ( -- ) + fcode-sys-table fcode-table 800 cells move + \ clear local fcodes + fcode-table 800 fff ['] undefined-fcode nreserved +; + +['] (init-fcode-table) to init-fcode-table diff --git a/forth/device/terminal.fs b/forth/device/terminal.fs new file mode 100644 index 0000000..0b4c86a --- /dev/null +++ b/forth/device/terminal.fs @@ -0,0 +1,256 @@ +\ tag: terminal emulation +\ +\ this code implements IEEE 1275-1994 ANNEX B +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +0 value (escseq) +10 buffer: (sequence) + +: (match-number) ( x y [1|2] [1|2] -- x [z] ) + 2dup = if \ 1 1 | 2 2 + drop exit + then + 2dup > if + 2drop drop 1 exit + then + 2drop 0 + ; + +: (esc-number) ( maxchar -- ?? ?? num ) + >r depth >r ( R: depth maxchar ) + 0 (sequence) 2+ (escseq) 2- ( 0 seq+2 seqlen-2 ) + \ if numerical, scan until non-numerical + 0 ?do + ( 0 seq+2 ) + dup i + c@ a + digit if + ( 0 ptr n ) + rot a * + ( ptr val ) + swap + else + ( 0 ptr asc ) + ascii ; = if + 0 swap + else + drop leave + then + then + + loop + depth r> - r> + 0 to (escseq) + (match-number) + ; + +: (match-seq) + (escseq) 1- (sequence) + c@ \ get last character in sequence + \ dup draw-character + case + ascii A of \ CUU - cursor up + 1 (esc-number) + 0> if + 1 max + else + 1 + then + negate line# + + 0 max to line# + endof + ascii B of \ CUD - cursor down + 1 (esc-number) + 0> if + 1 max + line# + + #lines 1- min to line# + then + endof + ascii C of \ CUF - cursor forward + 1 (esc-number) + 0> if + 1 max + column# + + #columns 1- min to column# + then + endof + ascii D of \ CUB - cursor backward + 1 (esc-number) + 0> if + 1 max + negate column# + + 0 max to column# + then + endof + ascii E of \ Cursor next line (CNL) + \ FIXME - check agains ANSI3.64 + 1 (esc-number) + 0> if + 1 max + line# + + #lines 1- min to line# + then + 0 to column# + endof + ascii f of + 2 (esc-number) + 2 = if + #columns 1- min to column# + #lines 1- min to line# + then + endof + ascii H of + 2 (esc-number) + 2 = if + #columns 1- min to column# + #lines 1- min to line# + then + endof + ascii J of + 0 to (escseq) + #columns column# - delete-characters + #lines line# - delete-lines + endof + ascii K of + 0 to (escseq) + #columns column# - delete-characters + endof + ascii L of + 1 (esc-number) + 0> if + 1 max + insert-lines + then + endof + ascii M of + 1 (esc-number) + 1 = if + 1 max + delete-lines + then + endof + ascii @ of + 1 (esc-number) + 1 = if + 1 max + insert-characters + then + endof + ascii P of + 1 (esc-number) + 1 = if + 1 max + delete-characters + then + endof + ascii m of + 1 (esc-number) + 1 = if + 7 = if + true to inverse? + else + false to inverse? + then + then + endof + ascii p of \ normal text colors + 0 to (escseq) + inverse-screen? if + false to inverse-screen? + inverse? 0= to inverse? + invert-screen + then + endof + ascii q of \ inverse text colors + 0 to (escseq) + inverse-screen? not if + true to inverse-screen? + inverse? 0= to inverse? + invert-screen + then + endof + ascii s of + \ Resets the display device associated with the terminal emulator. + 0 to (escseq) + reset-screen + endof + endcase + ; + +: (term-emit) ( char -- ) + toggle-cursor + + (escseq) 0> if + (escseq) 10 = if + 0 to (escseq) + ." overflow in esc" cr + drop + then + (escseq) 1 = if + dup ascii [ = if \ not a [ + (sequence) 1+ c! + 2 to (escseq) + else + 0 to (escseq) \ break out of ESC sequence + ." out of ESC" cr + drop \ don't print breakout character + then + toggle-cursor exit + else + (sequence) (escseq) + c! + (escseq) 1+ to (escseq) + (match-seq) + toggle-cursor exit + then + then + + case + 7 of \ BEL + blink-screen + s" /screen" s" ring-bell" + execute-device-method + endof + 8 of \ BS + column# 0<> if + column# 1- dup + to column# + 20 draw-character + to column# + then + endof + 9 of \ TAB + column# dup #columns = if + drop + else + 8 + -8 and ff and to column# + then + endof + a of \ LF + line# 1+ to line# 0 to column# + endof + b of \ VT + line# 0<> if + line# 1- to line# + then + endof + c of \ FF + 0 to column# 0 to line# + erase-screen + endof + d of \ CR + 0 to column# + endof + 1b of \ ESC + 1b (sequence) c! + 1 to (escseq) + endof + dup draw-character + endcase + toggle-cursor + ; + +['] (term-emit) to fb-emit + diff --git a/forth/device/tree.fs b/forth/device/tree.fs new file mode 100644 index 0000000..7bb3243 --- /dev/null +++ b/forth/device/tree.fs @@ -0,0 +1,72 @@ +\ tag: Device Tree +\ +\ this code implements IEEE 1275-1994 ch. 3.5 +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + + +\ root node +new-device + " OpenBiosTeam,OpenBIOS" device-name + 1 encode-int " #address-cells" property + external + : open true ; + : close ; + : decode-unit parse-hex ; + : encode-unit ( addr -- str len ) + pocket tohexstr + ; + +new-device + " aliases" device-name + external + : open true ; + : close ; +finish-device + +new-device + " openprom" device-name + " BootROM" device-type + " OpenFirmware 3" model + 0 0 " relative-addressing" property + 0 0 " supports-bootinfo" property + 1 encode-int " boot-syntax" property + + external + : selftest + ." OpenBIOS selftest... succeded" cr + true + ; + : open true ; + : close ; + + new-device + " client-services" device-name + : open true ; + : close ; + finish-device + +finish-device + +new-device + " options" device-name +finish-device + +new-device + " chosen" device-name + 0 encode-int " stdin" property + 0 encode-int " stdout" property + \ " hda1:/boot/vmunix" encode-string " bootpath" property + \ " -as" encode-string " bootargs" property + 0 encode-int " memory" property + 0 encode-int " mmu" property + external +finish-device + +\ END +finish-device + diff --git a/forth/lib/build.xml b/forth/lib/build.xml new file mode 100644 index 0000000..9c7e58d --- /dev/null +++ b/forth/lib/build.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/forth/lib/creation.fs b/forth/lib/creation.fs new file mode 100644 index 0000000..c3d0db8 --- /dev/null +++ b/forth/lib/creation.fs @@ -0,0 +1,52 @@ +\ tag: misc useful functions +\ +\ C bindings +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ return xt of the word just defined +: last-xt ( -- xt ) + latest @ na1+ +; + +\ ------------------------------------------------------------------------- +\ word creation +\ ------------------------------------------------------------------------- + +: $is-ibuf ( size name name-len -- xt ) + instance $buffer: drop + last-xt +; + +: is-ibuf ( size -- xt ) + 0 0 $is-ibuf +; + +: is-ivariable ( size name len -- xt ) + 4 -rot instance $buffer: drop + last-xt +; + +: is-xt-func ( xt|0 wordstr len ) + header 1 , + ?dup if , then + ['] (semis) , reveal +; + +: is-2xt-func ( xt1 xt2 wordstr len ) + header 1 , + swap , , + ['] (semis) , reveal +; + +: is-func-begin ( wordstr len ) + header 1 , +; + +: is-func-end ( wordstr len ) + ['] (semis) , reveal +; diff --git a/forth/lib/lists.fs b/forth/lib/lists.fs new file mode 100644 index 0000000..91f7867 --- /dev/null +++ b/forth/lib/lists.fs @@ -0,0 +1,26 @@ +\ tag: misc useful functions +\ +\ Misc useful functions +\ +\ Copyright (C) 2003 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ ------------------------------------------------------------------------- +\ statically allocated lists +\ ------------------------------------------------------------------------- +\ list-head should be a variable + +: list-add ( listhead -- ) + here 0 , swap \ next, [data...] + ( here listhead ) + begin dup @ while @ repeat ! +; + +: list-get ( listptr -- nextlistptr dictptr true | false ) + @ dup if + dup na1+ true + then +; diff --git a/forth/lib/preinclude.fs b/forth/lib/preinclude.fs new file mode 100644 index 0000000..6f20ea8 --- /dev/null +++ b/forth/lib/preinclude.fs @@ -0,0 +1,11 @@ +\ +\ config and build date includes +\ +\ Copyright (C) 2005 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +include config.fs +include version.fs diff --git a/forth/lib/preprocessor.fs b/forth/lib/preprocessor.fs new file mode 100644 index 0000000..ac88885 --- /dev/null +++ b/forth/lib/preprocessor.fs @@ -0,0 +1,75 @@ +\ tag: Forth preprocessor +\ +\ Forth preprocessor +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +0 value prep-wid +0 value prep-dict +0 value prep-here + +: ([IF]) + begin + begin parse-word dup 0= while + 2drop refill + repeat + + 2dup " [IF]" strcmp 0= if 1 throw then + 2dup " [ELSE]" strcmp 0= if 2 throw then + 2dup " [THEN]" strcmp 0= if 3 throw then + " \\" strcmp 0= if linefeed parse 2drop then + again +; + +: [IF] ( flag -- ) + if exit then + 1 begin + ['] ([IF]) catch case + \ EOF (FIXME: this does not work) + \ -1 of ." Missing [THEN]" abort exit endof + \ [IF] + 1 of 1+ endof + \ [ELSE] + 2 of dup 1 = if 1- then endof + \ [THEN] + 3 of 1- endof + endcase + dup 0 <= + until drop +; immediate + +: [ELSE] 0 [ ['] [IF] , ] ; immediate +: [THEN] ; immediate + +:noname + 0 to prep-wid + 0 to prep-dict +; initializer + +: [IFDEF] ( -- ) + prep-wid if + parse-word prep-wid search-wordlist dup if nip then + else 0 then + [ ['] [IF] , ] +; immediate + +: [DEFINE] ( -- ) + parse-word here get-current >r >r + prep-dict 0= if + 2000 alloc-mem here! + here to prep-dict + wordlist to prep-wid + here to prep-here + then + prep-wid set-current prep-here here! + $create + here to prep-here + r> r> set-current here! +; immediate + +: [0] 0 ; immediate +: [1] 1 ; immediate diff --git a/forth/lib/split.fs b/forth/lib/split.fs new file mode 100644 index 0000000..1a7ac3a --- /dev/null +++ b/forth/lib/split.fs @@ -0,0 +1,49 @@ +\ implements split-before, split-after and left-split +\ as described in 4.3 (Path resolution) + +\ delimeter returned in R-string +: split-before ( addr len delim -- addr-R len-R addr-L len-L ) + 0 rot dup >r 0 ?do + ( str char cnt R: len ) + 2 pick over + c@ 2 pick = if leave then + 1+ + loop + nip + 2dup + r> 2 pick - + 2swap +; + +\ delimeter returned in L-string +: split-after ( addr len delim -- addr-R len-R addr-L len-L ) + over 1- rot dup >r 0 ?do + ( str char cnt R: len ) + 2 pick over + c@ 2 pick = if leave then + 1- + loop + nip + dup 0 >= if 1+ else drop r@ then + 2dup + r> 2 pick - + 2swap +; + +\ delimiter not returned +: left-split ( addr len delim -- addr-R len-R addr-L len-L ) + 0 rot dup >r 0 ?do + ( str char cnt R: len ) + 2 pick i + c@ 2 pick = if leave then + 1+ + loop + nip + 2dup + 1+ r> 2 pick - + dup if 1- then + 2swap +; + +\ delimiter not returned [THIS FUNCTION IS NOT NEEDED] +: right-split ( addr len delim -- addr-R len-R addr-L len-L ) + dup >r + split-after + dup if 2dup + 1- + c@ r@ = if 1- then then + r> drop +; diff --git a/forth/lib/string.fs b/forth/lib/string.fs new file mode 100644 index 0000000..eb64749 --- /dev/null +++ b/forth/lib/string.fs @@ -0,0 +1,127 @@ +\ tag: misc useful functions +\ +\ Misc useful functions +\ +\ Copyright (C) 2003 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ compare c-string with (str len) pair +: comp0 ( cstr str len -- 0|-1|1 ) + 3dup + comp ?dup if >r 3drop r> exit then + nip + c@ 0<> if 1 else 0 then +; + +\ returns 0 if the strings match +: strcmp ( str1 len1 str2 len2 -- 0|1 ) + rot over <> if 3drop 1 exit then + comp if 1 else 0 then +; + +: strchr ( str len char -- where|0 ) + >r + begin + 1- dup 0>= + while + ( str len ) + over c@ r@ = if r> 2drop exit then + swap 1+ swap + repeat + r> 3drop 0 +; + +: cstrlen ( cstr -- len ) + dup + begin dup c@ while 1+ repeat + swap - +; + +: strdup ( str len -- newstr len ) + dup if + dup >r + dup alloc-mem dup >r swap move + r> r> + else + 2drop 0 0 + then +; + +: dict-strdup ( str len -- dict-addr len ) + dup here swap allot null-align + swap 2dup >r >r move r> r> +; + +\ ----------------------------------------------------- +\ string copy and cat variants +\ ----------------------------------------------------- + +: tmpstrcat ( addr2 len2 addr1 len1 tmpbuf -- buf len1+len2 tmpbuf+l1+l2 ) + \ save return arguments + dup 2 pick + 4 pick + >r ( R: buf+l1+l2 ) + over 4 pick + >r + dup >r + \ copy... + 2dup + >r + swap move r> swap move + r> r> r> +; + +: tmpstrcpy ( addr1 len1 tmpbuf -- tmpbuf len1 tmpbuf+len1 ) + swap 2dup >r >r move + r> r> 2dup + +; + + + +\ ----------------------------------------------------- +\ number to string conversion +\ ----------------------------------------------------- + +: numtostr ( num buf -- buf len ) + swap rdepth -rot + ( rdepth buf num ) + begin + base @ u/mod swap + \ dup 0< if base @ + then + dup a < if ascii 0 else ascii a a - then + >r + ?dup 0= + until + + rdepth rot - 0 + ( buf len cnt ) + begin + r> over 4 pick + c! + 1+ 2dup <= + until + drop +; + +: tohexstr ( num buf -- buf len ) + base @ hex -rot numtostr rot base ! +; + +: toudecstr ( num buf -- buf len ) + base @ decimal -rot numtostr rot base ! +; + +: todecstr ( num buf -- buf len ) + over 0< if + swap negate over ascii - over c! 1+ + ( buf num buf+1 ) + toudecstr 1+ nip + else + toudecstr + then +; + + +\ ----------------------------------------------------- +\ string to number conversion +\ ----------------------------------------------------- + +: parse-hex ( str len -- value ) + base @ hex -rot $number if 0 then swap base ! +; diff --git a/forth/lib/vocabulary.fs b/forth/lib/vocabulary.fs new file mode 100644 index 0000000..f1e6b07 --- /dev/null +++ b/forth/lib/vocabulary.fs @@ -0,0 +1,155 @@ +\ tag: vocabulary implementation for openbios +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ +\ this is an implementation of DPANS94 wordlists (SEARCH EXT) +\ + + +16 constant #vocs +create vocabularies #vocs cells allot \ word lists +['] vocabularies to context + +: search-wordlist ( 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. + find-wordlist + if + true over immediate? if + negate + then + else + 2drop false + then + ; + +: wordlist ( -- wid ) + \ Creates 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. + here 0 , + ; + +: get-order ( -- wid1 .. widn n ) + #order @ 0 ?do + #order @ i - 1- cells context + @ + loop + #order @ + ; + +: set-order ( wid1 .. widn n -- ) + dup -1 = if + drop forth-last 1 \ push system default word list and number of lists + then + dup #order ! + 0 ?do + i cells context + ! + loop + ; + +: order ( -- ) + \ display word lists in the search order in their search order sequence + \ from the first searched to last searched. Also display word list into + \ which new definitions will be placed. + cr + get-order 0 ?do + ." wordlist " i (.) type 2e emit space . cr + loop + cr ." definitions: " current @ . cr + ; + + +: previous ( -- ) + \ Transform the search order consisting of widn, ... wid2, wid1 (where + \ wid1 is searched first) into widn, ... wid2. An ambiguous condition + \ exists if the search order was empty before PREVIOUS was executed. + get-order nip 1- set-order + ; + + +: do-vocabulary ( -- ) \ implementation factor + does> + @ >r ( ) ( R: widnew ) + get-order swap drop ( wid1 ... widn-1 n ) + r> swap set-order + ; + +: discard ( x1 .. xu u - ) \ implementation factor + 0 ?do + drop + loop + ; + +: vocabulary ( >name -- ) + wordlist create , do-vocabulary + ; + +: also ( -- ) + get-order over swap 1+ set-order + ; + +: only ( -- ) + -1 set-order also + ; + +only + +\ create forth forth-wordlist , do-vocabulary +create forth get-order over , discard do-vocabulary + +: findw ( c-addr -- c-addr 0 | w 1 | w -1 ) + 0 ( c-addr 0 ) + #order @ 0 ?do + over count ( c-addr 0 c-addr' u ) + i cells context + @ ( c-addr 0 c-addr' u wid ) + search-wordlist ( c-addr 0; 0 | w 1 | w -1 ) + ?dup if ( c-addr 0; w 1 | w -1 ) + 2swap 2drop leave ( w 1 | w -1 ) + then ( c-addr 0 ) + loop ( c-addr 0 | w 1 | w -1 ) + ; + +: get-current ( -- wid ) + current @ + ; + +: set-current ( wid -- ) + current ! + ; + +: definitions ( -- ) + \ 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. + context @ set-current + ; + +: forth-wordlist ( -- wid ) + forth-last + ; + +: #words ( -- ) + 0 last + begin + @ ?dup + while + swap 1+ swap + repeat + + cr + ; + +true to vocabularies? + + diff --git a/forth/packages/Kconfig b/forth/packages/Kconfig new file mode 100644 index 0000000..f558561 --- /dev/null +++ b/forth/packages/Kconfig @@ -0,0 +1,17 @@ + +config PKG_DEBLOCKER + bool "Deblocker" + default y + +config PKG_DISKLABEL + bool "Disk Label" + default y + +config PKG_OBP_TFTP + bool "OBP-TFTP" + default y + +config PKG_TERMINAL_EMULATOR + bool "Terminal Emulator" + default y + diff --git a/forth/packages/README b/forth/packages/README new file mode 100644 index 0000000..793d263 --- /dev/null +++ b/forth/packages/README @@ -0,0 +1,12 @@ +IEEE 1275-1994 support packages +------------------------------- + +These files create the sub nodes of the /packages node. The nodes +do normally not need an open or close method since their methods are +called statically. + +Currently there are the following support packages: +* deblocker +* obp-tftp +* + diff --git a/forth/packages/build.xml b/forth/packages/build.xml new file mode 100644 index 0000000..f32443d --- /dev/null +++ b/forth/packages/build.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/forth/packages/deblocker.fs b/forth/packages/deblocker.fs new file mode 100644 index 0000000..3959f79 --- /dev/null +++ b/forth/packages/deblocker.fs @@ -0,0 +1,64 @@ +\ tag: deblocker support package +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +" /packages" find-device + +\ The deblocker package makes it easy to implement byte-oriented device +\ methods, using the block-oriented or record-oriented methods defined by +\ devices such as disks or tapes. It provides a layer of buffering between +\ the high-level byte-oriented interface and the low-level block-oriented +\ interface. deblocker uses the max-transfer, block-size, read-blocks and +\ write-blocks methods of its parent. + +new-device + " deblocker" device-name + external + \ open ( -- flag ) + \ Prepares the package for subsequent use, allocating the buffers used + \ by the deblocking process based upon the values returned by the parent + \ instance's max-transfer and block-size methods. Returns -1 if the + \ operation succeeds, 0 otherwise. + : open ( -- flag ) + + ; + + \ close ( -- ) + \ Frees all resources that were allocated by open. + : close ( -- ) + ; + + \ read ( adr len -- actual ) + \ Reads at most len bytes from the device into the memory buffer + \ beginning at adr. Returns actual, the number of bytes actually + \ read, or 0 if the read operation failed. Uses the parent's read- + \ blocks method as necessary to satisfy the request, buffering any + \ unused bytes for the next request. + + : read ( adr len -- actual ) + ; + + \ Writes at most len bytes from the device into the memory buffer + \ beginning at adr. Returns actual, the number of bytes actually + \ read, or 0 if the write operation failed. Uses the parent's write- + \ blocks method as necessary to satisfy the request, buffering any + \ unused bytes for the next request. + + : write ( adr len -- actual ) + ; + + \ Sets the device position at which the next read or write will take + \ place. The position is specified by the 64-bit number x.position. + \ Returns 0 if the operation succeeds or -1 if it fails. + + : seek ( x.position -- flag ) + ; + +finish-device + +\ clean up afterwards +device-end diff --git a/forth/packages/disklabel.fs b/forth/packages/disklabel.fs new file mode 100644 index 0000000..01f9517 --- /dev/null +++ b/forth/packages/disklabel.fs @@ -0,0 +1,23 @@ +\ tag: disklabel support package +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +" /packages" find-device + +\ +\ IEEE 1275 disklabel package +\ + +new-device + " disklabel" device-name + external + \ now the methods... + +finish-device + +\ clean up afterwards +device-end diff --git a/forth/packages/obp-tftp.fs b/forth/packages/obp-tftp.fs new file mode 100644 index 0000000..8a42eee --- /dev/null +++ b/forth/packages/obp-tftp.fs @@ -0,0 +1,23 @@ +\ tag: tftp support package +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +" /packages" find-device + +\ +\ IEEE 1275 obp-tftp package +\ + +new-device + " obp-tftp" device-name + external + \ now the methods... + +finish-device + +\ clean up afterwards +device-end diff --git a/forth/packages/packages.fs b/forth/packages/packages.fs new file mode 100644 index 0000000..d1d15af --- /dev/null +++ b/forth/packages/packages.fs @@ -0,0 +1,18 @@ +\ tag: /packages sub device tree +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +" /" find-device + +new-device + " packages" device-name + external + : open true ; + : close ; +finish-device + +device-end diff --git a/forth/packages/terminal-emulator.fs b/forth/packages/terminal-emulator.fs new file mode 100644 index 0000000..07fc84b --- /dev/null +++ b/forth/packages/terminal-emulator.fs @@ -0,0 +1,25 @@ +\ tag: terminal emulator support package +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +" /packages" find-device + +\ +\ IEEE 1275 terminal-emulator package +\ + +new-device + " terminal-emulator" device-name + external + \ now the methods... + +finish-device + +\ clean up afterwards + +device-end + diff --git a/forth/system/build.xml b/forth/system/build.xml new file mode 100644 index 0000000..f15440a --- /dev/null +++ b/forth/system/build.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/forth/system/ciface.fs b/forth/system/ciface.fs new file mode 100644 index 0000000..f32efc6 --- /dev/null +++ b/forth/system/ciface.fs @@ -0,0 +1,318 @@ + +0 value ciface-ph + +dev /packages/ +new-device +" client-iface" device-name + +active-package to ciface-ph + +\ ------------------------------------------------------------- +\ private stuff +\ ------------------------------------------------------------- + +: ?phandle ( phandle -- phandle ) + dup 0= if ." NULL phandle" -1 throw then +; +: ?ihandle ( ihandle -- ihandle ) + dup 0= if ." NULL ihandle" -2 throw then +; + +\ copy and null terminate return string +: ci-strcpy ( buf buflen str len -- len ) + >r -rot dup + ( str buf buflen buflen R: len ) + r@ min swap + ( str buf n buflen R: len ) + over > if + ( str buf n ) + 2dup + 0 swap c! + then + move r> +; + +0 value memory-ih +0 value mmu-ih + +:noname ( -- ) + " /chosen" find-device + + " mmu" active-package get-package-property 0= if + decode-int nip nip to mmu-ih + then + + " memory" active-package get-package-property 0= if + decode-int nip nip to memory-ih + then + device-end +; SYSTEM-initializer + +: safetype + ." <" dup cstrlen dup 20 < if type else 2drop ." BAD" then ." >" +; + +\ ------------------------------------------------------------- +\ public interface +\ ------------------------------------------------------------- + +external + +\ ------------------------------------------------------------- +\ 6.3.2.1 Client interface +\ ------------------------------------------------------------- + +\ returns -1 if missing +: test ( name -- 0|-1 ) + dup cstrlen ciface-ph find-method + if drop 0 else -1 then +; + +\ ------------------------------------------------------------- +\ 6.3.2.2 Device tree +\ ------------------------------------------------------------- + +: peer peer ; +: child child ; +: parent parent ; + +: getproplen ( phandle name -- len|-1 ) + \ ." PH " over . dup cstrlen ." GETPROPLEN " 2dup type cr + dup cstrlen + rot ?phandle get-package-property + if -1 else nip then +; + +: getprop ( phandle name buf buflen -- size|-1 ) + \ ." PH " 3 pick . ." GETPROP " 2 pick dup cstrlen type cr + >r >r dup cstrlen + rot + \ detect phandle == -1 + dup -1 = if + r> r> 2drop 3drop -1 exit + then + + \ return -1 if phandle is 0 (MacOS actually does this) + ?dup 0= if r> r> 2drop 2drop -1 exit then + + ?phandle get-package-property if r> r> 2drop -1 exit then + r> r> + ( prop proplen dest destlen ) + rot dup >r min move r> +; + +\ 1 OK, 0 no more prop, -1 prev invalid +: nextprop ( phandle prev buf -- 1|0|-1 ) + rot >r + swap ( buf prev ) + dup 0= if 0 else dup cstrlen then + + ( buf prev prev_len ) + 0 3 pick c! + + \ verify that prev exists (overkill...) + dup if + 2dup r@ get-package-property if + r> 2drop 2drop -1 exit + else + 2drop + then + then + + ( buf prev prev_len ) + + r> next-property if + ( buf name name_len ) + dup 1+ -rot ci-strcpy drop 1 + else + ( buf ) + drop 0 + then +; + +: setprop ( phandle name buf len -- size ) + dup >r encode-bytes rot dup cstrlen + ( phandle buf len name name_len R: size ) + 4 pick (property) + drop r> +; + +: finddevice ( dev_spec -- phandle|-1 ) + dup cstrlen + \ ." FIND-DEVICE " 2dup type + find-dev 0= if -1 then + \ ." -- " dup . cr +; + +: instance-to-package ( ihandle -- phandle ) + ?ihandle ihandle>phandle +; + +: package-to-path ( phandle buf buflen -- length ) + rot + \ XXX improve error checking + dup 0= if 3drop -1 exit then + get-package-path + ( buf buflen str len ) + ci-strcpy +; + +: canon ( dev_specifier buf buflen -- len ) + rot dup cstrlen find-dev if + ( buf buflen phandle ) + -rot + package-to-path + else + 2drop -1 + then +; + +: instance-to-path ( ihandle buf buflen -- length ) + rot + \ XXX improve error checking + dup 0= if 3drop -1 exit then + get-instance-path + \ ." INSTANCE: " 2dup type cr dup . + ( buf buflen str len ) + ci-strcpy +; + +: instance-to-interposed-path ( ihandle buf buflen -- length ) + rot + \ XXX improve error checking + dup 0= if 3drop -1 exit then + get-instance-interposed-path + ( buf buflen str len ) + ci-strcpy +; + +: call-method ( ihandle method -- xxxx catch-result ) + dup 0= if ." call of null method" -1 exit then + dup >r + dup cstrlen + \ ." call-method " 2dup type cr + rot ?ihandle ['] $call-method catch dup if + \ not necessary an error but very useful for debugging... + ." call-method " r@ dup cstrlen type ." : exception " dup . cr + then + r> drop +; + + +\ ------------------------------------------------------------- +\ 6.3.2.3 Device I/O +\ ------------------------------------------------------------- + +: open ( dev_spec -- ihandle|0 ) + dup cstrlen open-dev +; + +: close ( ihandle -- ) + close-dev +; + +: read ( ihandle addr len -- actual ) + rot dup ihandle>phandle " read" rot find-method + if swap call-package else 3drop -1 then +; + +: write ( ihandle addr len -- actual ) + rot dup ihandle>phandle " write" rot find-method + if swap call-package else 3drop -1 then +; + +: seek ( ihandle pos_hi pos_lo -- status ) + \ package methods uses ( pos_lo pos_hi -- status ) + swap + rot dup ihandle>phandle " seek" rot find-method + if swap call-package else 3drop -1 then +; + + +\ ------------------------------------------------------------- +\ 6.3.2.4 Memory +\ ------------------------------------------------------------- + +\ : claim ( virt size align -- baseaddr|-1 ) ; +\ : release ( virt size -- ) ; + +\ ------------------------------------------------------------- +\ 6.3.2.5 Control transfer +\ ------------------------------------------------------------- + +: boot ( bootspec -- ) + ." BOOT" +; + +: enter ( -- ) + ." ENTER" +; + +\ exit ( -- ) is defined later (clashes with builtin exit) + +: chain ( virt size entry args len -- ) + ." CHAIN" +; + +\ ------------------------------------------------------------- +\ 6.3.2.6 User interface +\ ------------------------------------------------------------- + +: interpret ( xxx cmdstring -- ??? catch-reult ) + dup cstrlen + \ ." INTERPRETE: --- " 2dup type + ['] evaluate catch dup if + \ this is not necessary an error... + ." interpret: exception " dup . ." caught" cr + then + \ ." --- " cr +; + +\ : set-callback ( newfunc -- oldfunc ) ; +\ : set-symbol-lookup ( sym-to-value -- value-to-sym ) ; + + +\ ------------------------------------------------------------- +\ 6.3.2.7 Time +\ ------------------------------------------------------------- + +\ : milliseconds ( -- ms ) ; + + +\ ------------------------------------------------------------- +\ arch? +\ ------------------------------------------------------------- + +: start-cpu ( xxx xxx xxx --- ) + ." Start CPU unimplemented" cr + 3drop +; + +\ ------------------------------------------------------------- +\ special +\ ------------------------------------------------------------- + +: exit ( -- ) + ." EXIT" + outer-interpreter +; + +finish-device +device-end + + +\ ------------------------------------------------------------- +\ entry point +\ ------------------------------------------------------------- + +: client-iface ( [args] name len -- [args] -1 | [rets] 0 ) + ciface-ph find-method 0= if -1 exit then + catch ?dup if + cr ." Unexpected client interface exception: " . -2 cr exit + then + 0 +; + +: client-call-iface ( [args] name len -- [args] -1 | [rets] 0 ) + ciface-ph find-method 0= if -1 exit then + execute +; diff --git a/forth/system/main.fs b/forth/system/main.fs new file mode 100644 index 0000000..122ab1f --- /dev/null +++ b/forth/system/main.fs @@ -0,0 +1,60 @@ +\ tag: misc useful functions +\ +\ Open Firmware Startup +\ +\ Copyright (C) 2003 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +variable PREPOST-list +variable POST-list +variable SYSTEM-list +variable DIAG-list + +: PREPOST-initializer ( xt -- ) + PREPOST-list list-add , +; + +: POST-initializer ( xt -- ) + POST-list list-add , +; + +: SYSTEM-initializer ( xt -- ) + SYSTEM-list list-add , +; + +: DIAG-initializer ( xt -- ) + DIAG-list list-add , +; + + +\ OpenFirmware entrypoint +: initialize-of ( startmem endmem -- ) + initialize-forth + + PREPOST-list begin list-get while @ execute repeat + POST-list begin list-get while @ execute repeat + SYSTEM-list begin list-get while @ execute repeat + + \ evaluate nvramrc script + use-nvramrc? if + nvramrc evaluate + then + + \ probe-all etc. + suppress-banner? 0= if + probe-all + install-console + banner + then + + DIAG-list begin list-get while @ execute repeat + + auto-boot? if + boot-command evaluate + then + + outer-interpreter +; diff --git a/forth/testsuite/README b/forth/testsuite/README new file mode 100644 index 0000000..7aa98de --- /dev/null +++ b/forth/testsuite/README @@ -0,0 +1,8 @@ +TESTSUITES +---------- + +This directory contains additional testsuites for some open +firmware components. They are not built per default. + + +tag: testsuites readme diff --git a/forth/testsuite/build.xml b/forth/testsuite/build.xml new file mode 100644 index 0000000..7b7d62b --- /dev/null +++ b/forth/testsuite/build.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/forth/testsuite/fract.fs b/forth/testsuite/fract.fs new file mode 100644 index 0000000..ff31bb1 --- /dev/null +++ b/forth/testsuite/fract.fs @@ -0,0 +1,36 @@ +\ tag: forth fractal example +\ +\ Copyright (C) 2002, 2003 Volker Poplawski +\ Stefan Reinauer + +\ This example even fits in a signature ;-) + +\ hex 4666 dup negate do i 4000 dup 2* negate do 2a 0 dup 2dup 1e 0 do +\ 2swap * d >>a 4 pick + -rot - j + dup dup * e >>a rot dup dup * e >>a +\ rot swap 2dup + 10000 > if 3drop 2drop 20 0 dup 2dup leave then loop +\ 2drop 2drop type 268 +loop cr drop 5de +loop + + +: fract +4666 dup negate +do + i 4000 dup 2* negate + do + 2a 0 dup 2dup 1e 0 + do + 2swap * d >>a 4 pick + + -rot - j + + dup dup * e >>a rot + dup dup * e >>a rot + swap + 2dup + 10000 > if + 3drop 2drop 20 0 dup 2dup leave + then + loop + 2drop 2drop + emit + 268 +loop + cr drop +5de +loop +; + diff --git a/forth/testsuite/framebuffer-test.fs b/forth/testsuite/framebuffer-test.fs new file mode 100644 index 0000000..c417a34 --- /dev/null +++ b/forth/testsuite/framebuffer-test.fs @@ -0,0 +1,13 @@ + +: test-screen + 10 10 pci-l@ + f0 0 do + dup d# 1280 i * + + 500 i fill + loop + ; + + test-screen + + + diff --git a/forth/testsuite/memory-testsuite.fs b/forth/testsuite/memory-testsuite.fs new file mode 100644 index 0000000..9dace51 --- /dev/null +++ b/forth/testsuite/memory-testsuite.fs @@ -0,0 +1,106 @@ +\ this is the memory management testsuite. +\ +\ run it with paflof < memory-testsuite.fs 2>/dev/null + +s" memory.fs" included + +\ dumps all free-list entries +\ useful for debugging. + +: dump-freelist ( -- ) + ." Dumping freelist:" cr + free-list @ + + \ If the free list is empty we notify the user. + dup 0= if ." empty." drop cr exit then + + begin dup 0<> while + dup ." entry 0x" . \ print pointer to entry + dup cell+ @ ." , next=0x" u. \ pointer to next entry + dup @ ." , size=0x" u. cr \ len of current entry + + cell+ @ + repeat + cr drop + ; + +\ simple testsuite. run testsuite-init to initialize +\ with some dummy memory in the dictionary. +\ run testsuite-test[1..3] for different tests. + +: testsuite-init ( -- ) + here 40000 cell+ dup allot ( -- ptr len ) + init-mem + + ." start-mem = 0x" start-mem @ . cr + ." end-mem = 0x" end-mem @ . cr + ." free-list = 0x" free-list @ . cr + + ." Memory management initialized." cr + dump-freelist + ; + +: testsuite-test1 ( -- ) + ." Test No. 1: Allocating all available memory (256k)" cr + + 40000 alloc-mem + dup 0<> if + ." worked, ptr=0x" dup . + else + ." did not work." + then + cr + + dump-freelist + ." Freeing memory." cr + ." stack=" .s cr + free-mem + dump-freelist + ; + +: testsuite-test2 ( -- ) + ." Test No. 2: Allocating 5 blocks" cr + 4000 alloc-mem + 4000 alloc-mem + 4000 alloc-mem + 4000 alloc-mem + 4000 alloc-mem + + ." Allocated 5 blocks. Stack:" cr .s cr + + dump-freelist + + ." Freeing Block 2" cr + 3 pick free-mem dump-freelist + + ." Freeing Block 4" cr + over free-mem dump-freelist + + ." Freeing Block 3" cr + 2 pick free-mem dump-freelist + + ." Cleaning up blocks 1 and 5" cr + free-mem \ Freeing block 5 + dump-freelist + 3drop \ blocks 4, 3, 2 + free-mem + + dump-freelist + ; + +: testsuite-test3 ( -- ) + ." Test No. 3: freeing illegal address 0xdeadbeef." cr + deadbeef free-mem + dump-freelist + ; + +: testsuite ( -- ) + testsuite-init + testsuite-test1 + testsuite-test2 + testsuite-test3 + ; + +testsuite + +bye diff --git a/forth/testsuite/splitfunc-testsuite.fs b/forth/testsuite/splitfunc-testsuite.fs new file mode 100644 index 0000000..00469bb --- /dev/null +++ b/forth/testsuite/splitfunc-testsuite.fs @@ -0,0 +1,38 @@ +\ this is the splitfunc testsuite. +\ +\ run it with paflof < splitfunc-testsuite.fs 2>/dev/null + +\ implements split-before, split-after and left-split +\ as described in 4.3 (Path resolution) + +s" splitfunc.fs" included + +: test-split + s" var/log/messages" 2dup + + cr ." split-before test:" cr + 2dup ." String: " type cr + 2f split-before + 2swap + ." initial: " type cr ." remainder:" type cr + cr + ." split-after test:" cr + 2f split-after cr + 2swap + ." initial: " type cr ." remainder:" type cr + + ." foobar test" cr + + s" foobar" 2dup + + 2f split-after cr + 2swap + ." initial: " type cr ." remainder:" type cr + + 2f split-after cr + 2swap + ." initial: " type cr ." remainder:" type cr + ; + + + diff --git a/forth/util/apic.fs b/forth/util/apic.fs new file mode 100644 index 0000000..82a62aa --- /dev/null +++ b/forth/util/apic.fs @@ -0,0 +1,62 @@ +\ +\ ioapic and local apic tester +\ +\ Copyright (C) 2003 Stefan Reinauer +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +hex + +fee00000 constant lapic_base +fec00000 constant ioapic_base + +: read_lapic ( regoffset -- value ) + lapic_base + l@ + ; + +: write_lapic ( value regoffset -- ) + lapic_base + l! + ; + +: read_ioapic ( regoffset -- low_value high_value ) + 2* 10 + dup + ioapic_base l! ioapic_base 4 cells + l@ + swap 1+ + ioapic_base l! ioapic_base 4 cells + l@ + ; + +: write_ioapic ( low high regoffset -- ) + 2* 10 + dup ( low high offs offs ) + ioapic_base l! rot ioapic_base 4 cells + l! ( high offs ) + 1+ + ioapic_base l! ioapic_base 4 cells + l! ( high offs ) + ; + +: test-lapic + s" Dumping local apic:" type cr + 3f0 0 do + i dup ( lapic_base + ) s" 0x" type . s" = 0x" type read_lapic space . + i 30 and 0= if cr then + 10 +loop + cr + ; + +: test-ioapic + s" Dumping io apic:" type cr + 17 0 do + i dup s" irq=" type . read_ioapic s" = 0x" type . s" ." type . + i 1 and 0<> if + cr + then + loop + cr + ; + +: dump-apics + test-lapic + test-ioapic + ; + +\ tag: apic test utility diff --git a/forth/util/build.xml b/forth/util/build.xml new file mode 100644 index 0000000..4839d2c --- /dev/null +++ b/forth/util/build.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/forth/util/pci.fs b/forth/util/pci.fs new file mode 100644 index 0000000..3d15619 --- /dev/null +++ b/forth/util/pci.fs @@ -0,0 +1,127 @@ +\ tag: PCI helper functions +\ +\ Copyright (C) 2003-2004 Stefan Reinauer +\ Copyright (C) 2003 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ simple set of words for pci access, these are not +\ compliant to the PCI bus binding of OpenFirmware. + +\ only forth +\ vocabulary pci +\ also pci definitions + +hex + +: busdevfn ( bus dev fn -- busdevfn ) + 7 and swap + 1f and 3 << or ( dev fn -- devfn ) + swap 8 << or ( bus devfn -- busdevfn ) + ; + +: config-command ( busdevfn reg -- reg addr ) + dup -rot + 3 invert and + swap 8 << or + 80000000 or + ; + +: pci-c@ ( busdevfn reg -- x ) + config-command + cf8 iol! + 3 and cfc + + ioc@ + ; + +: pci-w@ ( busdevfn reg -- x ) + config-command + cf8 iol! + 2 and cfc + iow@ + ; + +: pci-l@ ( busdevfn reg -- x ) + config-command + cf8 iol! + drop + cfc iol@ + ; + +: pci-c! ( busdevfn reg val -- ) + -rot config-command + cf8 iol! + 3 and cfc + ioc! + ; + +: pci-w! ( busdevfn reg val -- ) + -rot config-command + cf8 iol! + 2 and cfc + iow! + ; + +: pci-l! ( busdevfn reg val -- ) + -rot config-command + cf8 iol! + drop + cfc iol! + ; + +: dump-pci-device ( bus dev fn -- ) + 2 pick (.) type 3a emit over + (.) type 2e emit dup (.) type 20 emit 5b emit \ 0:18.0 [ + busdevfn >r + r@ 0 pci-w@ u. 2f emit r@ 2 pci-w@ u. 5d emit \ 1022/1100] + r> + \ now we iterate + 10 0 do + cr i todigit emit 30 emit 3a emit 20 emit + 10 0 do + dup i j 4 << or pci-c@ + dup 4 >> todigit emit f and todigit emit + 20 emit + loop + loop + drop + cr cr + ; + +\ : test-pci +\ 0 2 0 dump-pci-device +\ ; + +\ only forth + + +\ ------------------------------------------------------------------------- +\ PCI encode/decode unit +\ ------------------------------------------------------------------------- + +\ we only implement DD and DD,F +: encode-unit-pci ( phys.lo phy.mid phys.hi -- str len ) + nip nip ff00 and 8 >> dup 3 >> + swap 7 and + ( ddddd fff ) + + ?dup if + pocket tohexstr + " ," pocket tmpstrcat + else + 0 0 pocket tmpstrcpy + then + >r + rot pocket tohexstr r> tmpstrcat drop +; + +: decode-unit-pci-bus ( str len bus -- phys.lo phys.mid phys.hi ) + -rot ascii , left-split + ( addr-R len-R addr-L len-L ) + parse-hex b << f800 and + -rot parse-hex 8 << 700 and + or + ( bus phys.hi ) + swap ff and 10 << or + 0 0 rot +; + diff --git a/forth/util/util.fs b/forth/util/util.fs new file mode 100644 index 0000000..6f549bf --- /dev/null +++ b/forth/util/util.fs @@ -0,0 +1,95 @@ +\ tag: Utility functions +\ +\ Utility functions +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ ------------------------------------------------------------------------- +\ package utils +\ ------------------------------------------------------------------------- + +( method-str method-len package-str package-len -- xt|0 ) +: $find-package-method + find-package 0= if 2drop false exit then + find-method 0= if 0 then +; + +\ like $call-parent but takes an xt +: call-parent ( ... xt -- ??? ) + my-parent call-package +; + +: [active-package], + ['] (lit) , active-package , +; immediate + +\ ------------------------------------------------------------------------- +\ word creation +\ ------------------------------------------------------------------------- + +: ?mmissing ( name len -- 1 name len | 0 ) + 2dup active-package find-method + if 3drop false else true then +; + +\ install trivial open and close functions +: is-open ( -- ) + " open" ?mmissing if ['] true -rot is-xt-func then + " close" ?mmissing if 0 -rot is-xt-func then +; + +\ is-relay installs a relay function (a function that calls +\ a function with the same name but belonging to a different node). +\ The execution behaviour of xt should be ( -- ptr-to-ihandle ). +\ +: is-relay ( xt ph name-str name-len -- ) + rot >r 2dup r> find-method 0= if + \ function missing (not necessarily an error) + 3drop exit + then + + -rot is-func-begin + ( xt method-xt ) + ['] (lit) , , \ ['] method + , ['] @ , \ xt @ + ['] call-package , \ call-package + is-func-end +; + +\ ------------------------------------------------------------------------- +\ install deblocker bindings +\ ------------------------------------------------------------------------- + +: (open-deblocker) ( varaddr -- ) + " deblocker" find-package if + 0 0 rot open-package + else 0 then + swap ! +; + +: is-deblocker ( -- ) + " deblocker" find-package 0= if exit then >r + " deblocker" is-ivariable + + \ create open-deblocker + " open-deblocker" is-func-begin + dup , ['] (open-deblocker) , + is-func-end + + \ create close-deblocker + " close-deblocker" is-func-begin + dup , ['] @ , ['] close-package , + is-func-end + + ( save-ph deblk-xt R: deblocker-ph ) + r> + 2dup " read" is-relay + 2dup " seek" is-relay + 2dup " write" is-relay + 2dup " tell" is-relay + 2drop +; diff --git a/fs/build.xml b/fs/build.xml new file mode 100644 index 0000000..dfddfab --- /dev/null +++ b/fs/build.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/fs/grubfs/Kconfig b/fs/grubfs/Kconfig new file mode 100644 index 0000000..9de37bf --- /dev/null +++ b/fs/grubfs/Kconfig @@ -0,0 +1,84 @@ +config FSYS_EXT2FS + depends on GRUBFS + bool "EXT2 support" + default n + help + Include EXT2 filesystem support + +config FSYS_FAT + depends on GRUBFS + bool "(V)FAT support" + default n + help + Include VFAT/FAT (MSDOS / Windows95) filesystem support + +config FSYS_JFS + depends on GRUBFS + bool "JFS support" + default n + help + Include JFS support + +config FSYS_MINIX + depends on GRUBFS + bool "Minix filesystem support" + default n + help + Include Minix filesystem support + +config FSYS_REISERFS + depends on GRUBFS + bool "Reiser filesystem support" + default n + help + Include Reiser filesystem support + +config FSYS_XFS + depends on GRUBFS + bool "XFS support" + default n + help + Include XFS support + +config FSYS_UFS + depends on GRUBFS + bool "UFS/UFS2 support" + default n + help + Include UFS/UFS2 support + +config FSYS_ISO9660 + depends on GRUBFS + bool "ISO 9660 support" + default n + help + Include ISO9660 (cdrom) filesystem support + +config FSYS_FFS + depends on GRUBFS + bool "FreeBSD FFS support" + default n + help + Include FreeBSD FFS filesystem support + +config FSYS_VSTAFS + depends on GRUBFS + bool "VSTA filesystem support" + default n + help + Include VSTA filesystem support + +config FSYS_NTFS + depends on GRUBFS + bool "NT filesystem support" + default n + help + Include NTFS filesystem support + +config FSYS_AFFS + depends on GRUBFS + bool "Amiga fast filesystem support" + default n + help + Include Amiga FFS filesystem support + diff --git a/fs/grubfs/build.xml b/fs/grubfs/build.xml new file mode 100644 index 0000000..7469313 --- /dev/null +++ b/fs/grubfs/build.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/fs/grubfs/debug.h b/fs/grubfs/debug.h new file mode 100644 index 0000000..dc97c3e --- /dev/null +++ b/fs/grubfs/debug.h @@ -0,0 +1,3 @@ +/* for grub compatibility */ + + diff --git a/fs/grubfs/defs.h b/fs/grubfs/defs.h new file mode 100644 index 0000000..f2f2683 --- /dev/null +++ b/fs/grubfs/defs.h @@ -0,0 +1,94 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Common definitions for Berkeley Fast File System. + */ + +/* + * Compatibility definitions for disk IO. + */ + +/* + * Disk devices do all IO in 512-byte blocks. + */ +#define DEV_BSIZE 512 + +/* + * Conversion between bytes and disk blocks. + */ +#define btodb(byte_offset) ((byte_offset) >> 9) +#define dbtob(block_number) ((block_number) << 9) + +/* + * Compatibility definitions for old type names. + */ + +typedef unsigned char u_char; /* unsigned char */ +typedef unsigned short u_short; /* unsigned short */ +typedef unsigned int u_int; /* unsigned int */ + +typedef struct _quad_ + { + unsigned int val[2]; /* 2 int values make... */ + } +quad; /* an 8-byte item */ + +typedef unsigned int mach_time_t; /* an unsigned int */ +typedef unsigned int mach_daddr_t; /* an unsigned int */ +typedef unsigned int mach_off_t; /* another unsigned int */ + +typedef unsigned short mach_uid_t; +typedef unsigned short mach_gid_t; +typedef unsigned int mach_ino_t; + +#define NBBY 8 + +/* + * The file system is made out of blocks of at most MAXBSIZE units, + * with smaller units (fragments) only in the last direct block. + * MAXBSIZE primarily determines the size of buffers in the buffer + * pool. It may be made larger without any effect on existing + * file systems; however, making it smaller may make some file + * systems unmountable. + * + * Note that the disk devices are assumed to have DEV_BSIZE "sectors" + * and that fragments must be some multiple of this size. + */ +#define MAXBSIZE 8192 +#define MAXFRAG 8 + +/* + * MAXPATHLEN defines the longest permissible path length + * after expanding symbolic links. + * + * MAXSYMLINKS defines the maximum number of symbolic links + * that may be expanded in a path name. It should be set + * high enough to allow all legitimate uses, but halt infinite + * loops reasonably quickly. + */ + +#define MAXPATHLEN 1024 +#define MAXSYMLINKS 8 diff --git a/fs/grubfs/dir.h b/fs/grubfs/dir.h new file mode 100644 index 0000000..287bf60 --- /dev/null +++ b/fs/grubfs/dir.h @@ -0,0 +1,147 @@ + +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)dir.h 7.6 (Berkeley) 5/9/89 + */ + +#ifndef _BOOT_UFS_DIR_H_ +#define _BOOT_UFS_DIR_H_ + +/* + * A directory consists of some number of blocks of DIRBLKSIZ + * bytes, where DIRBLKSIZ is chosen such that it can be transferred + * to disk in a single atomic operation (e.g. 512 bytes on most machines). + * + * Each DIRBLKSIZ byte block contains some number of directory entry + * structures, which are of variable length. Each directory entry has + * a struct direct at the front of it, containing its inode number, + * the length of the entry, and the length of the name contained in + * the entry. These are followed by the name padded to a 4 byte boundary + * with null bytes. All names are guaranteed null terminated. + * The maximum length of a name in a directory is MAXNAMLEN. + * + * The macro DIRSIZ(dp) gives the amount of space required to represent + * a directory entry. Free space in a directory is represented by + * entries which have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes + * in a directory block are claimed by the directory entries. This + * usually results in the last entry in a directory having a large + * dp->d_reclen. When entries are deleted from a directory, the + * space is returned to the previous entry in the same directory + * block by increasing its dp->d_reclen. If the first entry of + * a directory block is free, then its dp->d_ino is set to 0. + * Entries other than the first in a directory do not normally have + * dp->d_ino set to 0. + */ +#define DIRBLKSIZ DEV_BSIZE +#define MAXNAMLEN 255 + +struct direct + { + u_int d_ino; /* inode number of entry */ + u_short d_reclen; /* length of this record */ + u_short d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN + 1]; /* name with length <= MAXNAMLEN */ + }; + +/* + * The DIRSIZ macro gives the minimum record length which will hold + * the directory entry. This requires the amount of space in struct direct + * without the d_name field, plus enough space for the name with a terminating + * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. + */ +#undef DIRSIZ +#define DIRSIZ(dp) \ + ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) + +#ifdef KERNEL +/* + * Template for manipulating directories. + * Should use struct direct's, but the name field + * is MAXNAMLEN - 1, and this just won't do. + */ +struct dirtemplate + { + u_int dot_ino; + short dot_reclen; + short dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int dotdot_ino; + short dotdot_reclen; + short dotdot_namlen; + char dotdot_name[4]; /* ditto */ + }; +#endif + +/* + * The following information should be obtained from + * and is provided solely (and temporarily) for backward compatibility. + */ +#ifndef KERNEL +#define d_fileno d_ino /* compatibility with POSIX */ +#ifndef DEV_BSIZE +#define DEV_BSIZE 512 +#endif +/* + * Definitions for library routines operating on directories. + */ +typedef struct _dirdesc + { + int dd_fd; + int dd_loc; + int dd_size; + char dd_buf[DIRBLKSIZ]; + } +DIR; + +#define dirfd(dirp) ((dirp)->dd_fd) + +#ifndef NULL +#define NULL 0 +#endif +extern DIR *opendir (); +extern struct direct *readdir (); +extern int telldir (); +extern void seekdir (); +#define rewinddir(dirp) seekdir((dirp), (long)0) +extern void closedir (); +#endif /* not KERNEL */ +#endif /* _BOOT_UFS_DIR_H_ */ diff --git a/fs/grubfs/disk_inode.h b/fs/grubfs/disk_inode.h new file mode 100644 index 0000000..2103cb8 --- /dev/null +++ b/fs/grubfs/disk_inode.h @@ -0,0 +1,110 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)inode.h 7.5 (Berkeley) 7/3/89 + */ + +#ifndef _BOOT_UFS_DISK_INODE_H_ +#define _BOOT_UFS_DISK_INODE_H_ + +/* + * The I node is the focus of all file activity in the BSD Fast File System. + * There is a unique inode allocated for each active file, + * each current directory, each mounted-on file, text file, and the root. + * An inode is 'named' by its dev/inumber pair. (iget/iget.c) + * Data in icommon is read in from permanent inode on volume. + */ + +#define FFS_NDADDR 12 /* direct addresses in inode */ +#define FFS_NIADDR 3 /* indirect addresses in inode */ + +#define FFS_MAX_FASTLINK_SIZE ((FFS_NDADDR + FFS_NIADDR) \ + * sizeof (mach_daddr_t)) + +struct icommon + { + u_short ic_mode; /* 0: mode and type of file */ + short ic_nlink; /* 2: number of links to file */ + mach_uid_t ic_uid; /* 4: owner's user id */ + mach_gid_t ic_gid; /* 6: owner's group id */ + quad ic_size; /* 8: number of bytes in file */ + mach_time_t ic_atime; /* 16: time last accessed */ + int ic_atspare; + mach_time_t ic_mtime; /* 24: time last modified */ + int ic_mtspare; + mach_time_t ic_ctime; /* 32: last time inode changed */ + int ic_ctspare; + union + { + struct + { + mach_daddr_t Mb_db[FFS_NDADDR]; /* 40: disk block addresses */ + mach_daddr_t Mb_ib[FFS_NIADDR]; /* 88: indirect blocks */ + } + ic_Mb; + char ic_Msymlink[FFS_MAX_FASTLINK_SIZE]; + /* 40: symbolic link name */ + } + ic_Mun; +#define ic_db ic_Mun.ic_Mb.Mb_db +#define ic_ib ic_Mun.ic_Mb.Mb_ib +#define ic_symlink ic_Mun.ic_Msymlink + int ic_flags; /* 100: status, currently unused */ + int ic_blocks; /* 104: blocks actually held */ + int ic_gen; /* 108: generation number */ + int ic_spare[4]; /* 112: reserved, currently unused */ + }; + +/* + * Same structure, but on disk. + */ +struct dinode + { + union + { + struct icommon di_com; + char di_char[128]; + } + di_un; + }; +#define di_ic di_un.di_com + +#endif /* _BOOT_UFS_DISK_INODE_H_ */ diff --git a/fs/grubfs/disk_inode_ffs.h b/fs/grubfs/disk_inode_ffs.h new file mode 100644 index 0000000..1c8caa1 --- /dev/null +++ b/fs/grubfs/disk_inode_ffs.h @@ -0,0 +1,101 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)inode.h 7.5 (Berkeley) 7/3/89 + */ + +#ifndef _BOOT_UFS_DISK_INODE_FFS_H_ +#define _BOOT_UFS_DISK_INODE_FFS_H_ + +#define NDADDR FFS_NDADDR +#define NIADDR FFS_NIADDR + +#define MAX_FASTLINK_SIZE FFS_MAX_FASTLINK_SIZE + +#define IC_FASTLINK 0x0001 /* Symbolic link in inode */ + +#define i_mode ic_mode +#define i_nlink ic_nlink +#define i_uid ic_uid +#define i_gid ic_gid +#if defined(BYTE_MSF) && BYTE_MSF +#define i_size ic_size.val[1] +#else /* BYTE_LSF */ +#define i_size ic_size.val[0] +#endif +#define i_db ic_db +#define i_ib ic_ib +#define i_atime ic_atime +#define i_mtime ic_mtime +#define i_ctime ic_ctime +#define i_blocks ic_blocks +#define i_rdev ic_db[0] +#define i_symlink ic_symlink +#define i_flags ic_flags +#define i_gen ic_gen + +/* modes */ +#define IFMT 0xf000 /* type of file */ +#define IFCHR 0x2000 /* character special */ +#define IFDIR 0x4000 /* directory */ +#define IFBLK 0x6000 /* block special */ +#define IFREG 0x8000 /* regular */ +#define IFLNK 0xa000 /* symbolic link */ +#define IFSOCK 0xc000 /* socket */ + + +#define ISUID 0x0800 /* set user id on execution */ +#define ISGID 0x0400 /* set group id on execution */ +#define ISVTX 0x0200 /* save swapped text even after use */ +#define IREAD 0x0100 /* read, write, execute permissions */ +#define IWRITE 0x0080 +#define IEXEC 0x0040 + +#ifdef EEK +#define f_fs u.ffs.ffs_fs +#define i_ic u.ffs.ffs_ic +#define f_nindir u.ffs.ffs_nindir +#define f_blk u.ffs.ffs_blk +#define f_blksize u.ffs.ffs_blksize +#define f_blkno u.ffs.ffs_blkno +#endif /* EEK */ + +#endif /* _BOOT_UFS_DISK_INODE_FFS_H_ */ diff --git a/fs/grubfs/fat.h b/fs/grubfs/fat.h new file mode 100644 index 0000000..7fed6ba --- /dev/null +++ b/fs/grubfs/fat.h @@ -0,0 +1,100 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* + * Defines for the FAT BIOS Parameter Block (embedded in the first block + * of the partition. + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; + +/* Note that some shorts are not aligned, and must therefore + * be declared as array of two bytes. + */ +struct fat_bpb { + __s8 ignored[3]; /* Boot strap short or near jump */ + __s8 system_id[8]; /* Name - can be used to special case + partition manager volumes */ + __u8 bytes_per_sect[2]; /* bytes per logical sector */ + __u8 sects_per_clust;/* sectors/cluster */ + __u8 reserved_sects[2]; /* reserved sectors */ + __u8 num_fats; /* number of FATs */ + __u8 dir_entries[2]; /* root directory entries */ + __u8 short_sectors[2]; /* number of sectors */ + __u8 media; /* media code (unused) */ + __u16 fat_length; /* sectors/FAT */ + __u16 secs_track; /* sectors per track */ + __u16 heads; /* number of heads */ + __u32 hidden; /* hidden sectors (unused) */ + __u32 long_sectors; /* number of sectors (if short_sectors == 0) */ + + /* The following fields are only used by FAT32 */ + __u32 fat32_length; /* sectors/FAT */ + __u16 flags; /* bit 8: fat mirroring, low 4: active fat */ + __u8 version[2]; /* major, minor filesystem version */ + __u32 root_cluster; /* first cluster in root directory */ + __u16 info_sector; /* filesystem info sector */ + __u16 backup_boot; /* backup boot sector */ + __u16 reserved2[6]; /* Unused */ +}; + +#define FAT_CVT_U16(bytarr) (* (__u16*)(bytarr)) + +/* + * Defines how to differentiate a 12-bit and 16-bit FAT. + */ + +#define FAT_MAX_12BIT_CLUST 4087 /* 4085 + 2 */ + +/* + * Defines for the file "attribute" byte + */ + +#define FAT_ATTRIB_OK_MASK 0x37 +#define FAT_ATTRIB_NOT_OK_MASK 0xC8 +#define FAT_ATTRIB_DIR 0x10 +#define FAT_ATTRIB_LONGNAME 0x0F + +/* + * Defines for FAT directory entries + */ + +#define FAT_DIRENTRY_LENGTH 32 + +#define FAT_DIRENTRY_ATTRIB(entry) \ + (*((unsigned char *) (entry+11))) +#define FAT_DIRENTRY_VALID(entry) \ + ( ((*((unsigned char *) entry)) != 0) \ + && ((*((unsigned char *) entry)) != 0xE5) \ + && !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) ) +#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \ + ((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16)) +#define FAT_DIRENTRY_FILELENGTH(entry) \ + (*((unsigned long *) (entry+28))) + +#define FAT_LONGDIR_ID(entry) \ + (*((unsigned char *) (entry))) +#define FAT_LONGDIR_ALIASCHECKSUM(entry) \ + (*((unsigned char *) (entry+13))) diff --git a/fs/grubfs/filesys.h b/fs/grubfs/filesys.h new file mode 100644 index 0000000..d38cdd3 --- /dev/null +++ b/fs/grubfs/filesys.h @@ -0,0 +1,302 @@ +/* GRUB compatibility header + * + * taken from filo and grub. + */ + +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2003 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* This disables some portion of code */ +#define STAGE1_5 1 + +#if defined CONFIG_X86 +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +static __inline__ unsigned int +ffz (unsigned int word) +{ + __asm__ ("bsfl %1,%0" + : "=r" (word) + : "r" (~word)); + return word; +} + +static __inline__ unsigned int +log2 (unsigned int word) +{ + __asm__ ("bsfl %1,%0" + : "=r" (word) + : "r" (word)); + return word; +} + +#elif defined (CONFIG_PPC) +static __inline__ unsigned long + __ilog2(unsigned long x) +{ + unsigned long lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x)); + return 31 - lz; +} + +static __inline__ unsigned long +ffz(unsigned long x) +{ + if ((x = ~x) == 0) + return 32; + + return __ilog2(x & -x); +} + +#define log2(n) ffz(~(n)) + +#else + +static __inline__ unsigned int log2(unsigned int word) +{ + /* assume 8 bits per byte. */ + unsigned int i = 1 << (sizeof(word)*8 - 1); + unsigned int pow = sizeof(word) * 8 - 1; + + if (! word) { + /* invalid parameter */ + return -1; + } + for(; i > word; i >>= 1, pow--) ; + + return pow; +} + +#define ffz(n) log2(~(n)) + +#endif + +static inline int +substring (const char *s1, const char *s2) +{ + while (*s1 == *s2) + { + /* The strings match exactly. */ + if (! *(s1++)) + return 0; + s2 ++; + } + + /* S1 is a substring of S2. */ + if (*s1 == 0) + return -1; + + /* S1 isn't a substring. */ + return 1; +} + +#define grub_memmove memmove +#define grub_strcmp strcmp + +#define MAXINT 0x7fffffff + +/* This is only used by fsys_* to determine if it's hard disk. If it is, + * they try to guess filesystem type by partition type. I guess it is + * not necessory, so hardcoded to 0 (first floppy) --ts1 */ +#define current_drive 0 +#define current_slice 0 +#define current_partition 0 + +extern unsigned long part_start; +extern unsigned long part_length; +extern int filepos; +extern int filemax; +extern int fsmax; + +/* Error codes (descriptions are in common.c) */ +typedef enum +{ + ERR_NONE = 0, + ERR_BAD_FILENAME, + ERR_BAD_FILETYPE, + ERR_BAD_GZIP_DATA, + ERR_BAD_GZIP_HEADER, + ERR_BAD_PART_TABLE, + ERR_BAD_VERSION, + ERR_BELOW_1MB, + ERR_BOOT_COMMAND, + ERR_BOOT_FAILURE, + ERR_BOOT_FEATURES, + ERR_DEV_FORMAT, + ERR_DEV_VALUES, + ERR_EXEC_FORMAT, + ERR_FILELENGTH, + ERR_FILE_NOT_FOUND, + ERR_FSYS_CORRUPT, + ERR_FSYS_MOUNT, + ERR_GEOM, + ERR_NEED_LX_KERNEL, + ERR_NEED_MB_KERNEL, + ERR_NO_DISK, + ERR_NO_PART, + ERR_NUMBER_PARSING, + ERR_OUTSIDE_PART, + ERR_READ, + ERR_SYMLINK_LOOP, + ERR_UNRECOGNIZED, + ERR_WONT_FIT, + ERR_WRITE, + ERR_BAD_ARGUMENT, + ERR_UNALIGNED, + ERR_PRIVILEGED, + ERR_DEV_NEED_INIT, + ERR_NO_DISK_SPACE, + ERR_NUMBER_OVERFLOW, + + MAX_ERR_NUM +} grub_error_t; + +extern grub_error_t errnum; + +#define grub_open file_open +#define grub_read file_read +#define grub_seek file_seek +#define grub_close file_close + +/* instrumentation variables */ +/* (Not used in FILO) */ +extern void (*disk_read_hook) (int, int, int); +extern void (*disk_read_func) (int, int, int); + +#define FSYS_BUFLEN 0x8000 +extern char FSYS_BUF[FSYS_BUFLEN]; + +#define print_possibilities 0 + +#define SECTOR_SIZE 512 +#define SECTOR_BITS 9 + +#ifdef CONFIG_FSYS_FAT +int fat_mount (void); +int fat_read (char *buf, int len); +int fat_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_EXT2FS +int ext2fs_mount (void); +int ext2fs_read (char *buf, int len); +int ext2fs_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_MINIX +int minix_mount (void); +int minix_read (char *buf, int len); +int minix_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_REISERFS +int reiserfs_mount (void); +int reiserfs_read (char *buf, int len); +int reiserfs_dir (char *dirname); +int reiserfs_embed (int *start_sector, int needed_sectors); +#endif + +#ifdef CONFIG_FSYS_JFS +int jfs_mount (void); +int jfs_read (char *buf, int len); +int jfs_dir (char *dirname); +int jfs_embed (int *start_sector, int needed_sectors); +#endif + +#ifdef CONFIG_FSYS_XFS +int xfs_mount (void); +int xfs_read (char *buf, int len); +int xfs_dir (char *dirname); +#endif + +#ifdef CONFIG_FSYS_UFS +int ufs_mount (void); +int ufs_read (char *buf, int len); +int ufs_dir (char *dirname); +int ufs_embed (int *start_sector, int needed_sectors); +#endif + +#ifdef CONFIG_FSYS_ISO9660 +int iso9660_mount (void); +int iso9660_read (char *buf, int len); +int iso9660_dir (char *dirname); +#endif + +/* This is not a flag actually, but used as if it were a flag. */ +#define PC_SLICE_TYPE_HIDDEN_FLAG 0x10 + +#define PC_SLICE_TYPE_NONE 0 +#define PC_SLICE_TYPE_FAT12 1 +#define PC_SLICE_TYPE_FAT16_LT32M 4 +#define PC_SLICE_TYPE_EXTENDED 5 +#define PC_SLICE_TYPE_FAT16_GT32M 6 +#define PC_SLICE_TYPE_FAT32 0xb +#define PC_SLICE_TYPE_FAT32_LBA 0xc +#define PC_SLICE_TYPE_FAT16_LBA 0xe +#define PC_SLICE_TYPE_WIN95_EXTENDED 0xf +#define PC_SLICE_TYPE_EZD 0x55 +#define PC_SLICE_TYPE_MINIX 0x80 +#define PC_SLICE_TYPE_LINUX_MINIX 0x81 +#define PC_SLICE_TYPE_EXT2FS 0x83 +#define PC_SLICE_TYPE_LINUX_EXTENDED 0x85 +#define PC_SLICE_TYPE_VSTAFS 0x9e +#define PC_SLICE_TYPE_DELL_UTIL 0xde +#define PC_SLICE_TYPE_LINUX_RAID 0xfd + +/* For convinience. */ +/* Check if TYPE is a FAT partition type. Clear the hidden flag before + the check, to allow the user to mount a hidden partition in GRUB. */ +#define IS_PC_SLICE_TYPE_FAT(type) \ + ({ int _type = (type) & ~PC_SLICE_TYPE_HIDDEN_FLAG; \ + _type == PC_SLICE_TYPE_FAT12 \ + || _type == PC_SLICE_TYPE_FAT16_LT32M \ + || _type == PC_SLICE_TYPE_FAT16_GT32M \ + || _type == PC_SLICE_TYPE_FAT16_LBA \ + || _type == PC_SLICE_TYPE_FAT32 \ + || _type == PC_SLICE_TYPE_FAT32_LBA \ + || _type == PC_SLICE_TYPE_DELL_UTIL; }) + +#define IS_PC_SLICE_TYPE_MINIX(type) \ + (((type) == PC_SLICE_TYPE_MINIX) \ + || ((type) == PC_SLICE_TYPE_LINUX_MINIX)) + +#define IS_PC_SLICE_TYPE_BSD_WITH_FS(type,fs) 0 + +/* possible values for the *BSD-style partition type */ +#define FS_UNUSED 0 /* unused */ +#define FS_SWAP 1 /* swap */ +#define FS_V6 2 /* Sixth Edition */ +#define FS_V7 3 /* Seventh Edition */ +#define FS_SYSV 4 /* System V */ +#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define FS_V8 6 /* Eighth Edition, 4K blocks */ +#define FS_BSDFFS 7 /* 4.2BSD fast file system */ +#define FS_MSDOS 8 /* MSDOS file system */ +#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */ +#define FS_OTHER 10 /* in use, but unknown/unsupported */ +#define FS_HPFS 11 /* OS/2 high-performance file system */ +#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */ +#define FS_BOOT 13 /* partition contains bootstrap */ +#define FS_ADOS 14 /* AmigaDOS fast file system */ +#define FS_HFS 15 /* Macintosh HFS */ +#define FS_FILECORE 16 /* Acorn Filecore Filing System */ +#define FS_EXT2FS 17 /* Linux Extended 2 file system */ diff --git a/fs/grubfs/fs.h b/fs/grubfs/fs.h new file mode 100644 index 0000000..8ed4fe0 --- /dev/null +++ b/fs/grubfs/fs.h @@ -0,0 +1,457 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)fs.h 7.7 (Berkeley) 5/9/89 + */ + +/* + * Each disk drive contains some number of file systems. + * A file system consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A file system is described by its super-block, which in turn + * describes the cylinder groups. The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss. This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For file system fs, the offsets of the various blocks of interest + * are given in the super block as: + * [fs->fs_sblkno] Super-block + * [fs->fs_cblkno] Cylinder group block + * [fs->fs_iblkno] Inode blocks + * [fs->fs_dblkno] Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * The first boot and super blocks are given in absolute disk addresses. + * The byte-offset forms are preferred, as they don't imply a sector size. + */ +#define BBSIZE 8192 +#define SBSIZE 8192 +#define BBOFF ((mach_off_t)(0)) +#define SBOFF ((mach_off_t)(BBOFF + BBSIZE)) +#define BBLOCK ((mach_daddr_t)(0)) +#define SBLOCK ((mach_daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) + +/* + * Addresses stored in inodes are capable of addressing fragments + * of `blocks'. File system blocks of at most size MAXBSIZE can + * be optionally broken into 2, 4, or 8 pieces, each of which is + * addressible; these pieces may be DEV_BSIZE, or some multiple of + * a DEV_BSIZE unit. + * + * Large files consist of exclusively large data blocks. To avoid + * undue wasted disk space, the last data block of a small file may be + * allocated as only as many fragments of a large block as are + * necessary. The file system format retains only a single pointer + * to such a fragment, which is a piece of a single large block that + * has been divided. The size of such a fragment is determinable from + * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. + * + * The file system records space availability at the fragment level; + * to determine block availability, aligned fragments are examined. + * + * The root inode is the root of the file system. + * Inode 0 can't be used for normal purposes and + * historically bad blocks were linked to inode 1, + * thus the root inode is 2. (inode 1 is no longer used for + * this purpose, however numerous dump tapes make this + * assumption, so we are stuck with it) + */ +#define ROOTINO ((mach_ino_t)2) /* i number of all roots */ + +/* + * MINBSIZE is the smallest allowable block size. + * In order to insure that it is possible to create files of size + * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. + * MINBSIZE must be big enough to hold a cylinder group block, + * thus changes to (struct cg) must keep its size within MINBSIZE. + * Note that super blocks are always of size SBSIZE, + * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. + */ +#define MINBSIZE 4096 + +/* + * The path name on which the file system is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + * The limit on the amount of summary information per file system + * is defined by MAXCSBUFS. It is currently parameterized for a + * maximum of two million cylinders. + */ +#define MAXMNTLEN 512 +#define MAXCSBUFS 32 + +/* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks. These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + * + * N.B. sizeof(struct csum) must be a power of two in order for + * the ``fs_cs'' macro to work (see below). + */ +struct csum + { + int cs_ndir; /* number of directories */ + int cs_nbfree; /* number of free blocks */ + int cs_nifree; /* number of free inodes */ + int cs_nffree; /* number of free frags */ + }; + +/* + * Super block for a file system. + */ +#define FS_MAGIC 0x011954 +struct fs + { + int xxx1; /* struct fs *fs_link; */ + int xxx2; /* struct fs *fs_rlink; */ + mach_daddr_t fs_sblkno; /* addr of super-block in filesys */ + mach_daddr_t fs_cblkno; /* offset of cyl-block in filesys */ + mach_daddr_t fs_iblkno; /* offset of inode-blocks in filesys */ + mach_daddr_t fs_dblkno; /* offset of first data after cg */ + int fs_cgoffset; /* cylinder group offset in cylinder */ + int fs_cgmask; /* used to calc mod fs_ntrak */ + mach_time_t fs_time; /* last time written */ + int fs_size; /* number of blocks in fs */ + int fs_dsize; /* number of data blocks in fs */ + int fs_ncg; /* number of cylinder groups */ + int fs_bsize; /* size of basic blocks in fs */ + int fs_fsize; /* size of frag blocks in fs */ + int fs_frag; /* number of frags in a block in fs */ +/* these are configuration parameters */ + int fs_minfree; /* minimum percentage of free blocks */ + int fs_rotdelay; /* num of ms for optimal next block */ + int fs_rps; /* disk revolutions per second */ +/* these fields can be computed from the others */ + int fs_bmask; /* ``blkoff'' calc of blk offsets */ + int fs_fmask; /* ``fragoff'' calc of frag offsets */ + int fs_bshift; /* ``lblkno'' calc of logical blkno */ + int fs_fshift; /* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ + int fs_maxcontig; /* max number of contiguous blks */ + int fs_maxbpg; /* max number of blks per cyl group */ +/* these fields can be computed from the others */ + int fs_fragshift; /* block to frag shift */ + int fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int fs_sbsize; /* actual size of super block */ + int fs_csmask; /* csum block offset */ + int fs_csshift; /* csum block number */ + int fs_nindir; /* value of NINDIR */ + int fs_inopb; /* value of INOPB */ + int fs_nspf; /* value of NSPF */ +/* yet another configuration parameter */ + int fs_optim; /* optimization preference, see below */ +/* these fields are derived from the hardware */ + int fs_npsect; /* # sectors/track including spares */ + int fs_interleave; /* hardware sector interleave */ + int fs_trackskew; /* sector 0 skew, per track */ + int fs_headswitch; /* head switch time, usec */ + int fs_trkseek; /* track-to-track seek, usec */ +/* sizes determined by number of cylinder groups and their sizes */ + mach_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int fs_cssize; /* size of cyl grp summary area */ + int fs_cgsize; /* cylinder group size */ +/* these fields are derived from the hardware */ + int fs_ntrak; /* tracks per cylinder */ + int fs_nsect; /* sectors per track */ + int fs_spc; /* sectors per cylinder */ +/* this comes from the disk driver partitioning */ + int fs_ncyl; /* cylinders in file system */ +/* these fields can be computed from the others */ + int fs_cpg; /* cylinders per group */ + int fs_ipg; /* inodes per group */ + int fs_fpg; /* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ + struct csum fs_cstotal; /* cylinder summary information */ +/* these fields are cleared at mount time */ + char fs_fmod; /* super block modified flag */ + char fs_clean; /* file system is clean flag */ + char fs_ronly; /* mounted read-only flag */ + char fs_flags; /* currently unused flag */ + char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ +/* these fields retain the current block allocation info */ + int fs_cgrotor; /* last cg searched */ +#if 1 + int was_fs_csp[MAXCSBUFS]; +#else + struct csum *fs_csp[MAXCSBUFS]; /* list of fs_cs info buffers */ +#endif + int fs_cpc; /* cyl per cycle in postbl */ + short fs_opostbl[16][8]; /* old rotation block list head */ + long fs_sparecon[50]; /* reserved for future constants */ + long fs_contigsumsize; /* size of cluster summary array */ + long fs_maxsymlinklen; /* max length of an internal symlink */ + long fs_inodefmt; /* format of on-disk inodes */ + quad fs_maxfilesize; /* maximum representable file size */ + quad fs_qbmask; /* ~fs_bmask - for use with quad size */ + quad fs_qfmask; /* ~fs_fmask - for use with quad size */ + long fs_state; /* validate fs_clean field */ + int fs_postblformat; /* format of positional layout tables */ + int fs_nrpos; /* number of rotaional positions */ + int fs_postbloff; /* (short) rotation block list head */ + int fs_rotbloff; /* (u_char) blocks for each rotation */ + int fs_magic; /* magic number */ + u_char fs_space[1]; /* list of blocks for each rotation */ +/* actually longer */ + }; +/* + * Preference for optimization. + */ +#define FS_OPTTIME 0 /* minimize allocation time */ +#define FS_OPTSPACE 1 /* minimize disk fragmentation */ + +/* + * Rotational layout table format types + */ +#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ +#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ +/* + * Macros for access to superblock array structures + */ +#define fs_postbl(fs, cylno) \ + (((fs)->fs_postblformat == FS_42POSTBLFMT) \ + ? ((fs)->fs_opostbl[cylno]) \ + : ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) +#define fs_rotbl(fs) \ + (((fs)->fs_postblformat == FS_42POSTBLFMT) \ + ? ((fs)->fs_space) \ + : ((u_char *)((char *)(fs) + (fs)->fs_rotbloff))) + +/* + * Convert cylinder group to base address of its global summary info. + * + * N.B. This macro assumes that sizeof(struct csum) is a power of two. + */ +#define fs_cs(fs, indx) \ + fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask] + +/* + * Cylinder group block for a file system. + */ +#define CG_MAGIC 0x090255 +struct cg + { + int xxx1; /* struct cg *cg_link; */ + int cg_magic; /* magic number */ + mach_time_t cg_time; /* time last written */ + int cg_cgx; /* we are the cgx'th cylinder group */ + short cg_ncyl; /* number of cyl's this cg */ + short cg_niblk; /* number of inode blocks this cg */ + int cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + int cg_rotor; /* position of last used block */ + int cg_frotor; /* position of last used frag */ + int cg_irotor; /* position of last used inode */ + int cg_frsum[MAXFRAG]; /* counts of available frags */ + int cg_btotoff; /* (long) block totals per cylinder */ + int cg_boff; /* (short) free block positions */ + int cg_iusedoff; /* (char) used inode map */ + int cg_freeoff; /* (u_char) free block map */ + int cg_nextfreeoff; /* (u_char) next available space */ + int cg_sparecon[16]; /* reserved for future use */ + u_char cg_space[1]; /* space for cylinder group maps */ +/* actually longer */ + }; +/* + * Macros for access to cylinder group array structures + */ +#define cg_blktot(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_btot) \ + : ((int *)((char *)(cgp) + (cgp)->cg_btotoff))) +#define cg_blks(fs, cgp, cylno) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_b[cylno]) \ + : ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) +#define cg_inosused(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_iused) \ + : ((char *)((char *)(cgp) + (cgp)->cg_iusedoff))) +#define cg_blksfree(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_free) \ + : ((u_char *)((char *)(cgp) + (cgp)->cg_freeoff))) +#define cg_chkmagic(cgp) \ + ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC) + +/* + * The following structure is defined + * for compatibility with old file systems. + */ +struct ocg + { + int xxx1; /* struct ocg *cg_link; */ + int xxx2; /* struct ocg *cg_rlink; */ + mach_time_t cg_time; /* time last written */ + int cg_cgx; /* we are the cgx'th cylinder group */ + short cg_ncyl; /* number of cyl's this cg */ + short cg_niblk; /* number of inode blocks this cg */ + int cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + int cg_rotor; /* position of last used block */ + int cg_frotor; /* position of last used frag */ + int cg_irotor; /* position of last used inode */ + int cg_frsum[8]; /* counts of available frags */ + int cg_btot[32]; /* block totals per cylinder */ + short cg_b[32][8]; /* positions of free blocks */ + char cg_iused[256]; /* used inode map */ + int cg_magic; /* magic number */ + u_char cg_free[1]; /* free block map */ +/* actually longer */ + }; + +/* + * Turn file system block numbers into disk block addresses. + * This maps file system blocks to device size blocks. + */ +#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb) +#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc file system addresses of cylinder group data structures. + */ +#define cgbase(fs, c) ((mach_daddr_t)((fs)->fs_fpg * (c))) +#define cgstart(fs, c) \ + (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask))) +#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ +#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ +#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ +#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ + +/* + * Macros for handling inode numbers: + * inode number to file system block offset. + * inode number to cylinder group number. + * inode number to file system block address. + */ +#define itoo(fs, x) ((x) % INOPB(fs)) +#define itog(fs, x) ((x) / (fs)->fs_ipg) +#define itod(fs, x) \ + ((mach_daddr_t)(cgimin(fs, itog(fs, x)) + \ + (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) + +/* + * Give cylinder group number for a file system block. + * Give cylinder group block number for a file system block. + */ +#define dtog(fs, d) ((d) / (fs)->fs_fpg) +#define dtogd(fs, d) ((d) % (fs)->fs_fpg) + +/* + * Extract the bits for a block from a map. + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define blkmap(fs, map, loc) \ + (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) +#define cbtocylno(fs, bno) \ + ((bno) * NSPF(fs) / (fs)->fs_spc) +#define cbtorpos(fs, bno) \ + (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \ + (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \ + (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \ + ((loc) & ~(fs)->fs_bmask) +#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ + ((loc) & ~(fs)->fs_fmask) +#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \ + ((loc) >> (fs)->fs_bshift) +#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ + ((loc) >> (fs)->fs_fshift) +#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \ + (((size) + (fs)->fs_bsize - 1) & (fs)->fs_bmask) +#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \ + (((size) + (fs)->fs_fsize - 1) & (fs)->fs_fmask) +#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \ + ((frags) >> (fs)->fs_fragshift) +#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \ + ((blks) << (fs)->fs_fragshift) +#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \ + ((fsb) & ((fs)->fs_frag - 1)) +#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \ + ((fsb) &~ ((fs)->fs_frag - 1)) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve + */ +#define freespace(fs, percentreserved) \ + (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ + (fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100)) + +/* + * Determining the size of a file block in the file system. + */ +#define blksize(fs, ip, lbn) \ + (((lbn) >= NDADDR || (ip)->i_size >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) +#define dblksize(fs, dip, lbn) \ + (((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) + +/* + * Number of disk sectors per block; assumes DEV_BSIZE byte sector size. + */ +#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift) +#define NSPF(fs) ((fs)->fs_nspf) + +/* + * INOPB is the number of inodes in a secondary storage block. + */ +#define INOPB(fs) ((fs)->fs_inopb) +#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) + +/* + * NINDIR is the number of indirects in a file system block. + */ +#define NINDIR(fs) ((fs)->fs_nindir) diff --git a/fs/grubfs/fsys_affs.c b/fs/grubfs/fsys_affs.c new file mode 100644 index 0000000..3b11183 --- /dev/null +++ b/fs/grubfs/fsys_affs.c @@ -0,0 +1,702 @@ +#ifdef FSYS_AFFS +#include "shared.h" +#include "filesys.h" + +/******************************** RDB definitions */ +#define RDB_LOCATION_LIMIT 16 +#define IDNAME_RIGIDDISK 0x5244534B /* 'RDSK' */ + +struct RigidDiskBlock +{ + unsigned long rdb_ID; + unsigned long rdb_SummedLongs; + long rdb_ChkSum; + unsigned long rdb_HostID; + unsigned long rdb_BlockBytes; + unsigned long rdb_Flags; + unsigned long rdb_BadBlockList; + unsigned long rdb_PartitionList; + unsigned long rdb_FileSysHeaderList; + unsigned long rdb_DriveInit; + unsigned long rdb_Reserved1[6]; + unsigned long rdb_Cylinders; + unsigned long rdb_Sectors; + unsigned long rdb_Heads; + unsigned long rdb_Interleave; + unsigned long rdb_Park; + unsigned long rdb_Reserved2[3]; + unsigned long rdb_WritePreComp; + unsigned long rdb_ReducedWrite; + unsigned long rdb_StepRate; + unsigned long rdb_Reserved3[5]; + unsigned long rdb_RDBBlocksLo; + unsigned long rdb_RDBBlocksHi; + unsigned long rdb_LoCylinder; + unsigned long rdb_HiCylinder; + unsigned long rdb_CylBlocks; + unsigned long rdb_AutoParkSeconds; + unsigned long rdb_HighRDSKBlock; + unsigned long rdb_Reserved4; + char rdb_DiskVendor[8]; + char rdb_DiskProduct[16]; + char rdb_DiskRevision[4]; + char rdb_ControllerVendor[8]; + char rdb_ControllerProduct[16]; + char rdb_ControllerRevision[4]; + char rdb_DriveInitName[40]; +}; + +struct PartitionBlock +{ + unsigned long pb_ID; + unsigned long pb_SummedLongs; + long pb_ChkSum; + unsigned long pb_HostID; + unsigned long pb_Next; + unsigned long pb_Flags; + unsigned long pb_Reserved1[2]; + unsigned long pb_DevFlags; + unsigned char pb_DriveName[32]; + unsigned long pb_Reserved2[15]; + unsigned long pb_Environment[20]; + unsigned long pb_EReserved[12]; +}; + +#define DE_TABLESIZE 0 +#define DE_SIZEBLOCK 1 +#define DE_BLOCKSIZE 2 +#define DE_NUMHEADS 3 +#define DE_SECSPERBLOCK 4 +#define DE_BLKSPERTRACK 5 +#define DE_RESERVEDBLKS 6 +#define DE_PREFAC 7 +#define DE_INTERLEAVE 8 +#define DE_LOWCYL 9 +#define DE_HIGHCYL 10 +#define DE_UPPERCYL DE_HIGHCYL +#define DE_NUMBUFFERS 11 +#define DE_BUFMEMTYPE 12 +#define DE_MEMBUFTYPE DE_BUFMEMTYPE +#define DE_MAXTRANSFER 13 +#define DE_MASK 14 +#define DE_BOOTPRI 15 +#define DE_DOSTYPE 16 +#define DE_BAUD 17 +#define DE_CONTROL 18 +#define DE_BOOTBLOCKS 19 + + +/******************************** AFFS definitions */ +#define T_SHORT 2 +#define T_LIST 16 + +#define ST_FILE -3 +#define ST_ROOT 1 +#define ST_USERDIR 2 + +struct BootBlock{ + int id; + int chksum; + int rootblock; + int data[127]; +}; + +struct RootBlock{ + int p_type; //0 + int n1[2]; //1-2 + int hashtable_size; //3 + int n2; //4 + int checksum; //5 + int hashtable[72]; //6-77 + int bitmap_valid_flag; //78 + int bitmap_ptrs[25]; //79-103 + int bitmap_extension; //104 + int root_days; //105 + int root_mins; //106 + int root_ticks; //107; + char diskname[32]; //108-115 + int n3[2]; //116-117 + int volume_days; //118 + int volume_mins; //119 + int volume_ticks; //120 + int creation_days; //121 + int creation_mins; //122 + int creation_ticks; //123 + int n4[3]; //124-126 + int s_type; //127 +}; + +struct DirHeader { + int p_type; //0 + int own_key; //1 + int n1[3]; //2-4 + int checksum; //5 + int hashtable[72]; //6-77 + int n2; //78 + int owner; //79 + int protection; //80 + int n3; //81 + char comment[92]; //82-104 + int days; //105 + int mins; //106 + int ticks; //107 + char name[32]; //108-115 + int n4[2]; //116-117 + int linkchain; //118 + int n5[5]; //119-123 + int hashchain; //124 + int parent; //125 + int n6; //126 + int s_type; //127 +}; + +struct FileHeader { + int p_type; //0 + int own_key; //1 + int n1[3]; //2-4 + int checksum; //5 + int filekey_table[72]; //6-77 + int n2; //78 + int owner; //79 + int protection; //80 + int bytesize; //81 + char comment[92]; //82-104 + int days; //105 + int mins; //106 + int ticks; //107 + char name[32]; //108-115 + int n3[2]; //116-117 + int linkchain; //118 + int n4[5]; //119-123 + int hashchain; //124 + int parent; //125 + int extension; //126 + int s_type; //127 +}; + +struct FileKeyExtension{ + int p_type; //0 + int own_key; //1 + int table_size; //2 + int n1[2]; //3-4 + int checksum; //5 + int filekey_table[72]; //6-77 + int info[46]; //78-123 + int n2; //124 + int parent; //125 + int extension; //126 + int s_type; //127 +}; + +struct Position { + unsigned int block; + short filekey; + unsigned short byte; + unsigned int offset; +}; + +struct ReadData { + unsigned int header_block; + struct Position current; + unsigned int filesize; +}; + +#warning "Big vs. little endian for configure needed" +#define AROS_BE2LONG(l) \ + ( \ + ((((unsigned long)(l)) >> 24) & 0x000000FFUL) | \ + ((((unsigned long)(l)) >> 8) & 0x0000FF00UL) | \ + ((((unsigned long)(l)) << 8) & 0x00FF0000UL) | \ + ((((unsigned long)(l)) << 24) & 0xFF000000UL) \ + ) + +struct CacheBlock { + int blocknum; + unsigned short flags; + unsigned short access_count; + unsigned int blockbuffer[128]; +}; +#define LockBuffer(x) (((struct CacheBlock *)(x))->flags |= 0x0001) +#define UnLockBuffer(x) (((struct CacheBlock *)(x))->flags &= ~0x0001) + +#define MAX_CACHE_BLOCKS 10 + +struct FSysBuffer { + struct ReadData file; + struct CacheBlock blocks[MAX_CACHE_BLOCKS]; +}; + +#define bootBlock(x) ((struct BootBlock *)(x)->blockbuffer) +#define rootBlock(x) ((struct RootBlock *)(x)->blockbuffer) +#define dirHeader(x) ((struct DirHeader *)(x)->blockbuffer) +#define fileHeader(x) ((struct FileHeader *)(x)->blockbuffer) +#define extensionBlock(x) ((struct FileKeyExtension *)(x)->blockbuffer) + +#define rdsk(x) ((struct RigidDiskBlock *)(x)->blockbuffer) +#define part(x) ((struct PartitionBlock *)(x)->blockbuffer) + +struct FSysBuffer *fsysb; +int blockoffset; /* offset if there is an embedded RDB partition */ +int rootb; /* block number of root block */ +int rdbb; /* block number of rdb block */ + +void initCache() { +int i; + + for (i=0;iblocks[i].blocknum = -1; + fsysb->blocks[i].flags = 0; + fsysb->blocks[i].access_count = 0; + } +} + +struct CacheBlock *getBlock(unsigned int block) { +struct CacheBlock *freeblock; +int i; + + /* get first unlocked block */ + i = 0; + do + { + freeblock = &fsysb->blocks[i++]; + } while (freeblock->flags & 0x0001); + /* search through list if block is already loaded in */ + for (i=0;iblocks[i].blocknum == block) + { + fsysb->blocks[i].access_count++; + return &fsysb->blocks[i]; + } + if (!(fsysb->blocks[i].flags & 0x0001)) + if (freeblock->access_count>fsysb->blocks[i].access_count) + freeblock = &fsysb->blocks[i]; + } + freeblock->blocknum = block; + devread(block+blockoffset, 0, 512, (char *)freeblock->blockbuffer); + return freeblock; +} + +unsigned int calcChkSum(unsigned short SizeBlock, unsigned int *buffer) { +unsigned int sum=0,count=0; + + for (count=0;countid) & 0xFFFFFF00)==0x444F5300) && + ((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFF)>0) + ) || + (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK) + ) + break; + } + if (i == RDB_LOCATION_LIMIT) + return 0; + if (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK) + { + /* we have an RDB partition table within a MBR-Partition */ + rdbb = i; + } + else if (i<2) + { + /* partition type is 0x30 = AROS and AFFS formatted */ + rdbb = RDB_LOCATION_LIMIT; + rootb = (part_length-1+2)/2; + cblock = getBlock(rootb); + if ( + (AROS_BE2LONG(rootBlock(cblock)->p_type) != T_SHORT) || + (AROS_BE2LONG(rootBlock(cblock)->s_type) != ST_ROOT) || + calcChkSum(128, cblock->blockbuffer) + ) + return 0; + } + else + return 0; + return 1; +} + +int seek(unsigned long offset) { +struct CacheBlock *cblock; +unsigned long block; +unsigned long togo; + + block = fsysb->file.header_block; + + togo = offset / 512; + fsysb->file.current.filekey = 71-(togo % 72); + togo /= 72; + fsysb->file.current.byte = offset % 512; + fsysb->file.current.offset = offset; + while ((togo) && (block)) + { + disk_read_func = disk_read_hook; + cblock = getBlock(block); + disk_read_func = 0; + block = AROS_BE2LONG(extensionBlock(cblock)->extension); + togo--; + } + if (togo) + return 1; + fsysb->file.current.block = block; + return 0; +} + +int affs_read(char *buf, int len) { +struct CacheBlock *cblock; +unsigned short size; +unsigned int readbytes = 0; + + if (fsysb->file.current.offset != filepos) + { + if (seek(filepos)) + return ERR_FILELENGTH; + } + if (fsysb->file.current.block == 0) + return 0; + if (len>(fsysb->file.filesize-fsysb->file.current.offset)) + len=fsysb->file.filesize-fsysb->file.current.offset; + disk_read_func = disk_read_hook; + cblock = getBlock(fsysb->file.current.block); + disk_read_func = 0; + while (len) + { + disk_read_func = disk_read_hook; + if (fsysb->file.current.filekey<0) + { + fsysb->file.current.filekey = 71; + fsysb->file.current.block = AROS_BE2LONG(extensionBlock(cblock)->extension); + if (fsysb->file.current.block) + { + cblock = getBlock(fsysb->file.current.block); + } +#warning "else shouldn't occour" + } + size = 512; + size -= fsysb->file.current.byte; + if (size>len) + { + size = len; + devread + ( + AROS_BE2LONG + ( + extensionBlock(cblock)->filekey_table + [fsysb->file.current.filekey] + )+blockoffset, + fsysb->file.current.byte, size, (char *)((int)buf+readbytes) + ); + fsysb->file.current.byte += size; + } + else + { + devread + ( + AROS_BE2LONG + ( + extensionBlock(cblock)->filekey_table + [fsysb->file.current.filekey] + )+blockoffset, + fsysb->file.current.byte, size, (char *)((int)buf+readbytes) + ); + fsysb->file.current.byte = 0; + fsysb->file.current.filekey--; + } + disk_read_func = 0; + len -= size; + readbytes += size; + } + fsysb->file.current.offset += readbytes; + filepos = fsysb->file.current.offset; + return readbytes; +} + +unsigned char capitalch(unsigned char ch, unsigned char flags) { + + if ((flags==0) || (flags==1)) + return (unsigned char)((ch>='a') && (ch<='z') ? ch-('a'-'A') : ch); + else // DOS\(>=2) + return (unsigned char)(((ch>=224) && (ch<=254) && (ch!=247)) || + ((ch>='a') && (ch<='z')) ? ch-('a'-'A') : ch); +} + +// str2 is a BCPL string +int noCaseStrCmp(char *str1, char *str2, unsigned char flags) { +unsigned char length; + + length=str2++[0]; + do { + if ((*str1==0) && (length==0)) + return 0; + length--; +// if ((*str1==0) && (*str2==0)) return 1; + } while (capitalch(*str1++,flags)==capitalch(*str2++,flags)); + str1--; + return (*str1) ? 1 : -1; +} + +unsigned int getHashKey(char *name,unsigned int tablesize, unsigned char flags) { +unsigned int length; + + length=0; + while (name[length] != 0) + length++; + while (*name!=0) + length=(length * 13 +capitalch(*name++,flags)) & 0x7FF; + return length%tablesize; +} + +grub_error_t getHeaderBlock(char *name, struct CacheBlock **dirh) { +int key; + + key = getHashKey(name, 72, 1); + if (!dirHeader(*dirh)->hashtable[key]) + return ERR_FILE_NOT_FOUND; + *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashtable[key])); + if (calcChkSum(128, (*dirh)->blockbuffer)) + { +#ifdef DEBUG_AFFS +printf("ghb: %d\n", (*dirh)->blocknum); +#endif + return ERR_FSYS_CORRUPT; + } + if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT) + return ERR_BAD_FILETYPE; + while (noCaseStrCmp(name,dirHeader(*dirh)->name,1) != 0) + { + if (!dirHeader(*dirh)->hashchain) + return ERR_FILE_NOT_FOUND; + *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashchain)); + if (calcChkSum(128, (*dirh)->blockbuffer)) + { +#ifdef DEBUG_AFFS +printf("ghb2: %d\n", (*dirh)->blocknum); +#endif + return ERR_FSYS_CORRUPT; + } + if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT) + return ERR_BAD_FILETYPE; + } + return 0; +} + +char *copyPart(char *src, char *dst) { + + while ((*src != '/') && (*src)) + *dst++ = *src++; + if (*src == '/') + src++; + *dst-- = 0; + /* cut off spaces at the end */ + while (*dst == ' ') + *dst-- = 0; + return src; +} + +grub_error_t findBlock(char *name, struct CacheBlock **dirh) { +char dname[32]; +int block; + + name++; /* skip "/" */ + /* partition table part */ + if (rdbb < RDB_LOCATION_LIMIT) + { + int bpc; + + blockoffset = 0; + *dirh = getBlock(rdbb); + if (*name==0) + return 0; + name = copyPart(name, dname); + bpc = AROS_BE2LONG(rdsk(*dirh)->rdb_Sectors)*AROS_BE2LONG(rdsk(*dirh)->rdb_Heads); + block = AROS_BE2LONG(rdsk(*dirh)->rdb_PartitionList); + while (block != -1) + { + *dirh = getBlock(block); + if (noCaseStrCmp(dname, part(*dirh)->pb_DriveName, 1) == 0) + break; + block = AROS_BE2LONG(part(*dirh)->pb_Next); + } + if (block == -1) + return ERR_FILE_NOT_FOUND; + if ( + ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFFFFFF00)!=0x444F5300) || + ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFF)==0) + ) + return ERR_BAD_FILETYPE; + blockoffset = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_LOWCYL]); + rootb = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_HIGHCYL]); + rootb = rootb-blockoffset+1; /* highcyl-lowcyl+1 */ + rootb *= bpc; + rootb = rootb-1+AROS_BE2LONG(part(*dirh)->pb_Environment[DE_RESERVEDBLKS]); + rootb /= 2; + blockoffset *= bpc; + } + + /* filesystem part */ + *dirh = getBlock(rootb); + while (*name) + { + if ( + (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_ROOT) && + (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_USERDIR) + ) + return ERR_BAD_FILETYPE; + name = copyPart(name, dname); + errnum = getHeaderBlock(dname, dirh); + if (errnum) + return errnum; + } + return 0; +} + +void checkPossibility(char *filename, char *bstr) { + +#ifndef STAGE1_5 + char cstr[32]; + + if (noCaseStrCmp(filename, bstr, 1)<=0) + { + if (print_possibilities>0) + print_possibilities = -print_possibilities; + memcpy(cstr, bstr+1, bstr[0]); + cstr[bstr[0]]=0; + print_a_completion(cstr); + } +#endif +} + +int affs_dir(char *dirname) +{ + struct CacheBlock *buffer1; + struct CacheBlock *buffer2; + char *current = dirname; + char filename[128]; + char *fname = filename; + int i,block; + + if (print_possibilities) + { + while (*current) + current++; + while (*current != '/') + current--; + current++; + while (*current) + { + *fname++ = *current; + *current++ = 0; + } + *fname=0; + errnum = findBlock(dirname, &buffer1); + if (errnum) + return 0; + if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == IDNAME_RIGIDDISK) + { + block = AROS_BE2LONG(rdsk(buffer1)->rdb_PartitionList); + while (block != -1) + { + buffer1 = getBlock(block); + checkPossibility(filename, part(buffer1)->pb_DriveName); + block = AROS_BE2LONG(part(buffer1)->pb_Next); + } +#ifndef STAGE1_5 + if (*filename == 0) + if (print_possibilities>0) + print_possibilities = -print_possibilities; +#endif + } + else if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == T_SHORT) + { + LockBuffer(buffer1); + for (i=0;i<72;i++) + { + block = dirHeader(buffer1)->hashtable[i]; + while (block) + { + buffer2 = getBlock(AROS_BE2LONG(block)); + if (calcChkSum(128, buffer2->blockbuffer)) + { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + if (AROS_BE2LONG(dirHeader(buffer2)->p_type) != T_SHORT) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + checkPossibility(filename, dirHeader(buffer2)->name); + block = dirHeader(buffer2)->hashchain; + } + } + UnLockBuffer(buffer1); +#ifndef STAGE1_5 + if (*filename == 0) + if (print_possibilities>0) + print_possibilities = -print_possibilities; +#endif + } + else + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + while (*current != '/') + current--; + current++; + fname = filename; + while (*fname) + *current++ = *fname++; +#warning "TODO: add some more chars until posibilities differ" + if (print_possibilities>0) + errnum = ERR_FILE_NOT_FOUND; + return (print_possibilities<0); + } + else + { + while (*current && !isspace(*current)) + *fname++ = *current++; + *fname = 0; + + errnum = findBlock(filename, &buffer2); + if (errnum) + return 0; + if (AROS_BE2LONG(fileHeader(buffer2)->s_type)!=ST_FILE) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + fsysb->file.header_block = AROS_BE2LONG(fileHeader(buffer2)->own_key); + fsysb->file.current.block = AROS_BE2LONG(fileHeader(buffer2)->own_key); + fsysb->file.current.filekey = 71; + fsysb->file.current.byte = 0; + fsysb->file.current.offset = 0; + fsysb->file.filesize = AROS_BE2LONG(fileHeader(buffer2)->bytesize); + filepos = 0; + filemax = fsysb->file.filesize; + return 1; + } +} +#endif + diff --git a/fs/grubfs/fsys_ext2fs.c b/fs/grubfs/fsys_ext2fs.c new file mode 100644 index 0000000..b67e505 --- /dev/null +++ b/fs/grubfs/fsys_ext2fs.c @@ -0,0 +1,804 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999, 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef FSYS_EXT2FS + +#include "shared.h" +#include "filesys.h" +#include + +static int mapblock1, mapblock2; + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE 1024 /* initial block size for superblock read */ +/* made up, defaults to 1 but can be passed via mount_opts */ +#define WHICH_SUPER 1 +/* kind of from fs/ext2/super.c */ +#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */ + +/* include/asm-i386/types.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; + +/* + * Constants relative to the data blocks, from ext2_fs.h + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* include/linux/ext2_fs.h */ +struct ext2_super_block + { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_pad; + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + __u32 s_reserved[235]; /* Padding to the end of the block */ + }; + +struct ext2_group_desc + { + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; + }; + +struct ext2_inode + { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Owner Uid */ + __u32 i_size; /* 4: Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* 12: Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* 20: Deletion Time */ + __u16 i_gid; /* Group Id */ + __u16 i_links_count; /* 24: Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* 32: File flags */ + union + { + struct + { + __u32 l_i_reserved1; + } + linux1; + struct + { + __u32 h_i_translator; + } + hurd1; + struct + { + __u32 m_i_reserved1; + } + masix1; + } + osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ + __u32 i_version; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union + { + struct + { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u32 l_i_reserved2[2]; + } + linux2; + struct + { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } + hurd2; + struct + { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } + masix2; + } + osd2; /* OS dependent 2 */ + }; + +/* linux/limits.h */ +#define NAME_MAX 255 /* # chars in a file name */ + +/* linux/posix_type.h */ +typedef long linux_off_t; + +/* linux/ext2fs.h */ +#define EXT2_NAME_LEN 255 +struct ext2_dir_entry + { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT2_NAME_LEN]; /* File name */ + }; + +/* linux/ext2fs.h */ +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + + +/* ext2/super.c */ +#define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */ +#define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */ +#define PATH_MAX 1024 /* include/linux/limits.h */ +#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */ + +/* made up, these are pointers into FSYS_BUF */ +/* read once, always stays there: */ +#define SUPERBLOCK \ + ((struct ext2_super_block *)(FSYS_BUF)) +#define GROUP_DESC \ + ((struct ext2_group_desc *) \ + ((char *)SUPERBLOCK + sizeof(struct ext2_super_block))) +#define INODE \ + ((struct ext2_inode *)((char *)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK))) +#define DATABLOCK1 \ + ((char *)((char *)INODE + sizeof(struct ext2_inode))) +#define DATABLOCK2 \ + ((char *)((char *)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK))) + +/* linux/ext2_fs.h */ +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s))) + +/* linux/ext2_fs.h */ +#define EXT2_BLOCK_SIZE_BITS(s) (__le32_to_cpu((s)->s_log_block_size) + 10) +/* kind of from ext2/super.c */ +#define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s)) +/* linux/ext2fs.h */ +#define EXT2_DESC_PER_BLOCK(s) \ + (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +/* linux/stat.h */ +#define S_IFMT 00170000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFDIR 0040000 +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + +#ifdef E2DEBUG +void +dump_super(struct ext2_super_block *s) +{ + printf(" superblock 0x%x:\n", s); + printf(" inodes=%d\n", __le32_to_cpu(s->s_inodes_count)); + printf(" blocks=%d\n", __le32_to_cpu(s->s_blocks_count)); + printf(" reserved=%d\n", __le32_to_cpu(s->s_r_blocks_count)); + printf(" i_free=%d\n", __le32_to_cpu(s->s_free_inodes_count)); + printf(" b_free=%d\n", __le32_to_cpu(s->s_free_blocks_count)); + printf(" first=%d\n", __le32_to_cpu(s->s_first_data_block)); + printf(" log_b_size=%d, b_size=%d\n", __le32_to_cpu(s->s_log_block_size), EXT2_BLOCK_SIZE(s)); + printf(" log_f_size=%d\n", __le32_to_cpu(s->s_log_frag_size)); + printf(" bpg=%d\n", __le32_to_cpu(s->s_blocks_per_group)); + printf(" fpg=%d\n", __le32_to_cpu(s->s_frags_per_group)); + printf(" ipg=%d\n", __le32_to_cpu(s->s_inodes_per_group)); +} + +void +dump_group_desc(struct ext2_group_desc *g) +{ + printf(" group_desc 0x%x:\n", g); + printf(" b_bmap block=%d\n", __le32_to_cpu(g->bg_block_bitmap)); + printf(" i_bmap block=%d\n", __le32_to_cpu(g->bg_inode_bitmap)); + printf(" i_tab block=%d\n", __le32_to_cpu(g->bg_inode_table)); + printf(" free_blks=%d\n", __le16_to_cpu(g->bg_free_blocks_count)); + printf(" free_inodes=%d\n", __le16_to_cpu(g->bg_free_inodes_count)); + printf(" used_dirs=%d\n", __le16_to_cpu(g->bg_used_dirs_count)); +} + +void +dump_inode(struct ext2_inode *i) +{ + printf(" inode 0x%x:\n", i); + printf(" mode=%o\n", __le16_to_cpu(i->i_mode)); + printf(" uid=%d\n", __le16_to_cpu(i->i_uid)); + printf(" gid=%d\n", __le16_to_cpu(i->i_gid)); + printf(" size=%d\n", __le32_to_cpu(i->i_size)); + printf(" atime=%d\n", __le32_to_cpu(i->i_atime)); + printf(" ctime=%d\n", __le32_to_cpu(i->i_ctime)); + printf(" mtime=%d\n", __le32_to_cpu(i->i_mtime)); + printf(" dtime=%d\n", __le32_to_cpu(i->i_dtime)); + printf(" links=%d\n", __le16_to_cpu(i->i_links_count)); + printf(" blocks=%d\n", __le32_to_cpu(i->i_blocks)); + printf(" flags=%d\n", __le32_to_cpu(i->i_flags)); +} + +void +dump_inode_data(unsigned char *inode, int len) +{ + static char hexdigit[] = "0123456789abcdef"; + unsigned char *i; + for (i = inode; + i < (inode + len); + i++) + { + printf ("%c", hexdigit[*i >> 4]); + printf ("%c", hexdigit[*i % 16]); + if (!((i + 1 - inode) % 16)) + { + printf ("\n"); + } + else + { + printf (" "); + } + } +} +#endif + +/* check filesystem types and read superblock into memory buffer */ +int +ext2fs_mount (void) +{ + int retval = 1; + + if ((((current_drive & 0x80) || (current_slice != 0)) + && (current_slice != PC_SLICE_TYPE_EXT2FS) + && (current_slice != PC_SLICE_TYPE_LINUX_RAID) + && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS)) + && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))) + || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE)) + || !devread (SBLOCK, 0, sizeof (struct ext2_super_block), + (char *) SUPERBLOCK) + || __le16_to_cpu(SUPERBLOCK->s_magic) != EXT2_SUPER_MAGIC) + retval = 0; + + return retval; +} + +/* Takes a file system block number and reads it into BUFFER. */ +static int +ext2_rdfsb (int fsblock, char * buffer) +{ +#ifdef E2DEBUG + printf ("ext2_rdfsb: fsblock %d, devblock %d, size %d\n", fsblock, + fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), + EXT2_BLOCK_SIZE (SUPERBLOCK)); +#endif /* E2DEBUG */ + return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0, + EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer); +} + +/* from + ext2/inode.c:ext2_bmap() +*/ +/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into + a physical block (the location in the file system) via an inode. */ +static int +ext2fs_block_map (int logical_block) +{ + +#ifdef E2DEBUG + printf ("ext2fs_block_map(%d)\n", logical_block); +#endif /* E2DEBUG */ + + /* if it is directly pointed to by the inode, return that physical addr */ + if (logical_block < EXT2_NDIR_BLOCKS) + { +#ifdef E2DEBUG + printf ("ext2fs_block_map: returning %d\n", __le32_to_cpu(INODE->i_block[logical_block])); +#endif /* E2DEBUG */ + return __le32_to_cpu(INODE->i_block[logical_block]); + } + /* else */ + logical_block -= EXT2_NDIR_BLOCKS; + /* try the indirect block */ + if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK)) + { + if (mapblock1 != 1 + && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_IND_BLOCK]), DATABLOCK1)) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 1; + return __le32_to_cpu(((__u32 *) DATABLOCK1)[logical_block]); + } + /* else */ + logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK); + /* now try the double indirect block */ + if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2))) + { + int bnum; + if (mapblock1 != 2 + && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_DIND_BLOCK]), DATABLOCK1)) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 2; + if ((bnum = __le32_to_cpu(((__u32 *) DATABLOCK1) + [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)])) + != mapblock2 + && !ext2_rdfsb (bnum, DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock2 = bnum; + return __le32_to_cpu(((__u32 *) DATABLOCK2) + [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]); + } + /* else */ + mapblock2 = -1; + logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)); + if (mapblock1 != 3 + && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_TIND_BLOCK]), DATABLOCK1)) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 3; + if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK1) + [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) + * 2)]), + DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK2) + [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)) + & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]), + DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + return __le32_to_cpu(((__u32 *) DATABLOCK2) + [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]); +} + +/* preconditions: all preconds of ext2fs_block_map */ +int +ext2fs_read (char *buf, int len) +{ + int logical_block; + int offset; + int map; + int ret = 0; + int size = 0; + +#ifdef E2DEBUG + printf("ext2fs_read(0x%x, %d)\n", buf, len); + dump_inode(INODE); + dump_inode_data((unsigned char *)INODE, sizeof (struct ext2_inode)); +#endif /* E2DEBUG */ + while (len > 0) + { + /* find the (logical) block component of our location */ + logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); + offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); + map = ext2fs_block_map (logical_block); +#ifdef E2DEBUG + printf ("map=%d\n", map); +#endif /* E2DEBUG */ + if (map < 0) + break; + + size = EXT2_BLOCK_SIZE (SUPERBLOCK); + size -= offset; + if (size > len) + size = len; + + disk_read_func = disk_read_hook; + + devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), + offset, size, buf); + + disk_read_func = 0; + + buf += size; + len -= size; + filepos += size; + ret += size; + } + + if (errnum) + ret = 0; + + return ret; +} + + +/* Based on: + def_blk_fops points to + blkdev_open, which calls (I think): + sys_open() + do_open() + open_namei() + dir_namei() which accesses current->fs->root + fs->root was set during original mount: + (something)... which calls (I think): + ext2_read_super() + iget() + __iget() + read_inode() + ext2_read_inode() + uses desc_per_block_bits, which is set in ext2_read_super() + also uses group descriptors loaded during ext2_read_super() + lookup() + ext2_lookup() + ext2_find_entry() + ext2_getblk() + +*/ + +/* preconditions: ext2fs_mount already executed, therefore supblk in buffer + * known as SUPERBLOCK + * returns: 0 if error, nonzero iff we were able to find the file successfully + * postconditions: on a nonzero return, buffer known as INODE contains the + * inode of the file we were trying to look up + * side effects: messes up GROUP_DESC buffer area + */ +int +ext2fs_dir (char *dirname) +{ + int current_ino = EXT2_ROOT_INO; /* start at the root */ + int updir_ino = current_ino; /* the parent of the current directory */ + int group_id; /* which group the inode is in */ + int group_desc; /* fs pointer to that group */ + int desc; /* index within that group */ + int ino_blk; /* fs pointer of the inode's information */ + int str_chk = 0; /* used to hold the results of a string compare */ + struct ext2_group_desc *gdp; + struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */ + + char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ + int link_count = 0; + + char *rest; + char ch; /* temp char holder */ + + int off; /* offset within block of directory entry (off mod blocksize) */ + int loc; /* location within a directory */ + int blk; /* which data blk within dir entry (off div blocksize) */ + long map; /* fs pointer of a particular block from dir entry */ + struct ext2_dir_entry *dp; /* pointer to directory entry */ + + /* loop invariants: + current_ino = inode to lookup + dirname = pointer to filename component we are cur looking up within + the directory known pointed to by current_ino (if any) + */ + +#ifdef E2DEBUG + printf("****** ext2fs_dir(%s)\n", dirname); + dump_super(SUPERBLOCK); +#endif /* E2DEBUG */ + + while (1) + { +#ifdef E2DEBUG + printf ("ext2fs_dir: inode %d\n", current_ino); + printf ("ext2fs_dir: dirname=%s\n", dirname); +#endif /* E2DEBUG */ + + /* look up an inode */ + group_id = (current_ino - 1) / __le32_to_cpu(SUPERBLOCK->s_inodes_per_group); + group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK)); + desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1); +#ifdef E2DEBUG + printf ("ext2fs_dir: ipg=%d, dpb=%d\n", __le32_to_cpu(SUPERBLOCK->s_inodes_per_group), + EXT2_DESC_PER_BLOCK (SUPERBLOCK)); + printf ("ext2fs_dir: group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc); +#endif /* E2DEBUG */ + if (!ext2_rdfsb ( + (WHICH_SUPER + group_desc + __le32_to_cpu(SUPERBLOCK->s_first_data_block)), + (char*) GROUP_DESC)) + { + return 0; + } + +#ifdef E2DEBUG + dump_group_desc(GROUP_DESC); +#endif /* E2DEBUG */ + + gdp = GROUP_DESC; + ino_blk = __le32_to_cpu(gdp[desc].bg_inode_table) + + (((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group)) + >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); +#ifdef E2DEBUG + printf ("ext2fs_dir: itab_blk=%d, i_in_grp=%d, log2=%d\n", + __le32_to_cpu(gdp[desc].bg_inode_table), + ((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group)), + log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); + printf ("ext2fs_dir: inode table fsblock=%d\n", ino_blk); +#endif /* E2DEBUG */ + if (!ext2_rdfsb (ino_blk, (int) INODE)) + { + return 0; + } + + /* reset indirect blocks! */ + mapblock2 = mapblock1 = -1; + + raw_inode = INODE + + ((current_ino - 1) + & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1)); +#ifdef E2DEBUG + printf ("ext2fs_dir: ipb=%d, sizeof(inode)=%d\n", + (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)), + sizeof (struct ext2_inode)); + printf ("ext2fs_dir: inode=%x, raw_inode=%x\n", INODE, raw_inode); + printf ("ext2fs_dir: offset into inode table block=%d\n", (int) raw_inode - (int) INODE); + dump_inode(raw_inode); + dump_inode_data((unsigned char *)INODE, EXT2_BLOCK_SIZE(SUPERBLOCK)); + printf ("ext2fs_dir: first word=%x\n", *((int *) raw_inode)); +#endif /* E2DEBUG */ + + /* copy inode to fixed location */ + memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode)); + +#ifdef E2DEBUG + dump_inode(INODE); + printf ("ext2fs_dir: first word=%x\n", *((int *) INODE)); +#endif /* E2DEBUG */ + + /* If we've got a symbolic link, then chase it. */ + if (S_ISLNK (__le16_to_cpu(INODE->i_mode))) + { + int len; + if (++link_count > MAX_LINK_COUNT) + { + errnum = ERR_SYMLINK_LOOP; + return 0; + } + + /* Find out how long our remaining name is. */ + len = 0; + while (dirname[len] && !isspace (dirname[len])) + len++; + + /* Get the symlink size. */ + filemax = __le32_to_cpu(INODE->i_size); + if (filemax + len > sizeof (linkbuf) - 2) + { + errnum = ERR_FILELENGTH; + return 0; + } + + if (len) + { + /* Copy the remaining name to the end of the symlink data. + Note that DIRNAME and LINKBUF may overlap! */ + memmove (linkbuf + filemax, dirname, len); + } + linkbuf[filemax + len] = '\0'; + + /* Read the symlink data. */ + if (__le32_to_cpu(INODE->i_blocks)) + { + /* Read the necessary blocks, and reset the file pointer. */ + len = file_read (linkbuf, filemax); + filepos = 0; + if (!len) + return 0; + } + else + { + /* Copy the data directly from the inode. */ + len = filemax; + memmove (linkbuf, (char *) INODE->i_block, len); + } + +#ifdef E2DEBUG + printf ("ext2fs_dir: symlink=%s\n", linkbuf); +#endif + + dirname = linkbuf; + if (*dirname == '/') + { + /* It's an absolute link, so look it up in root. */ + current_ino = EXT2_ROOT_INO; + updir_ino = current_ino; + } + else + { + /* Relative, so look it up in our parent directory. */ + current_ino = updir_ino; + } + + /* Try again using the new name. */ + continue; + } + + /* if end of filename, INODE points to the file's inode */ + if (!*dirname || isspace (*dirname)) + { + if (!S_ISREG (__le16_to_cpu(INODE->i_mode))) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + filemax = __le32_to_cpu(INODE->i_size); + return 1; + } + + /* else we have to traverse a directory */ + updir_ino = current_ino; + + /* skip over slashes */ + while (*dirname == '/') + dirname++; + + /* if this isn't a directory of sufficient size to hold our file, abort */ + if (!(__le32_to_cpu(INODE->i_size)) || !S_ISDIR (__le16_to_cpu(INODE->i_mode))) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + /* skip to next slash or end of filename (space) */ + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; + rest++); + + /* look through this directory and find the next filename component */ + /* invariant: rest points to slash after the next filename component */ + *rest = 0; + loc = 0; + + do + { + +#ifdef E2DEBUG + printf ("ext2fs_dir: dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc); +#endif /* E2DEBUG */ + + /* if our location/byte offset into the directory exceeds the size, + give up */ + if (loc >= __le32_to_cpu(INODE->i_size)) + { + if (print_possibilities < 0) + { +# if 0 + putchar ('\n'); +# endif + } + else + { + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + } + return (print_possibilities < 0); + } + + /* else, find the (logical) block component of our location */ + blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); + + /* we know which logical block of the directory entry we are looking + for, now we have to translate that to the physical (fs) block on + the disk */ + map = ext2fs_block_map (blk); +#ifdef E2DEBUG + printf ("ext2fs_dir: fs block=%d\n", map); +#endif /* E2DEBUG */ + mapblock2 = -1; + if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + *rest = ch; + return 0; + } + off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); + dp = (struct ext2_dir_entry *) (DATABLOCK2 + off); + /* advance loc prematurely to next on-disk directory entry */ + loc += __le16_to_cpu(dp->rec_len); + + /* NOTE: ext2fs filenames are NOT null-terminated */ + +#ifdef E2DEBUG + printf ("ext2fs_dir: directory entry ino=%d\n", __le32_to_cpu(dp->inode)); + if (__le32_to_cpu(dp->inode)) + printf ("entry=%s\n", dp->name); +#endif /* E2DEBUG */ + + if (__le32_to_cpu(dp->inode)) + { + int saved_c = dp->name[dp->name_len]; + + dp->name[dp->name_len] = 0; + str_chk = substring (dirname, dp->name); + +# ifndef STAGE1_5 + if (print_possibilities && ch != '/' + && (!*dirname || str_chk <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion (dp->name); + } +# endif + + dp->name[dp->name_len] = saved_c; + } + + } + while (!__le32_to_cpu(dp->inode) || (str_chk || (print_possibilities && ch != '/'))); + + current_ino = __le32_to_cpu(dp->inode); + *(dirname = rest) = ch; + } + /* never get here */ +} + +#endif /* FSYS_EXT2_FS */ + diff --git a/fs/grubfs/fsys_fat.c b/fs/grubfs/fsys_fat.c new file mode 100644 index 0000000..46cbd4b --- /dev/null +++ b/fs/grubfs/fsys_fat.c @@ -0,0 +1,476 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef FSYS_FAT + +#include "shared.h" +#include "filesys.h" +#include "fat.h" + +struct fat_superblock +{ + int fat_offset; + int fat_length; + int fat_size; + int root_offset; + int root_max; + int data_offset; + + int num_sectors; + int num_clust; + int clust_eof_marker; + int sects_per_clust; + int sectsize_bits; + int clustsize_bits; + int root_cluster; + + int cached_fat; + int file_cluster; + int current_cluster_num; + int current_cluster; +}; + +/* pointer(s) into filesystem info buffer for DOS stuff */ +#define FAT_SUPER ( (struct fat_superblock *) \ + ( FSYS_BUF + 32256) )/* 512 bytes long */ +#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */ +#define NAME_BUF ( FSYS_BUF + 29184 ) /* Filename buffer (833 bytes) */ + +#define FAT_CACHE_SIZE 2048 + +int +fat_mount (void) +{ + struct fat_bpb bpb; + __u32 magic, first_fat; + + /* Check partition type for harddisk */ + if (((current_drive & 0x80) || (current_slice != 0)) + && ! IS_PC_SLICE_TYPE_FAT (current_slice) + && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS))) + return 0; + + /* Read bpb */ + if (! devread (0, 0, sizeof (bpb), (char *) &bpb)) + return 0; + + /* Check if the number of sectors per cluster is zero here, to avoid + zero division. */ + if (bpb.sects_per_clust == 0) + return 0; + + FAT_SUPER->sectsize_bits = log2 (FAT_CVT_U16 (bpb.bytes_per_sect)); + FAT_SUPER->clustsize_bits + = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust); + + /* Fill in info about super block */ + FAT_SUPER->num_sectors = FAT_CVT_U16 (bpb.short_sectors) + ? FAT_CVT_U16 (bpb.short_sectors) : bpb.long_sectors; + + /* FAT offset and length */ + FAT_SUPER->fat_offset = FAT_CVT_U16 (bpb.reserved_sects); + FAT_SUPER->fat_length = + bpb.fat_length ? bpb.fat_length : bpb.fat32_length; + + /* Rootdir offset and length for FAT12/16 */ + FAT_SUPER->root_offset = + FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length; + FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries); + + /* Data offset and number of clusters */ + FAT_SUPER->data_offset = + FAT_SUPER->root_offset + + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1; + FAT_SUPER->num_clust = + 2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset) + / bpb.sects_per_clust); + FAT_SUPER->sects_per_clust = bpb.sects_per_clust; + + if (!bpb.fat_length) + { + /* This is a FAT32 */ + if (FAT_CVT_U16(bpb.dir_entries)) + return 0; + + if (bpb.flags & 0x0080) + { + /* FAT mirroring is disabled, get active FAT */ + int active_fat = bpb.flags & 0x000f; + if (active_fat >= bpb.num_fats) + return 0; + FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length; + } + + FAT_SUPER->fat_size = 8; + FAT_SUPER->root_cluster = bpb.root_cluster; + + /* Yes the following is correct. FAT32 should be called FAT28 :) */ + FAT_SUPER->clust_eof_marker = 0xffffff8; + } + else + { + if (!FAT_SUPER->root_max) + return 0; + + FAT_SUPER->root_cluster = -1; + if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST) + { + FAT_SUPER->fat_size = 4; + FAT_SUPER->clust_eof_marker = 0xfff8; + } + else + { + FAT_SUPER->fat_size = 3; + FAT_SUPER->clust_eof_marker = 0xff8; + } + } + + + /* Now do some sanity checks */ + + if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits) + || FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE + || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits + - FAT_SUPER->sectsize_bits)) + || FAT_SUPER->num_clust <= 2 + || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE) + > FAT_SUPER->fat_length)) + return 0; + + /* kbs: Media check on first FAT entry [ported from PUPA] */ + + if (!devread(FAT_SUPER->fat_offset, 0, + sizeof(first_fat), (char *)&first_fat)) + return 0; + + if (FAT_SUPER->fat_size == 8) + { + first_fat &= 0x0fffffff; + magic = 0x0fffff00; + } + else if (FAT_SUPER->fat_size == 4) + { + first_fat &= 0x0000ffff; + magic = 0xff00; + } + else + { + first_fat &= 0x00000fff; + magic = 0x0f00; + } + + if (first_fat != (magic | bpb.media)) + return 0; + + FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE; + return 1; +} + +int +fat_read (char *buf, int len) +{ + int logical_clust; + int offset; + int ret = 0; + int size; + + if (FAT_SUPER->file_cluster < 0) + { + /* root directory for fat16 */ + size = FAT_SUPER->root_max - filepos; + if (size > len) + size = len; + if (!devread(FAT_SUPER->root_offset, filepos, size, buf)) + return 0; + filepos += size; + return size; + } + + logical_clust = filepos >> FAT_SUPER->clustsize_bits; + offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1)); + if (logical_clust < FAT_SUPER->current_cluster_num) + { + FAT_SUPER->current_cluster_num = 0; + FAT_SUPER->current_cluster = FAT_SUPER->file_cluster; + } + + while (len > 0) + { + int sector; + while (logical_clust > FAT_SUPER->current_cluster_num) + { + /* calculate next cluster */ + int fat_entry = + FAT_SUPER->current_cluster * FAT_SUPER->fat_size; + int next_cluster; + int cached_pos = (fat_entry - FAT_SUPER->cached_fat); + + if (cached_pos < 0 || + (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE) + { + FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1)); + cached_pos = (fat_entry - FAT_SUPER->cached_fat); + sector = FAT_SUPER->fat_offset + + FAT_SUPER->cached_fat / (2*SECTOR_SIZE); + if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF)) + return 0; + } + next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1)); + if (FAT_SUPER->fat_size == 3) + { + if (cached_pos & 1) + next_cluster >>= 4; + next_cluster &= 0xFFF; + } + else if (FAT_SUPER->fat_size == 4) + next_cluster &= 0xFFFF; + + if (next_cluster >= FAT_SUPER->clust_eof_marker) + return ret; + if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust) + { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + + FAT_SUPER->current_cluster = next_cluster; + FAT_SUPER->current_cluster_num++; + } + + sector = FAT_SUPER->data_offset + + ((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits + - FAT_SUPER->sectsize_bits)); + size = (1 << FAT_SUPER->clustsize_bits) - offset; + if (size > len) + size = len; + + disk_read_func = disk_read_hook; + + devread(sector, offset, size, buf); + + disk_read_func = NULL; + + len -= size; + buf += size; + ret += size; + filepos += size; + logical_clust++; + offset = 0; + } + return errnum ? 0 : ret; +} + +int +fat_dir (char *dirname) +{ + char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH]; + char *filename = (char *) NAME_BUF; + int attrib = FAT_ATTRIB_DIR; +#ifndef STAGE1_5 + int do_possibilities = 0; +#endif + + /* XXX I18N: + * the positions 2,4,6 etc are high bytes of a 16 bit unicode char + */ + static unsigned char longdir_pos[] = + { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 }; + int slot = -2; + int alias_checksum = -1; + + FAT_SUPER->file_cluster = FAT_SUPER->root_cluster; + filepos = 0; + FAT_SUPER->current_cluster_num = MAXINT; + + /* main loop to find desired directory entry */ + loop: + + /* if we have a real file (and we're not just printing possibilities), + then this is where we want to exit */ + + if (!*dirname || isspace (*dirname)) + { + if (attrib & FAT_ATTRIB_DIR) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + return 1; + } + + /* continue with the file/directory name interpretation */ + + while (*dirname == '/') + dirname++; + + if (!(attrib & FAT_ATTRIB_DIR)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + /* Directories don't have a file size */ + filemax = MAXINT; + + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); + + *rest = 0; + +# ifndef STAGE1_5 + if (print_possibilities && ch != '/') + do_possibilities = 1; +# endif + + while (1) + { + if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH + || dir_buf[0] == 0) + { + if (!errnum) + { +# ifndef STAGE1_5 + if (print_possibilities < 0) + { +#if 0 + putchar ('\n'); +#endif + return 1; + } +# endif /* STAGE1_5 */ + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + } + + return 0; + } + + if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME) + { + /* This is a long filename. The filename is build from back + * to front and may span multiple entries. To bind these + * entries together they all contain the same checksum over + * the short alias. + * + * The id field tells if this is the first entry (the last + * part) of the long filename, and also at which offset this + * belongs. + * + * We just write the part of the long filename this entry + * describes and continue with the next dir entry. + */ + int i, offset; + unsigned char id = FAT_LONGDIR_ID(dir_buf); + + if ((id & 0x40)) + { + id &= 0x3f; + slot = id; + filename[slot * 13] = 0; + alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf); + } + + if (id != slot || slot == 0 + || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf)) + { + alias_checksum = -1; + continue; + } + + slot--; + offset = slot * 13; + + for (i=0; i < 13; i++) + filename[offset+i] = dir_buf[longdir_pos[i]]; + continue; + } + + if (!FAT_DIRENTRY_VALID (dir_buf)) + continue; + + if (alias_checksum != -1 && slot == 0) + { + int i; + unsigned char sum; + + slot = -2; + for (sum = 0, i = 0; i< 11; i++) + sum = ((sum >> 1) | (sum << 7)) + dir_buf[i]; + + if (sum == alias_checksum) + { +# ifndef STAGE1_5 + if (do_possibilities) + goto print_filename; +# endif /* STAGE1_5 */ + + if (substring (dirname, filename) == 0) + break; + } + } + + /* XXX convert to 8.3 filename format here */ + { + int i, j, c; + + for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i])) + && !isspace (c); i++); + + filename[i++] = '.'; + + for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j])) + && !isspace (c); j++); + + if (j == 0) + i--; + + filename[i + j] = 0; + } + +# ifndef STAGE1_5 + if (do_possibilities) + { + print_filename: + if (substring (dirname, filename) <= 0) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion (filename); + } + continue; + } +# endif /* STAGE1_5 */ + + if (substring (dirname, filename) == 0) + break; + } + + *(dirname = rest) = ch; + + attrib = FAT_DIRENTRY_ATTRIB (dir_buf); + filemax = FAT_DIRENTRY_FILELENGTH (dir_buf); + filepos = 0; + FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf); + FAT_SUPER->current_cluster_num = MAXINT; + + /* go back to main loop at top of function */ + goto loop; +} + +#endif /* FSYS_FAT */ diff --git a/fs/grubfs/fsys_ffs.c b/fs/grubfs/fsys_ffs.c new file mode 100644 index 0000000..c8f2801 --- /dev/null +++ b/fs/grubfs/fsys_ffs.c @@ -0,0 +1,310 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Elements of this file were originally from the FreeBSD "biosboot" + * bootloader file "disk.c" dated 4/12/95. + * + * The license and header comments from that file are included here. + */ + +/* + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd + * $Id: fsys_ffs.c,v 1.10 2001/11/12 06:57:29 okuji Exp $ + */ + +#ifdef FSYS_FFS + +#include "shared.h" + +#include "filesys.h" + +#include "defs.h" +#include "disk_inode.h" +#include "disk_inode_ffs.h" +#include "dir.h" +#include "fs.h" + +/* used for filesystem map blocks */ +static int mapblock; +static int mapblock_offset; +static int mapblock_bsize; + +/* pointer to superblock */ +#define SUPERBLOCK ((struct fs *) ( FSYS_BUF + 8192 )) +#define INODE ((struct icommon *) ( FSYS_BUF + 16384 )) +#define MAPBUF ( FSYS_BUF + 24576 ) +#define MAPBUF_LEN 8192 + + +int +ffs_mount (void) +{ + int retval = 1; + + if ((((current_drive & 0x80) || (current_slice != 0)) + && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_BSDFFS)) + || part_length < (SBLOCK + (SBSIZE / DEV_BSIZE)) + || !devread (SBLOCK, 0, SBSIZE, (char *) SUPERBLOCK) + || SUPERBLOCK->fs_magic != FS_MAGIC) + retval = 0; + + mapblock = -1; + mapblock_offset = -1; + + return retval; +} + +static int +block_map (int file_block) +{ + int bnum, offset, bsize; + + if (file_block < NDADDR) + return (INODE->i_db[file_block]); + + /* If the blockmap loaded does not include FILE_BLOCK, + load a new blockmap. */ + if ((bnum = fsbtodb (SUPERBLOCK, INODE->i_ib[0])) != mapblock + || (mapblock_offset <= bnum && bnum <= mapblock_offset + mapblock_bsize)) + { + if (MAPBUF_LEN < SUPERBLOCK->fs_bsize) + { + offset = ((file_block - NDADDR) % NINDIR (SUPERBLOCK)); + bsize = MAPBUF_LEN; + + if (offset + MAPBUF_LEN > SUPERBLOCK->fs_bsize) + offset = (SUPERBLOCK->fs_bsize - MAPBUF_LEN) / sizeof (int); + } + else + { + bsize = SUPERBLOCK->fs_bsize; + offset = 0; + } + + if (! devread (bnum, offset * sizeof (int), bsize, (char *) MAPBUF)) + { + mapblock = -1; + mapblock_bsize = -1; + mapblock_offset = -1; + errnum = ERR_FSYS_CORRUPT; + return -1; + } + + mapblock = bnum; + mapblock_bsize = bsize; + mapblock_offset = offset; + } + + return (((int *) MAPBUF)[((file_block - NDADDR) % NINDIR (SUPERBLOCK)) + - mapblock_offset]); +} + + +int +ffs_read (char *buf, int len) +{ + int logno, off, size, map, ret = 0; + + while (len && !errnum) + { + off = blkoff (SUPERBLOCK, filepos); + logno = lblkno (SUPERBLOCK, filepos); + size = blksize (SUPERBLOCK, INODE, logno); + + if ((map = block_map (logno)) < 0) + break; + + size -= off; + + if (size > len) + size = len; + + disk_read_func = disk_read_hook; + + devread (fsbtodb (SUPERBLOCK, map), off, size, buf); + + disk_read_func = NULL; + + buf += size; + len -= size; + filepos += size; + ret += size; + } + + if (errnum) + ret = 0; + + return ret; +} + + +int +ffs_dir (char *dirname) +{ + char *rest, ch; + int block, off, loc, map, ino = ROOTINO; + struct direct *dp; + +/* main loop to find destination inode */ +loop: + + /* load current inode (defaults to the root inode) */ + + if (!devread (fsbtodb (SUPERBLOCK, itod (SUPERBLOCK, ino)), + ino % (SUPERBLOCK->fs_inopb) * sizeof (struct dinode), + sizeof (struct dinode), (char *) INODE)) + return 0; /* XXX what return value? */ + + /* if we have a real file (and we're not just printing possibilities), + then this is where we want to exit */ + + if (!*dirname || isspace (*dirname)) + { + if ((INODE->i_mode & IFMT) != IFREG) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + filemax = INODE->i_size; + + /* incomplete implementation requires this! */ + fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize; + return 1; + } + + /* continue with file/directory name interpretation */ + + while (*dirname == '/') + dirname++; + + if (!(INODE->i_size) || ((INODE->i_mode & IFMT) != IFDIR)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); + + *rest = 0; + loc = 0; + + /* loop for reading a the entries in a directory */ + + do + { + if (loc >= INODE->i_size) + { +#if 0 + putchar ('\n'); +#endif + + if (print_possibilities < 0) + return 1; + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; + } + + if (!(off = blkoff (SUPERBLOCK, loc))) + { + block = lblkno (SUPERBLOCK, loc); + + if ((map = block_map (block)) < 0 + || !devread (fsbtodb (SUPERBLOCK, map), 0, + blksize (SUPERBLOCK, INODE, block), + (char *) FSYS_BUF)) + { + errnum = ERR_FSYS_CORRUPT; + *rest = ch; + return 0; + } + } + + dp = (struct direct *) (FSYS_BUF + off); + loc += dp->d_reclen; + +#ifndef STAGE1_5 + if (dp->d_ino && print_possibilities && ch != '/' + && (!*dirname || substring (dirname, dp->d_name) <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + + print_a_completion (dp->d_name); + } +#endif /* STAGE1_5 */ + } + while (!dp->d_ino || (substring (dirname, dp->d_name) != 0 + || (print_possibilities && ch != '/'))); + + /* only get here if we have a matching directory entry */ + + ino = dp->d_ino; + *(dirname = rest) = ch; + + /* go back to main loop at top of function */ + goto loop; +} + +int +ffs_embed (int *start_sector, int needed_sectors) +{ + /* XXX: I don't know if this is really correct. Someone who is + familiar with BSD should check for this. */ + if (needed_sectors > 14) + return 0; + + *start_sector = 1; +#if 1 + /* FIXME: Disable the embedding in FFS until someone checks if + the code above is correct. */ + return 0; +#else + return 1; +#endif +} + +#endif /* FSYS_FFS */ diff --git a/fs/grubfs/fsys_iso9660.c b/fs/grubfs/fsys_iso9660.c new file mode 100644 index 0000000..51c2a41 --- /dev/null +++ b/fs/grubfs/fsys_iso9660.c @@ -0,0 +1,336 @@ +/* + * ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader) + * including Rock Ridge Extensions support + * + * Copyright (C) 1998, 1999 Kousuke Takai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * References: + * linux/fs/isofs/rock.[ch] + * mkisofs-1.11.1/diag/isoinfo.c + * mkisofs-1.11.1/iso9660.h + * (all are written by Eric Youngdale) + * + * Modifications by: + * Leonid Lisovskiy 2003 + */ + +/* + * Modified to make it work with FILO + * 2003-10 by SONE Takeshi + */ + +#ifdef FSYS_ISO9660 + +#include "shared.h" +#include "filesys.h" +#include "iso9660.h" +#define DEBUG_THIS 1 +#include "debug.h" + +struct iso_superblock { + unsigned long vol_sector; + + unsigned long file_start; +}; + +#define ISO_SUPER ((struct iso_superblock *)(FSYS_BUF)) +#define PRIMDESC ((struct iso_primary_descriptor *)(FSYS_BUF + 2048)) +#define DIRREC ((struct iso_directory_record *)(FSYS_BUF + 4096)) +#define RRCONT_BUF ((unsigned char *)(FSYS_BUF + 6144)) +#define NAME_BUF ((unsigned char *)(FSYS_BUF + 8192)) + +static int +iso9660_devread (int sector, int byte_offset, int byte_len, char *buf) +{ + /* FILO uses 512-byte "soft" sector, and ISO-9660 uses 2048-byte + * CD-ROM sector */ + return devread(sector<<2, byte_offset, byte_len, buf); +} + +int +iso9660_mount (void) +{ + unsigned int sector; + + /* + * Because there is no defined slice type ID for ISO-9660 filesystem, + * this test will pass only either (1) if entire disk is used, or + * (2) if current partition is BSD style sub-partition whose ID is + * ISO-9660. + */ + /*if ((current_partition != 0xFFFFFF) + && !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660)) + return 0;*/ + + /* + * Currently, only FIRST session of MultiSession disks are supported !!! + */ + for (sector = 16 ; sector < 32 ; sector++) + { + if (!iso9660_devread(sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC)) + break; + /* check ISO_VD_PRIMARY and ISO_STANDARD_ID */ + if (CHECK4(&PRIMDESC->type, ISO_VD_PRIMARY, 'C', 'D', '0') + && CHECK2(PRIMDESC->id + 3, '0', '1')) + { + ISO_SUPER->vol_sector = sector; + ISO_SUPER->file_start = 0; + fsmax = PRIMDESC->volume_space_size.l; + return 1; + } + } + + return 0; +} + +int +iso9660_dir (char *dirname) +{ + struct iso_directory_record *idr; + RR_ptr_t rr_ptr; + struct rock_ridge *ce_ptr; + unsigned int pathlen; + int size; + unsigned int extent; + unsigned int rr_len; + unsigned char file_type; + unsigned char rr_flag; + + idr = &PRIMDESC->root_directory_record; + ISO_SUPER->file_start = 0; + + do + { + while (*dirname == '/') /* skip leading slashes */ + dirname++; + /* pathlen = strcspn(dirname, "/\n\t "); */ + for (pathlen = 0 ; + dirname[pathlen] + && !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ; + pathlen++) + ; + + size = idr->size.l; + extent = idr->extent.l; + + while (size > 0) + { + if (!iso9660_devread(extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC)) + { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + extent++; + + idr = (struct iso_directory_record *)DIRREC; + for (; idr->length.l > 0; + idr = (struct iso_directory_record *)((char *)idr + idr->length.l) ) + { + const char *name = idr->name; + unsigned int name_len = idr->name_len.l; + + file_type = (idr->flags.l & 2) ? ISO_DIRECTORY : ISO_REGULAR; + if (name_len == 1) + { + if ((name[0] == 0) || /* self */ + (name[0] == 1)) /* parent */ + continue; + } + if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1')) + { + name_len -= 2; /* truncate trailing file version */ + if (name_len > 1 && name[name_len - 1] == '.') + name_len--; /* truncate trailing dot */ + } + + /* + * Parse Rock-Ridge extension + */ + rr_len = (idr->length.l - idr->name_len.l + - (unsigned char)sizeof(struct iso_directory_record) + + (unsigned char)sizeof(idr->name)); + rr_ptr.ptr = ((unsigned char *)idr + idr->name_len.l + + sizeof(struct iso_directory_record) + - sizeof(idr->name)); + if (rr_ptr.i & 1) + rr_ptr.i++, rr_len--; + ce_ptr = NULL; + rr_flag = RR_FLAG_NM | RR_FLAG_PX; + + while (rr_len >= 4) + { + if (rr_ptr.rr->version != 1) + { +#ifndef STAGE1_5 + if (debug) + printf( + "Non-supported version (%d) RockRidge chunk " + "`%c%c'\n", rr_ptr.rr->version, + rr_ptr.rr->signature & 0xFF, + rr_ptr.rr->signature >> 8); +#endif + } + else if (rr_ptr.rr->signature == RRMAGIC('R', 'R') + && rr_ptr.rr->len >= 5) + rr_flag &= rr_ptr.rr->u.rr.flags.l; + else if (rr_ptr.rr->signature == RRMAGIC('N', 'M')) + { + name = rr_ptr.rr->u.nm.name; + name_len = rr_ptr.rr->len - 5; + rr_flag &= ~RR_FLAG_NM; + } + else if (rr_ptr.rr->signature == RRMAGIC('P', 'X') + && rr_ptr.rr->len >= 36) + { + file_type = ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT) + == POSIX_S_IFREG + ? ISO_REGULAR + : ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT) + == POSIX_S_IFDIR + ? ISO_DIRECTORY : ISO_OTHER)); + rr_flag &= ~RR_FLAG_PX; + } + else if (rr_ptr.rr->signature == RRMAGIC('C', 'E') + && rr_ptr.rr->len >= 28) + ce_ptr = rr_ptr.rr; + if (!rr_flag) + /* + * There is no more extension we expects... + */ + break; + rr_len -= rr_ptr.rr->len; + rr_ptr.ptr += rr_ptr.rr->len; + if (rr_len < 4 && ce_ptr != NULL) + { + /* preserve name before loading new extent. */ + if( RRCONT_BUF <= (unsigned char *)name + && (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE ) + { + memcpy(NAME_BUF, name, name_len); + name = NAME_BUF; + } + rr_ptr.ptr = RRCONT_BUF + ce_ptr->u.ce.offset.l; + rr_len = ce_ptr->u.ce.size.l; + if (!iso9660_devread(ce_ptr->u.ce.extent.l, 0, ISO_SECTOR_SIZE, RRCONT_BUF)) + { + errnum = 0; /* this is not fatal. */ + break; + } + ce_ptr = NULL; + } + } /* rr_len >= 4 */ + + filemax = MAXINT; + if (name_len >= pathlen + && !__builtin_memcmp(name, dirname, pathlen)) + { + if (dirname[pathlen] == '/' || !print_possibilities) + { + /* + * DIRNAME is directory component of pathname, + * or we are to open a file. + */ + if (pathlen == name_len) + { + if (dirname[pathlen] == '/') + { + if (file_type != ISO_DIRECTORY) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + goto next_dir_level; + } + if (file_type != ISO_REGULAR) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + ISO_SUPER->file_start = idr->extent.l; + filepos = 0; + filemax = idr->size.l; + return 1; + } + } + else /* Completion */ + { +#ifndef STAGE1_5 + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + memcpy(NAME_BUF, name, name_len); + NAME_BUF[name_len] = '\0'; + print_a_completion (NAME_BUF); +#endif + } + } + } /* for */ + + size -= ISO_SECTOR_SIZE; + } /* size>0 */ + + if (dirname[pathlen] == '/' || print_possibilities >= 0) + { + errnum = ERR_FILE_NOT_FOUND; + return 0; + } + +next_dir_level: + dirname += pathlen; + + } while (*dirname == '/'); + + return 1; +} + +int +iso9660_read (char *buf, int len) +{ + int sector, blkoffset, size, ret; + + if (ISO_SUPER->file_start == 0) + return 0; + + ret = 0; + blkoffset = filepos & (ISO_SECTOR_SIZE - 1); + sector = filepos >> ISO_SECTOR_BITS; + while (len > 0) + { + size = ISO_SECTOR_SIZE - blkoffset; + if (size > len) + size = len; + + disk_read_func = disk_read_hook; + + if (!iso9660_devread(ISO_SUPER->file_start + sector, blkoffset, size, buf)) + return 0; + + disk_read_func = NULL; + + len -= size; + buf += size; + ret += size; + filepos += size; + sector++; + blkoffset = 0; + } + + return ret; +} + +#endif /* FSYS_ISO9660 */ + diff --git a/fs/grubfs/fsys_jfs.c b/fs/grubfs/fsys_jfs.c new file mode 100644 index 0000000..307f836 --- /dev/null +++ b/fs/grubfs/fsys_jfs.c @@ -0,0 +1,403 @@ +/* fsys_jfs.c - an implementation for the IBM JFS file system */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2001,2002 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef FSYS_JFS + +#include "shared.h" +#include "filesys.h" +#include "jfs.h" + +#define MAX_LINK_COUNT 8 + +#define DTTYPE_INLINE 0 +#define DTTYPE_PAGE 1 + +struct jfs_info +{ + int bsize; + int l2bsize; + int bdlog; + int xindex; + int xlastindex; + int sindex; + int slastindex; + int de_index; + int dttype; + xad_t *xad; + ldtentry_t *de; +}; + +static struct jfs_info jfs; + +#define xtpage ((xtpage_t *)FSYS_BUF) +#define dtpage ((dtpage_t *)((char *)FSYS_BUF + 4096)) +#define fileset ((dinode_t *)((char *)FSYS_BUF + 8192)) +#define inode ((dinode_t *)((char *)FSYS_BUF + 8192 + sizeof(dinode_t))) +#define dtroot ((dtroot_t *)(&inode->di_btroot)) + +static ldtentry_t de_always[2] = { + {1, -1, 2, {'.', '.'}}, + {1, -1, 1, {'.'}} +}; + +static int +isinxt (s64 key, s64 offset, s64 len) +{ + return (key >= offset) ? (key < offset + len ? 1 : 0) : 0; +} + +static xad_t * +first_extent (dinode_t *di) +{ + xtpage_t *xtp; + + jfs.xindex = 2; + xtp = (xtpage_t *)&di->di_btroot; + jfs.xad = &xtp->xad[2]; + if (xtp->header.flag & BT_LEAF) { + jfs.xlastindex = xtp->header.nextindex; + } else { + do { + devread (addressXAD (jfs.xad) << jfs.bdlog, 0, + sizeof(xtpage_t), (char *)xtpage); + jfs.xad = &xtpage->xad[2]; + } while (!(xtpage->header.flag & BT_LEAF)); + jfs.xlastindex = xtpage->header.nextindex; + } + + return jfs.xad; +} + +static xad_t * +next_extent (void) +{ + if (++jfs.xindex < jfs.xlastindex) { + } else if (xtpage->header.next) { + devread (xtpage->header.next << jfs.bdlog, 0, + sizeof(xtpage_t), (char *)xtpage); + jfs.xlastindex = xtpage->header.nextindex; + jfs.xindex = XTENTRYSTART; + jfs.xad = &xtpage->xad[XTENTRYSTART]; + } else { + return NULL; + } + return ++jfs.xad; +} + + +static void +di_read (u32 inum, dinode_t *di) +{ + s64 key; + u32 xd, ioffset; + s64 offset; + xad_t *xad; + pxd_t pxd; + + key = (((inum >> L2INOSPERIAG) << L2INOSPERIAG) + 4096) >> jfs.l2bsize; + xd = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT; + ioffset = ((inum & (INOSPERIAG - 1)) & (INOSPEREXT - 1)) << L2DISIZE; + xad = first_extent (fileset); + do { + offset = offsetXAD (xad); + if (isinxt (key, offset, lengthXAD (xad))) { + devread ((addressXAD (xad) + key - offset) << jfs.bdlog, + 3072 + xd*sizeof(pxd_t), sizeof(pxd_t), (char *)&pxd); + devread (addressPXD (&pxd) << jfs.bdlog, + ioffset, DISIZE, (char *)di); + break; + } + } while ((xad = next_extent ())); +} + +static ldtentry_t * +next_dentry (void) +{ + ldtentry_t *de; + s8 *stbl; + + if (jfs.dttype == DTTYPE_INLINE) { + if (jfs.sindex < jfs.slastindex) { + return (ldtentry_t *)&dtroot->slot[(int)dtroot->header.stbl[jfs.sindex++]]; + } + } else { + de = (ldtentry_t *)dtpage->slot; + stbl = (s8 *)&de[(int)dtpage->header.stblindex]; + if (jfs.sindex < jfs.slastindex) { + return &de[(int)stbl[jfs.sindex++]]; + } else if (dtpage->header.next) { + devread (dtpage->header.next << jfs.bdlog, 0, + sizeof(dtpage_t), (char *)dtpage); + jfs.slastindex = dtpage->header.nextindex; + jfs.sindex = 1; + return &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]]; + } + } + + return (jfs.de_index < 2) ? &de_always[jfs.de_index++] : NULL; +} + +static ldtentry_t * +first_dentry (void) +{ + dtroot_t *dtr; + pxd_t *xd; + idtentry_t *de; + + dtr = (dtroot_t *)&inode->di_btroot; + jfs.sindex = 0; + jfs.de_index = 0; + + de_always[0].inumber = inode->di_parent; + de_always[1].inumber = inode->di_number; + if (dtr->header.flag & BT_LEAF) { + jfs.dttype = DTTYPE_INLINE; + jfs.slastindex = dtr->header.nextindex; + } else { + de = (idtentry_t *)dtpage->slot; + jfs.dttype = DTTYPE_PAGE; + xd = &((idtentry_t *)dtr->slot)[(int)dtr->header.stbl[0]].xd; + for (;;) { + devread (addressPXD (xd) << jfs.bdlog, 0, + sizeof(dtpage_t), (char *)dtpage); + if (dtpage->header.flag & BT_LEAF) + break; + xd = &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]].xd; + } + jfs.slastindex = dtpage->header.nextindex; + } + + return next_dentry (); +} + + +static dtslot_t * +next_dslot (int next) +{ + return (jfs.dttype == DTTYPE_INLINE) + ? (dtslot_t *)&dtroot->slot[next] + : &((dtslot_t *)dtpage->slot)[next]; +} + +static void +uni2ansi (UniChar *uni, char *ansi, int len) +{ + for (; len; len--, uni++) + *ansi++ = (*uni & 0xff80) ? '?' : *(char *)uni; +} + +int +jfs_mount (void) +{ + struct jfs_superblock super; + + if (part_length < MINJFS >> SECTOR_BITS + || !devread (SUPER1_OFF >> SECTOR_BITS, 0, + sizeof(struct jfs_superblock), (char *)&super) + || (super.s_magic != JFS_MAGIC) + || !devread ((AITBL_OFF >> SECTOR_BITS) + FILESYSTEM_I, + 0, DISIZE, (char*)fileset)) { + return 0; + } + + jfs.bsize = super.s_bsize; + jfs.l2bsize = super.s_l2bsize; + jfs.bdlog = jfs.l2bsize - SECTOR_BITS; + + return 1; +} + +int +jfs_read (char *buf, int len) +{ + xad_t *xad; + s64 endofprev, endofcur; + s64 offset, xadlen; + int toread, startpos, endpos; + + startpos = filepos; + endpos = filepos + len; + endofprev = (1ULL << 62) - 1; + xad = first_extent (inode); + do { + offset = offsetXAD (xad); + xadlen = lengthXAD (xad); + if (isinxt (filepos >> jfs.l2bsize, offset, xadlen)) { + endofcur = (offset + xadlen) << jfs.l2bsize; + toread = (endofcur >= endpos) + ? len : (endofcur - filepos); + + disk_read_func = disk_read_hook; + devread (addressXAD (xad) << jfs.bdlog, + filepos - (offset << jfs.l2bsize), toread, buf); + disk_read_func = NULL; + + buf += toread; + len -= toread; + filepos += toread; + } else if (offset > endofprev) { + toread = ((offset << jfs.l2bsize) >= endpos) + ? len : ((offset - endofprev) << jfs.l2bsize); + len -= toread; + filepos += toread; + for (; toread; toread--) { + *buf++ = 0; + } + continue; + } + endofprev = offset + xadlen; + xad = next_extent (); + } while (len > 0 && xad); + + return filepos - startpos; +} + +int +jfs_dir (char *dirname) +{ + char *ptr, *rest, ch; + ldtentry_t *de; + dtslot_t *ds; + u32 inum, parent_inum; + s64 di_size; + u32 di_mode; + int namlen, cmp, n, link_count; + char namebuf[JFS_NAME_MAX + 1], linkbuf[JFS_PATH_MAX]; + + parent_inum = inum = ROOT_I; + link_count = 0; + for (;;) { + di_read (inum, inode); + di_size = inode->di_size; + di_mode = inode->di_mode; + + if ((di_mode & IFMT) == IFLNK) { + if (++link_count > MAX_LINK_COUNT) { + errnum = ERR_SYMLINK_LOOP; + return 0; + } + if (di_size < (di_mode & INLINEEA ? 256 : 128)) { + grub_memmove (linkbuf, inode->di_fastsymlink, di_size); + n = di_size; + } else if (di_size < JFS_PATH_MAX - 1) { + filepos = 0; + filemax = di_size; + n = jfs_read (linkbuf, filemax); + } else { + errnum = ERR_FILELENGTH; + return 0; + } + + inum = (linkbuf[0] == '/') ? ROOT_I : parent_inum; + while (n < (JFS_PATH_MAX - 1) && (linkbuf[n++] = *dirname++)); + linkbuf[n] = 0; + dirname = linkbuf; + continue; + } + + if (!*dirname || isspace (*dirname)) { + if ((di_mode & IFMT) != IFREG) { + errnum = ERR_BAD_FILETYPE; + return 0; + } + filepos = 0; + filemax = di_size; + return 1; + } + + if ((di_mode & IFMT) != IFDIR) { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + for (; *dirname == '/'; dirname++); + + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); + *rest = 0; + + de = first_dentry (); + for (;;) { + namlen = de->namlen; + if (de->next == -1) { + uni2ansi (de->name, namebuf, namlen); + namebuf[namlen] = 0; + } else { + uni2ansi (de->name, namebuf, DTLHDRDATALEN); + ptr = namebuf; + ptr += DTLHDRDATALEN; + namlen -= DTLHDRDATALEN; + ds = next_dslot (de->next); + while (ds->next != -1) { + uni2ansi (ds->name, ptr, DTSLOTDATALEN); + ptr += DTSLOTDATALEN; + namlen -= DTSLOTDATALEN; + ds = next_dslot (ds->next); + } + uni2ansi (ds->name, ptr, namlen); + ptr += namlen; + *ptr = 0; + } + + cmp = (!*dirname) ? -1 : substring (dirname, namebuf); +#ifndef STAGE1_5 + if (print_possibilities && ch != '/' + && cmp <= 0) { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion (namebuf); + } else +#endif + if (cmp == 0) { + parent_inum = inum; + inum = de->inumber; + *(dirname = rest) = ch; + break; + } + de = next_dentry (); + if (de == NULL) { + if (print_possibilities < 0) + return 1; + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; + } + } + } +} + +int +jfs_embed (int *start_sector, int needed_sectors) +{ + struct jfs_superblock super; + + if (needed_sectors > 63 + || !devread (SUPER1_OFF >> SECTOR_BITS, 0, + sizeof (struct jfs_superblock), + (char *)&super) + || (super.s_magic != JFS_MAGIC)) { + return 0; + } + + *start_sector = 1; + return 1; +} + +#endif /* FSYS_JFS */ diff --git a/fs/grubfs/fsys_minix.c b/fs/grubfs/fsys_minix.c new file mode 100644 index 0000000..4b365ed --- /dev/null +++ b/fs/grubfs/fsys_minix.c @@ -0,0 +1,534 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Restrictions: + This is MINIX V1 only (yet) + Disk creation is like: + mkfs.minix -c DEVICE +*/ + +#ifdef FSYS_MINIX + +#include "shared.h" +#include "filesys.h" + +/* #define DEBUG_MINIX */ + +/* indirect blocks */ +static int mapblock1, mapblock2, namelen; + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1<. Oh well. */ +#define MINIX_LINK_MAX 250 +#define MINIX2_LINK_MAX 65530 + +#define MINIX_I_MAP_SLOTS 8 +#define MINIX_Z_MAP_SLOTS 64 +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ +#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ +#define MINIX_VALID_FS 0x0001 /* Clean fs. */ +#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) + +#define MINIX_V1 0x0001 /* original minix fs */ +#define MINIX_V2 0x0002 /* minix V2 fs */ + +/* originally this is : +#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version + here we have */ +#define INODE_VERSION(inode) (SUPERBLOCK->s_version) + +/* + * This is the original minix inode layout on disk. + * Note the 8-bit gid and atime and ctime. + */ +struct minix_inode { + __u16 i_mode; + __u16 i_uid; + __u32 i_size; + __u32 i_time; + __u8 i_gid; + __u8 i_nlinks; + __u16 i_zone[9]; +}; + +/* + * The new minix inode has all the time entries, as well as + * long block numbers and a third indirect block (7+1+1+1 + * instead of 7+1+1). Also, some previously 8-bit values are + * now 16-bit. The inode is now 64 bytes instead of 32. + */ +struct minix2_inode { + __u16 i_mode; + __u16 i_nlinks; + __u16 i_uid; + __u16 i_gid; + __u32 i_size; + __u32 i_atime; + __u32 i_mtime; + __u32 i_ctime; + __u32 i_zone[10]; +}; + +/* + * minix super-block data on disk + */ +struct minix_super_block { + __u16 s_ninodes; + __u16 s_nzones; + __u16 s_imap_blocks; + __u16 s_zmap_blocks; + __u16 s_firstdatazone; + __u16 s_log_zone_size; + __u32 s_max_size; + __u16 s_magic; + __u16 s_state; + __u32 s_zones; +}; + +struct minix_dir_entry { + __u16 inode; + char name[0]; +}; + +/* made up, these are pointers into FSYS_BUF */ +/* read once, always stays there: */ +#define SUPERBLOCK \ + ((struct minix_super_block *)(FSYS_BUF)) +#define INODE \ + ((struct minix_inode *)((char *) SUPERBLOCK + BLOCK_SIZE)) +#define DATABLOCK1 \ + ((char *)((char *)INODE + sizeof(struct minix_inode))) +#define DATABLOCK2 \ + ((char *)((char *)DATABLOCK1 + BLOCK_SIZE)) + +/* linux/stat.h */ +#define S_IFMT 00170000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFDIR 0040000 +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + +#define PATH_MAX 1024 /* include/linux/limits.h */ +#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */ + +/* check filesystem types and read superblock into memory buffer */ +int +minix_mount (void) +{ + if (((current_drive & 0x80) || current_slice != 0) + && ! IS_PC_SLICE_TYPE_MINIX (current_slice) + && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)) + return 0; /* The partition is not of MINIX type */ + + if (part_length < (SBLOCK + + (sizeof (struct minix_super_block) / DEV_BSIZE))) + return 0; /* The partition is too short */ + + if (!devread (SBLOCK, 0, sizeof (struct minix_super_block), + (char *) SUPERBLOCK)) + return 0; /* Cannot read superblock */ + + switch (SUPERBLOCK->s_magic) + { + case MINIX_SUPER_MAGIC: + namelen = 14; + break; + case MINIX_SUPER_MAGIC2: + namelen = 30; + break; + default: + return 0; /* Unsupported type */ + } + + return 1; +} + +/* Takes a file system block number and reads it into BUFFER. */ +static int +minix_rdfsb (int fsblock, char *buffer) +{ + return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0, + BLOCK_SIZE, buffer); +} + +/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into + a physical block (the location in the file system) via an inode. */ +static int +minix_block_map (int logical_block) +{ + int i; + + if (logical_block < 7) + return INODE->i_zone[logical_block]; + + logical_block -= 7; + if (logical_block < 512) + { + i = INODE->i_zone[7]; + + if (!i || ((mapblock1 != 1) + && !minix_rdfsb (i, DATABLOCK1))) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 1; + return ((__u16 *) DATABLOCK1) [logical_block]; + } + + logical_block -= 512; + i = INODE->i_zone[8]; + if (!i || ((mapblock1 != 2) + && !minix_rdfsb (i, DATABLOCK1))) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 2; + i = ((__u16 *) DATABLOCK1)[logical_block >> 9]; + if (!i || ((mapblock2 != i) + && !minix_rdfsb (i, DATABLOCK2))) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock2 = i; + return ((__u16 *) DATABLOCK2)[logical_block & 511]; +} + +/* read from INODE into BUF */ +int +minix_read (char *buf, int len) +{ + int logical_block; + int offset; + int map; + int ret = 0; + int size = 0; + + while (len > 0) + { + /* find the (logical) block component of our location */ + logical_block = filepos >> BLOCK_SIZE_BITS; + offset = filepos & (BLOCK_SIZE - 1); + map = minix_block_map (logical_block); +#ifdef DEBUG_MINIX + printf ("map=%d\n", map); +#endif + if (map < 0) + break; + + size = BLOCK_SIZE; + size -= offset; + if (size > len) + size = len; + + disk_read_func = disk_read_hook; + + devread (map * (BLOCK_SIZE / DEV_BSIZE), + offset, size, buf); + + disk_read_func = NULL; + + buf += size; + len -= size; + filepos += size; + ret += size; + } + + if (errnum) + ret = 0; + + return ret; +} + +/* preconditions: minix_mount already executed, therefore supblk in buffer + known as SUPERBLOCK + returns: 0 if error, nonzero iff we were able to find the file successfully + postconditions: on a nonzero return, buffer known as INODE contains the + inode of the file we were trying to look up + side effects: none yet */ +int +minix_dir (char *dirname) +{ + int current_ino = MINIX_ROOT_INO; /* start at the root */ + int updir_ino = current_ino; /* the parent of the current directory */ + int ino_blk; /* fs pointer of the inode's info */ + + int str_chk = 0; /* used ot hold the results of a string + compare */ + + struct minix_inode * raw_inode; /* inode info for current_ino */ + + char linkbuf[PATH_MAX]; /* buffer for following sym-links */ + int link_count = 0; + + char * rest; + char ch; + + int off; /* offset within block of directory + entry */ + int loc; /* location within a directory */ + int blk; /* which data blk within dir entry */ + long map; /* fs pointer of a particular block from + dir entry */ + struct minix_dir_entry * dp; /* pointer to directory entry */ + + /* loop invariants: + current_ino = inode to lookup + dirname = pointer to filename component we are cur looking up within + the directory known pointed to by current_ino (if any) */ + +#ifdef DEBUG_MINIX + printf ("\n"); +#endif + + while (1) + { +#ifdef DEBUG_MINIX + printf ("inode %d, dirname %s\n", current_ino, dirname); +#endif + + ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks + + (current_ino - 1) / MINIX_INODES_PER_BLOCK); + if (! minix_rdfsb (ino_blk, (char *) INODE)) + return 0; + + /* reset indirect blocks! */ + mapblock2 = mapblock1 = -1; + + raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK); + + /* copy inode to fixed location */ + memmove ((void *) INODE, (void *) raw_inode, + sizeof (struct minix_inode)); + + /* If we've got a symbolic link, then chase it. */ + if (S_ISLNK (INODE->i_mode)) + { + int len; + + if (++link_count > MAX_LINK_COUNT) + { + errnum = ERR_SYMLINK_LOOP; + return 0; + } +#ifdef DEBUG_MINIX + printf ("S_ISLNK (%s)\n", dirname); +#endif + + /* Find out how long our remaining name is. */ + len = 0; + while (dirname[len] && !isspace (dirname[len])) + len++; + + /* Get the symlink size. */ + filemax = (INODE->i_size); + if (filemax + len > sizeof (linkbuf) - 2) + { + errnum = ERR_FILELENGTH; + return 0; + } + + if (len) + { + /* Copy the remaining name to the end of the symlink data. + Note that DIRNAME and LINKBUF may overlap! */ + memmove (linkbuf + filemax, dirname, len); + } + linkbuf[filemax + len] = '\0'; + + /* Read the necessary blocks, and reset the file pointer. */ + len = grub_read (linkbuf, filemax); + filepos = 0; + if (!len) + return 0; + +#ifdef DEBUG_MINIX + printf ("symlink=%s\n", linkbuf); +#endif + + dirname = linkbuf; + if (*dirname == '/') + { + /* It's an absolute link, so look it up in root. */ + current_ino = MINIX_ROOT_INO; + updir_ino = current_ino; + } + else + { + /* Relative, so look it up in our parent directory. */ + current_ino = updir_ino; + } + + /* Try again using the new name. */ + continue; + } + + /* If end of filename, INODE points to the file's inode */ + if (!*dirname || isspace (*dirname)) + { + if (!S_ISREG (INODE->i_mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + filemax = (INODE->i_size); + return 1; + } + + /* else we have to traverse a directory */ + updir_ino = current_ino; + + /* skip over slashes */ + while (*dirname == '/') + dirname++; + + /* if this isn't a directory of sufficient size to hold our file, + abort */ + if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + /* skip to next slash or end of filename (space) */ + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; + rest++); + + /* look through this directory and find the next filename component */ + /* invariant: rest points to slash after the next filename component */ + *rest = 0; + loc = 0; + + do + { +#ifdef DEBUG_MINIX + printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc); +#endif + + /* if our location/byte offset into the directory exceeds the size, + give up */ + if (loc >= INODE->i_size) + { + if (print_possibilities < 0) + { +#if 0 + putchar ('\n'); +#endif + } + else + { + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + } + return (print_possibilities < 0); + } + + /* else, find the (logical) block component of our location */ + blk = loc >> BLOCK_SIZE_BITS; + + /* we know which logical block of the directory entry we are looking + for, now we have to translate that to the physical (fs) block on + the disk */ + map = minix_block_map (blk); +#ifdef DEBUG_MINIX + printf ("fs block=%d\n", map); +#endif + mapblock2 = -1; + if ((map < 0) || !minix_rdfsb (map, DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + *rest = ch; + return 0; + } + off = loc & (BLOCK_SIZE - 1); + dp = (struct minix_dir_entry *) (DATABLOCK2 + off); + /* advance loc prematurely to next on-disk directory entry */ + loc += sizeof (dp->inode) + namelen; + + /* NOTE: minix filenames are NULL terminated if < NAMELEN + else exact */ + +#ifdef DEBUG_MINIX + printf ("directory entry ino=%d\n", dp->inode); + if (dp->inode) + printf ("entry=%s\n", dp->name); +#endif + + if (dp->inode) + { + int saved_c = dp->name[namelen]; + + dp->name[namelen] = 0; + str_chk = substring (dirname, dp->name); + +# ifndef STAGE1_5 + if (print_possibilities && ch != '/' + && (!*dirname || str_chk <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion (dp->name); + } +# endif + + dp->name[namelen] = saved_c; + } + + } + while (!dp->inode || (str_chk || (print_possibilities && ch != '/'))); + + current_ino = dp->inode; + *(dirname = rest) = ch; + } + /* never get here */ +} + +#endif /* FSYS_MINIX */ diff --git a/fs/grubfs/fsys_ntfs.c b/fs/grubfs/fsys_ntfs.c new file mode 100644 index 0000000..a58e976 --- /dev/null +++ b/fs/grubfs/fsys_ntfs.c @@ -0,0 +1,1254 @@ +/* vim: set sw=4 :*/ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Samuel Leo + * Limitations: + * 1. Only 32 bit size support + * 2. don't support >1k MFT record size, >16k INDEX record size + * 3. don't support recursive at_attribute_list + * 4. don't support compressed attribute other than Datastream + * 5. all MFT's at_attribute_list must resident at first run list + * 6. don't support journaling + * 7. don't support EFS encryption + * 8. don't support mount point and junction + */ +#ifdef FSYS_NTFS + +//#define DEBUG_NTFS 1 + +/* +#define NO_ATTRIBUTE_LIST 1 + totally disable at_attribute_list support, + if no compressed/fragment file and MFT, + not recommended +#define NO_NON_RESIDENT_ATTRIBUTE_LIST 1 + disable non-resident at_attribute_list support, + if no huge compressed/fragment file and MFT +#define NO_NTFS_DECOMPRESSION 1 + disable ntfs compressed file support +#define NO_ALTERNATE_DATASTREAM 1 + disable ntfs alternate datastream support +*/ + +#include "shared.h" +#include "filesys.h" + +#ifdef STAGE1_5 +/* safe turn off non-resident attribute list if MFT fragments < 4000 */ +//#define NO_NON_RESIDENT_ATTRIBUTE_LIST 1 +#define NO_NTFS_DECOMPRESSION 1 +#endif + +#define MAX_MFT_RECORD_SIZE 1024 +#define MAX_INDEX_RECORD_SIZE 16384 +#define MAX_INDEX_BITMAP_SIZE 4096 +#define DECOMP_DEST_BUFFER_SIZE 16384 +#define DECOMP_SOURCE_BUFFER_SIZE (8192+2) +#define MAX_DIR_DEPTH 64 + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE 512 + +#define WHICH_SUPER 1 +#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */ + +/* include/asm-i386/type.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; +typedef __signed__ long long __s64; +typedef unsigned long long __u64; + +#define FILE_MFT 0 +#define FILE_MFTMIRR 1 +#define FILE_LOGFILE 2 +#define FILE_VOLUME 3 +#define FILE_ATTRDEF 4 +#define FILE_ROOT 5 +#define FILE_BITMAP 6 +#define FILE_BOOT 7 +#define FILE_BADCLUS 8 +#define FILE_QUOTA 9 +#define FILE_UPCASE 10 + +#define at_standard_information 0x10 +#define at_attribute_list 0x20 +#define at_filename 0x30 +#define at_security_descriptor 0x50 +#define at_data 0x80 +#define at_index_root 0x90 +#define at_index_allocation 0xa0 +#define at_bitmap 0xb0 +#define at_symlink 0xc0 + +#define NONAME "" +#define ATTR_NORMAL 0 +#define ATTR_COMPRESSED 1 +#define ATTR_RESIDENT 2 +#define ATTR_ENCRYPTED 16384 +#define ATTR_SPARSE 32768 + +typedef struct run_list { + char *start; + char *ptr; + int svcn; + int evcn; + int vcn; + int cnum0; + int cnum; + int clen; +} RUNL; + +typedef struct ntfs_mft_record { + char mft[MAX_MFT_RECORD_SIZE]; + char mft2[MAX_MFT_RECORD_SIZE]; + int attr_type; + char *attr_name; + int attr_flag; + int attr_size; + char *attr; + int attr_len; + RUNL runl; + char *attr_list; + int attr_list_len; + int attr_list_size; + int attr_list_off; + int attr_inited; + char attr_list_buf[2*BLOCK_SIZE]; + RUNL attr_list_runl; +} MFTR; + + +#define index_data ((char *)FSYS_BUF) +#define bitmap_data ((__u8 *)(FSYS_BUF+MAX_INDEX_RECORD_SIZE)) +#define dcdbuf ((__u8 *)index_data) +#define dcsbuf (bitmap_data) +#define dcend (dcsbuf+DECOMP_SOURCE_BUFFER_SIZE) +#define fnbuf ((char *)(bitmap_data+MAX_INDEX_BITMAP_SIZE)) +#define mmft ((MFTR *)dcend) +#define cmft ((MFTR *)(dcend+sizeof(MFTR))) +#define mft_run ((RUNL *)(dcend+2*sizeof(MFTR))) +#define path_ino ((int *)(dcend+2*sizeof(MFTR)+sizeof(RUNL))) +#define cluster16 (path_ino+MAX_DIR_DEPTH) +#define index16 cluster16[16] +#define blocksize cluster16[17] +#define clustersize cluster16[18] +#define mft_record_size cluster16[19] +#define index_record_size cluster16[20] +#define dcvcn cluster16[21] +#define dcoff cluster16[22] +#define dclen cluster16[23] +#define dcrem cluster16[24] +#define dcslen cluster16[25] +#define dcsptr ((__u8 *)cluster16[26]) +#define is_ads_completion cluster16[27] + +static int read_mft_record(int mftno, char *mft, int self); +static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl); +static int get_next_run(RUNL *runl); + +static inline int +nsubstring (char *s1, char *s2) +{ + while (tolower(*s1) == tolower(*s2)) + { + /* The strings match exactly. */ + if (! *(s1++)) + return 0; + s2 ++; + } + + /* S1 is a substring of S2. */ + if (*s1 == 0) + return -1; + + /* S1 isn't a substring. */ + return 1; +} + +static int fixup_record(char *record, char *magic, int size) +{ + int start, count, offset; + __u16 fixup; + + if(*(int *)record != *(int *)magic) + return 0; + start=*(__u16 *)(record+4); + count=*(__u16 *)(record+6); + count--; + if(size && blocksize*count != size) + return 0; + fixup = *(__u16 *)(record+start); + start+=2; + offset=blocksize-2; + while(count--){ + if(*(__u16 *)(record+offset)!=fixup) + return 0; + *(__u16 *)(record+offset) = *(__u16 *)(record+start); + start+=2; + offset+=blocksize; + } + return 1; +} + +static void rewind_run_list( RUNL *runl) { + runl->vcn = runl->svcn; + runl->ptr = runl->start; + runl->cnum0 = 0; + runl->cnum = 0; + runl->clen = 0; +} + +static int get_next_run(RUNL *runl){ + int t, n, v; + +#ifdef DEBUG_NTFS + printf("get_next_run: s=%d e=%d c=%d start=%x ptr=%x\n", + runl->svcn, runl->evcn, runl->vcn, runl->start, runl->ptr); +#endif + + runl->vcn += runl->clen; + if(runl->vcn > runl->evcn) { + return 0; + } + + t = *(runl->ptr)++; + n = t&0xf; + runl->clen = 0; v = 1; + while(n--) { + runl->clen += v * *((__u8 *)runl->ptr)++; + v <<= 8; + } + n = (t>>4)&0xf; + if(n==0) + runl->cnum = 0; + else { + int c = 0; + v = 1; + while(n--) { + c += v * *((__u8 *)runl->ptr)++; + v <<= 8; + } + if(c & (v>>1)) c -= v; + runl->cnum0 += c; + runl->cnum = runl->cnum0; + } +#ifdef DEBUG_NTFS + printf("got_next_run: t=%x cluster %x len %x vcn=%x ecn=%x\n", + t, runl->cnum, runl->clen, runl->vcn, runl->evcn); +#endif + return 1; +} + +#ifndef NO_ATTRIBUTE_LIST +static void init_run_list(char *attr, int len, RUNL *runl, __u32 *initp) { + int allocated; + + runl->svcn = *(__u32 *)(attr+0x10); /* only support 32 bit */ + runl->evcn = *(__u32 *)(attr+0x18); /* only support 32 bit */ + runl->start = attr + *(__u16 *)(attr+0x20); + allocated = *(__u32 *)(attr+0x28); + if(initp) *initp = *(__u32 *)(attr+0x38); + if(!runl->evcn) runl->evcn = (allocated - 1) / clustersize; +#ifdef DEBUG_NTFS + printf("size %d allocated=%d inited=%d cegin=%x csize=%d vcn=%d-%d\n", + /*attr_size*/ *(__u32 *)(attr+0x30), + /*allocated*/ *(__u32 *)(attr+0x28), + /*attr_inited*/ *(__u32 *)(attr+0x38), + /*cengin*/ *(__u16 *)(attr+0x22), + /*csize*/ *(__u16 *)(attr+0x40), + runl->svcn, runl->evcn); +#endif + rewind_run_list(runl); +} +#endif + + +static int find_attribute(char *mft, int type, char *name, char **attr, int *size, int *len, int *flag) { + int t, l, r, n, i, namelen; + unsigned short *attr_name; + + n = strlen(name); + r = mft_record_size - *(__u16 *)(mft+0x14); + mft += *(__u16 *)(mft+0x14); + while( (t = *(__s32 *)mft) != -1 ) { + l = *(__u32 *)(mft+4); + if(l>r) break; +#ifdef DEBUG_NTFS + printf("type = %x len = %d namelen=%d resident=%d compresed=%d attrno=%d\n", + t, l, + /*namelen*/ *(mft+9), + //name = (__u16 *)(mft + *(__u16 *)(mft+10)), + /*resident */ (*(mft+8) == 0), + /*compressed*/ *(__u16 *)(mft+12), + /*attrno*/ *(__u16 *)(mft+14)); +#endif + namelen = *(mft+9); + if(t == type) { +#ifndef STAGE1_5 +#ifndef NO_ALTERNATE_DATASTREAM + if(is_ads_completion && type == at_data) { + if(namelen && namelen >= n && + (!*(mft+8)/*resident*/ || !*(__u32 *)(attr+0x10)/*svcn==0*/)) + { + for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i < n; i++) + if(tolower(name[i]) != tolower(attr_name[i])) + break; + if(i >= n) { + for(; i < namelen; i++) + name[i] = attr_name[i]; + name[i] = '\0'; + if(print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion(fnbuf); + name[n] = '\0'; + } + } + } else +#endif +#endif + if(namelen == n) { + + for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i=n) { + if(flag) *flag = *(__u16 *)(mft+12); + if(*(mft+8) == 0) { + if(flag) *flag |= ATTR_RESIDENT; +#ifdef DEBUG_NTFS + printf("resident data at %x size %x indexed=%d\n", + /*data*/ *(__u16 *)(mft+0x14), + /*attr_size*/ *(__u16 *)(mft+0x10), + /*indexed*/ *(__u16 *)(mft+0x16)); +#endif + if(attr) *attr = mft + *(__u16 *)(mft+0x14); + if(size) *size = *(__u16 *)(mft+0x10); + if(len) *len = *(__u16 *)(mft+0x10); + } else { + if(attr) *attr = mft; + if(size) *size = *(__u32 *)(mft+0x30); + if(len) *len = l; + } + return 1; + } + } + } + mft += l; + r -= l; + } + return 0; +} + +#ifndef NO_ATTRIBUTE_LIST +static __u32 get_next_attribute_list(MFTR *mftr, int *size) { + int l, t, mftno; +#ifdef DEBUG_NTFS + printf("get_next_attribute_list: type=%x\n",mftr->attr_type); +#endif +again: + while(mftr->attr_list_len>0x14) { + t = *(__u32 *)(mftr->attr_list + 0); + l = *(__u16 *)(mftr->attr_list + 4); +#ifdef DEBUG_NTFS + printf("attr_list type=%x len=%x remain=%x\n", t, l, mftr->attr_list_len); +#endif + if(l==0 || l>mftr->attr_list_len) return 0; + mftno = *(__u32 *)(mftr->attr_list + 0x10); + mftr->attr_list_len -= l; + mftr->attr_list += l; + if(t==mftr->attr_type) + { +#ifdef DEBUG_NTFS + printf("attr_list mftno=%x\n", mftno); +#endif + if(read_mft_record(mftno, mftr->mft2, (mftr==mmft))==0) + break; + if(find_attribute(mftr->mft2, mftr->attr_type, mftr->attr_name, + &mftr->attr, size, &mftr->attr_len, &mftr->attr_flag)) + return 1; + } + } +#ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST + if(mftr->attr_list_off < mftr->attr_list_size) { + int len = mftr->attr_list_size - mftr->attr_list_off; + if(len > BLOCK_SIZE) len = BLOCK_SIZE; + + if(mftr->attr_list_len) + memmove(mftr->attr_list_buf, mftr->attr_list, mftr->attr_list_len); + mftr->attr_list = mftr->attr_list_buf; + + if(read_attribute( NULL, mftr->attr_list_off, + mftr->attr_list_buf + mftr->attr_list_len, + len, &mftr->attr_list_runl) != len) + { +#ifdef DEBUG_NTFS + printf("CORRUPT NON-RESIDENT ATTRIBUTE_LIST\n"); +#endif + /* corrupt */ + errnum = ERR_FSYS_CORRUPT; + mftr->attr_list_size = 0; + mftr->attr_len = 0; + mftr->attr_list = NULL; + return 0; + } + + mftr->attr_list_len += len; + mftr->attr_list_off += len; + goto again; + } +#endif + mftr->attr_list = NULL; + return 0; +} +#endif + +static int search_attribute( MFTR *mftr, int type, char *name) +{ +#ifdef DEBUG_NTFS + printf("searching attribute %x <%s>\n", type, name); +#endif + + mftr->attr_type = type; + mftr->attr_name = name; + mftr->attr_list = NULL; + mftr->attr_list_len = 0; + mftr->attr_list_size = 0; + mftr->attr_list_off = 0; + dcrem = dclen = 0; + +#ifndef NO_ATTRIBUTE_LIST + if(find_attribute(mftr->mft, at_attribute_list, NONAME, + &mftr->attr_list, &mftr->attr_list_size, + &mftr->attr_list_len, &mftr->attr_list_off)) { + if(mftr->attr_list_off&ATTR_RESIDENT) { + /* resident at_attribute_list */ + mftr->attr_list_size = 0; +#ifdef DEBUG_NTFS + printf("resident attribute_list len=%x\n", mftr->attr_list_len); +#endif + } else { +#ifdef DEBUG_NTFS + printf("non-resident attribute_list len=%x size=%x\n", + mftr->attr_list_len, mftr->attr_list_size); +#endif +#ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST + init_run_list(mftr->attr_list, mftr->attr_list_len, &mftr->attr_list_runl, NULL); + if(get_next_run(&mftr->attr_list_runl)==0 || + mftr->attr_list_runl.cnum==0) + mftr->attr_list_size = 0; +#endif + mftr->attr_list = NULL; + mftr->attr_list_len = 0; + } + } +#endif + + if(find_attribute(mftr->mft, type, name, + &mftr->attr, &mftr->attr_size, &mftr->attr_len, + &mftr->attr_flag) +#ifndef NO_ATTRIBUTE_LIST + || get_next_attribute_list(mftr, &mftr->attr_size) +#endif + ) + { +#ifndef NO_ATTRIBUTE_LIST + if(!(mftr->attr_flag&ATTR_RESIDENT)){ + init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, &mftr->attr_inited); + if(mftr->attr_inited > mftr->attr_size) + mftr->attr_inited = mftr->attr_size; + if(get_next_run(&mftr->runl)==0) { + mftr->attr_flag |= ATTR_RESIDENT; + mftr->attr_len = 0; + } + } else + mftr->attr_inited = mftr->attr_size; +#endif + + return 1; + } + + mftr->attr_type = 0; + return 0; +} + +static int get_run( RUNL *rl, int vcn, int *clp, int *lenp) { + if(rl->evcn < vcn) + return 0; + + if(rl->vcn > vcn) { + rewind_run_list(rl); + get_next_run(rl); + } + + while(rl->vcn+rl->clen <= vcn) + { + if(get_next_run(rl)==0) + return 0; + } + + if(clp) *clp = rl->cnum == 0 ? 0 : rl->cnum + vcn - rl->vcn; + if(lenp) *lenp = rl->clen - vcn + rl->vcn; + return 1; +} + +static int search_run(MFTR *mftr, int vcn) { + + if( mftr->attr==NULL && !search_attribute(mftr, mftr->attr_type, mftr->attr_name)) + return 0; + + if(mftr->runl.svcn > vcn) + search_attribute(mftr, mftr->attr_type, mftr->attr_name); + +#ifdef NO_ATTRIBUTE_LIST + if(mftr->runl.evcn < vcn) + return 0; +#else + while(mftr->runl.evcn < vcn) { + if(get_next_attribute_list(mftr, NULL)==0) { + mftr->attr = NULL; + return 0; + } + init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, NULL); + if(get_next_run(&mftr->runl)==0) { + mftr->attr = NULL; + return 0; + } + } +#endif + + return 1; +} + +static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl) { + int vcn; + int cnum, clen; + int done = 0; + int n; + RUNL *rl; + + if(!from_rl && (mftr->attr_flag & ATTR_RESIDENT)) { + /* resident attribute */ + if(offset > mftr->attr_len) + return 0; + if(offset+len > mftr->attr_len) + len = mftr->attr_len - offset; + memmove( buf, mftr->attr + offset, len); + return len; + } + + vcn = offset / clustersize; + offset %= clustersize; + + while(len>0) { + if(from_rl) + rl = from_rl; + else if(search_run(mftr, vcn) == 0) + break; + else + rl = &mftr->runl; + if(get_run(rl, vcn, &cnum, &clen) == 0) + break; + if(cnum==0 && from_rl) + break; + n = clen * clustersize - offset; + if(n > len) n = len; + if(cnum==0) { + memset( buf, 0, n); + } else if(!devread(cnum*(clustersize>>9)+(offset>>9), offset&0x1ff, n, buf)) + break; + + buf += n; + vcn += (offset+n)/clustersize; + done += n; + offset = 0; + len -= n; + } + return done; +} + +static int read_mft_record(int mftno, char *mft, int self){ +#ifdef DEBUG_NTFS + printf("Reading MFT record: mftno=%d\n", mftno); +#endif + if( read_attribute( mmft, mftno * mft_record_size, + mft, mft_record_size, self?mft_run:NULL) != mft_record_size) + return 0; + if(!fixup_record( mft, "FILE", mft_record_size)) + return 0; + return 1; +} + +#ifndef NO_NTFS_DECOMPRESSION +static int get_16_cluster(MFTR *mftr, int vcn) { + int n = 0, cnum, clen; + while(n < 16 && search_run(mftr, vcn) && get_run(&mftr->runl, vcn, &cnum, &clen) && cnum) { + if(clen > 16 - n) + clen = 16 - n; + vcn += clen; + while(clen--) + cluster16[n++] = cnum++; + } + cluster16[n] = 0; + return n; +} + +static inline int compressed_block_size( unsigned char *src ) { + return 3 + (*(__u16 *)src & 0xfff); +} + +static int decompress_block(unsigned char *dest, unsigned char *src) { + int head; + int copied=0; + unsigned char *last; + int bits; + int tag=0; + + /* high bit indicates that compression was performed */ + if(!(*(__u16 *)src & 0x8000)) { + memmove(dest,src+2,0x1000); + return 0x1000; + } + + if((head = *(__u16 *)src & 0xFFF)==0) + /* block is not used */ + return 0; + + src += 2; + last = src+head; + bits = 0; + + while(src<=last) + { + if(copied>4096) + { +#ifdef DEBUG_NTFS + printf("decompress error 1\n"); +#endif + errnum = ERR_FSYS_CORRUPT; + return 0; + } + if(!bits){ + tag=*(__u8 *)src; + bits=8; + src++; + if(src>last) + break; + } + if(tag & 1){ + int i,len,delta,code,lmask,dshift; + code = *(__u16 *)src; + src+=2; + if(!copied) + { +#ifdef DEBUG_NTFS + printf("decompress error 2\n"); +#endif + errnum = ERR_FSYS_CORRUPT; + return 0; + } + for(i=copied-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1) + { + lmask >>= 1; + dshift--; + } + delta = code >> dshift; + len = (code & lmask) + 3; + for(i=0; i>=1; + bits--; + } + + return copied; +} +#endif + +int ntfs_read(char *buf, int len){ + int ret; +#ifdef STAGE1_5 +/* stage2 can't be resident/compressed/encrypted files, + * but does sparse flag, cause stage2 never sparsed + */ + if((cmft->attr_flag&~ATTR_SPARSE) != ATTR_NORMAL) + return 0; + disk_read_func = disk_read_hook; + ret = read_attribute(cmft, filepos, buf, len, 0); + disk_read_func = NULL; + filepos += ret; +#else + +#ifndef NO_NTFS_DECOMPRESSION + int off; + int vcn; + int size; + int len0; +#endif + + if(len<=0 || filepos >= cmft->attr_size || (cmft->attr_flag&ATTR_ENCRYPTED)) + return 0; + + if(filepos+len > cmft->attr_size) + len = cmft->attr_size - filepos; + if(filepos >= cmft->attr_inited) { +#ifdef DEBUG_NTFS +printf("reading uninitialized data 1\n"); +#endif + memset(buf, 0, len); + return len; + } else if(filepos+len > cmft->attr_inited) { + len0 = len; + len = cmft->attr_inited - filepos; + len0 -= len; + } else + len0 = 0; +#ifdef DEBUG_NTFS +printf("read filepos=%x filemax=%x inited=%x len=%x len0=%x\n",filepos,filemax,cmft->attr_inited,len,len0); +#endif + + if((cmft->attr_flag&(ATTR_COMPRESSED|ATTR_RESIDENT)) != ATTR_COMPRESSED) { + if(cmft->attr_flag==ATTR_NORMAL) + disk_read_func = disk_read_hook; + ret = read_attribute(cmft, filepos, buf, len, 0); + if(cmft->attr_flag==ATTR_NORMAL) + disk_read_func = NULL; + filepos += ret; + if(ret==len && len0) { + memset(buf+len, 0, len0); + filepos += len0; + ret += len0; + } + return ret; + } + + ret = 0; + +#ifndef NO_NTFS_DECOMPRESSION + /* NTFS don't support compression if cluster size > 4k */ + if(clustersize > 4096) { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + + while(len > 0){ +#ifdef DEBUG_NTFS +printf("Reading filepos=%x len=%x\n", filepos, len); +#endif + if(filepos >= dcoff && filepos < (dcoff+dclen)) { +#ifdef DEBUG_NTFS +printf("decompress cache %x+%x\n", dcoff, dclen); +#endif + size = dcoff + dclen - filepos; + if(size > len) size = len; + memmove( buf, dcdbuf + filepos - dcoff, size); + filepos += size; + len -= size; + ret += size; + buf += size; + if(len==0) { + if(len0) { +#ifdef DEBUG_NTFS +printf("reading uninitialized data 2\n"); +#endif + memset(buf, 0, len0); + filepos += len0; + ret += len0; + } + return ret; + } + } + + vcn = filepos / clustersize / 16; + vcn *= 16; + off = filepos % (16 * clustersize); + if( dcvcn != vcn || filepos < dcoff) + dcrem = 0; + +#ifdef DEBUG_NTFS +printf("vcn %x off %x dcrem %x\n", vcn, off, dcrem); +#endif + if(dcrem) { + int head; + + /* reading source */ + if(dcslen < 2 || compressed_block_size(dcsptr) > dcslen) { + if(cluster16[index16]==0) { + errnum = ERR_FSYS_CORRUPT; + return ret; + } + if(dcslen) + memmove(dcsbuf, dcsptr, dcslen); + dcsptr = dcsbuf; + while((dcslen+clustersize) < DECOMP_SOURCE_BUFFER_SIZE) { + if(cluster16[index16]==0) + break; +#ifdef DEBUG_NTFS +printf("reading dcslen=%x cluster %x\n", dcslen, cluster16[index16]); +#endif + if(!devread(cluster16[index16]*(clustersize>>9), 0, clustersize, dcsbuf+dcslen)) + return ret; + dcslen += clustersize; + index16++; + } + } + /* flush destination */ + dcoff += dclen; + dclen = 0; + + while(dcrem && dclen < DECOMP_DEST_BUFFER_SIZE && + dcslen >= 2 && (head=compressed_block_size(dcsptr)) <= dcslen) { + size = decompress_block(dcdbuf+dclen, dcsptr); + if(dcrem>=0x1000 && size!=0x1000) { + errnum = ERR_FSYS_CORRUPT; + return ret; + } + dcrem -= size; + dclen += size; + dcsptr += head; + dcslen -= head; + } + continue; + } + dclen = dcrem = 0; +#ifdef DEBUG_NTFS +printf("get next 16 clusters\n"); +#endif + switch(get_16_cluster(cmft, vcn)) { + case 0: +#ifdef DEBUG_NTFS +printf("sparse\n"); +#endif + /* sparse */ + size = 16 * clustersize - off; + if( len < size ) + size = len; +#ifndef STAGE1_5 + memset( buf, 0, size); +#endif + filepos += size; + len -= size; + ret += size; + buf += size; + break; + + case 16: +#ifdef DEBUG_NTFS +printf("uncompressed\n"); +#endif + /* uncompressed */ + index16 = off / clustersize; + off %= clustersize; + while(index16 < 16) { + size = clustersize - off; + if( len < size ) + size = len; + if(!devread(cluster16[index16]*(clustersize>>9)+(off>>9), off&0x1ff, size, buf)) + return ret; + filepos += size; + len -= size; + ret += size; + if(len==0) + return ret; + off = 0; + buf += size; + index16++; + } + break; + + default: +#ifdef DEBUG_NTFS +printf("compressed\n"); +#endif + index16 = 0; + dcvcn = vcn; + dcoff = vcn * clustersize; + dcrem = cmft->attr_inited - dcoff; + if(dcrem > 16 * clustersize) + dcrem = 16 * clustersize; + dcsptr = dcsbuf; + dcslen = 0; + } + } + if(len0) { +#ifdef DEBUG_NTFS +printf("reading uninitialized data 3\n"); +#endif + memset(buf, 0, len0); + filepos += len0; + ret += len0; + } +#else + errnum = FSYS_CORRUPT; +#endif /*NO_NTFS_DECOMPRESSION*/ +#endif /*STAGE1_5*/ + return ret; +} + +int ntfs_mount (void) +{ + char *sb = (char *)FSYS_BUF; + int mft_record; + int spc; + + if (((current_drive & 0x80) || (current_slice != 0)) + && (current_slice != /*PC_SLICE_TYPE_NTFS*/7) + && (current_slice != /*PC_SLICE_TYPE_NTFS*/0x17)) + return 0; + + if (!devread (0, 0, 512, (char *) FSYS_BUF)) + return 0; /* Cannot read superblock */ + + if(sb[3]!='N' || sb[4]!='T' || sb[5]!='F' || sb[6]!='S') + return 0; + blocksize = *(__u16 *)(sb+0xb); + spc = *(unsigned char *)(sb+0xd); + clustersize = spc * blocksize; + mft_record_size = *(char *)(sb+0x40); + index_record_size = *(char *)(sb+0x44); + if(mft_record_size>0) + mft_record_size *= clustersize; + else + mft_record_size = 1 << (-mft_record_size); + + index_record_size *= clustersize; + mft_record = *(__u32 *)(sb+0x30); /* only support 32 bit */ + spc = clustersize / 512; + + if(mft_record_size > MAX_MFT_RECORD_SIZE || index_record_size > MAX_INDEX_RECORD_SIZE) { + /* only support 1k MFT record, 4k INDEX record */ + return 0; + } + +#ifdef DEBUG_NTFS + printf("spc=%x mft_record=%x:%x\n", spc, *(__s64 *)(sb+0x30)); +#endif + + if (!devread (mft_record*spc, 0, mft_record_size, mmft->mft)) + return 0; /* Cannot read superblock */ + + if(!fixup_record( mmft->mft, "FILE", mft_record_size)) + return 0; + +#ifndef NO_ALTERNATE_DATASTREAM + is_ads_completion = 0; +#endif + if(!search_attribute(mmft, at_data, NONAME)) return 0; + + *mft_run = mmft->runl; + + *path_ino = FILE_ROOT; + + return 1; +} + +int +ntfs_dir (char *dirname) +{ + char *rest, ch; + int namelen; + int depth = 0; + int chk_sfn = 1; + int flag = 0; + int record_offset; + int my_index_record_size; + unsigned char *index_entry = 0, *entry, *index_end; + int i; + + /* main loop to find desired directory entry */ +loop: + +#ifdef DEBUG_NTFS + printf("dirname=%s\n", dirname); +#endif + if(!read_mft_record(path_ino[depth], cmft->mft, 0)) + { +#ifdef DEBUG_NTFS + printf("MFT error 1\n"); +#endif + errnum = ERR_FSYS_CORRUPT; + return 0; + } + + /* if we have a real file (and we're not just printing possibilities), + then this is where we want to exit */ + + if (!*dirname || isspace (*dirname) || *dirname==':') + { +#ifndef STAGE1_5 +#ifndef NO_ALTERNATE_DATASTREAM + if (*dirname==':' && print_possibilities) { + char *tmp; + + /* preparing ADS name completion */ + for(tmp = dirname; *tmp != '/'; tmp--); + for(tmp++, rest=fnbuf; *tmp && !isspace(*tmp); *rest++ = *tmp++) + if(*tmp==':') dirname = rest; + *rest++ = '\0'; + + is_ads_completion = 1; + search_attribute(cmft, at_data, dirname+1); + is_ads_completion = 0; + + if(errnum==0) { + if(print_possibilities < 0) + return 1; + errnum = ERR_FILE_NOT_FOUND; + } + return 0; + } +#endif +#endif + + if (*dirname==':') dirname++; + for (rest = dirname; (ch = *rest) && !isspace (ch); rest++); + *rest = 0; + +#ifdef DEBUG_NTFS + printf("got file: search at_data\n"); +#endif + + if (!search_attribute(cmft, at_data, dirname)) { + errnum = *(dirname-1)==':'?ERR_FILE_NOT_FOUND:ERR_BAD_FILETYPE; + *rest = ch; + return 0; + } + *rest = ch; + + filemax = cmft->attr_size; +#ifdef DEBUG_NTFS + printf("filemax=%x\n", filemax); +#endif + return 1; + } + + if(depth >= (MAX_DIR_DEPTH-1)) { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + + /* continue with the file/directory name interpretation */ + + while (*dirname == '/') + dirname++; + + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/' && ch != ':'; rest++); + + *rest = 0; + + if (!search_attribute(cmft, at_index_root, "$I30")) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + read_attribute(cmft, 0, fnbuf, 16, 0); + my_index_record_size = *(__u32 *)(fnbuf+8); + + if(my_index_record_size > MAX_INDEX_RECORD_SIZE) { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + +#ifdef DEBUG_NTFS + printf("index_record_size=%x\n", my_index_record_size); +#endif + + if(cmft->attr_size > MAX_INDEX_RECORD_SIZE) { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + read_attribute(cmft, 0, index_data, cmft->attr_size, 0); + index_end = index_data + cmft->attr_size; + index_entry = index_data + 0x20; + record_offset = -1; + +#ifndef STAGE1_5 + if (print_possibilities && ch != '/' && ch != ':' && !*dirname) + { + print_possibilities = -print_possibilities; + /* fake '.' for empty directory */ + print_a_completion ("."); + } +#endif + + if (search_attribute(cmft, at_bitmap, "$I30")) { + if(cmft->attr_size > MAX_INDEX_BITMAP_SIZE) { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + + read_attribute(cmft, 0, bitmap_data, cmft->attr_size, 0); + + if (search_attribute(cmft, at_index_allocation, "$I30")==0) { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + + for(record_offset = 0; record_offset*my_index_record_sizeattr_size; record_offset++){ + int bit = 1 << (record_offset&3); + int byte = record_offset>>3; +#ifdef DEBUG_NTFS + printf("record_offset=%x\n", record_offset); +#endif + if((bitmap_data[byte]&bit)) + break; + } + + if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1; + } + + do + { + entry = index_entry; index_entry += *(__u16 *)(entry+8); + if(entry+0x50>=index_entry||entry>=index_end|| + index_entry>=index_end||(entry[0x12]&2)){ + if(record_offset < 0 || + !read_attribute(cmft, record_offset*my_index_record_size, index_data, my_index_record_size, 0)){ + if (!errnum) + { + if (print_possibilities < 0) + { +#if 0 + putchar ('\n'); +#endif + return 1; + } + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + } + + return 0; + } + if(!fixup_record( index_data, "INDX", my_index_record_size)) + { +#ifdef DEBUG_NTFS + printf("index error\n"); +#endif + errnum = ERR_FSYS_CORRUPT; + return 0; + } + entry = index_data + 0x18 + *(__u16 *)(index_data+0x18); + index_entry = entry + *(__u16 *)(entry+8); + index_end = index_data + my_index_record_size - 0x52; + for(record_offset++; record_offset*my_index_record_sizeattr_size; record_offset++){ + int bit = 1 << (record_offset&3); + int byte = record_offset>>3; + if((bitmap_data[byte]&bit)) break; + } + if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1; +#ifdef DEBUG_NTFS + printf("record_offset=%x\n", record_offset); +#endif + } + flag = entry[0x51]; + path_ino[depth+1] = *(__u32 *)entry; + if(path_ino[depth+1] < 16) + continue; + namelen = entry[0x50]; + //if(index_data[0x48]&2) printf("hidden file\n"); +#ifndef STAGE1_5 + /* skip short file name */ + if( flag == 2 && print_possibilities && ch != '/' && ch != ':' ) + continue; +#endif + + for( i = 0, entry+=0x52; i < namelen; i++, entry+=2 ) + { + int c = *(__u16 *)entry; + if(c==' '||c>=0x100) + fnbuf[i] = '_'; + else + fnbuf[i] = c; + } + fnbuf[namelen] = 0; +#ifdef DEBUG_NTFS + printf("FLAG: %d NAME: %s inum=%d\n", flag,fnbuf,path_ino[depth+1]); +#endif + + //uncntrl(fnbuf); + + chk_sfn = nsubstring(dirname,fnbuf); +#ifndef STAGE1_5 + if (print_possibilities && ch != '/' && ch != ':' + && (!*dirname || chk_sfn <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion (fnbuf); + } +#endif /* STAGE1_5 */ + } + while (chk_sfn != 0 || + (print_possibilities && ch != '/' && ch != ':')); + + *(dirname = rest) = ch; + + depth++; + + /* go back to main loop at top of function */ + goto loop; +} + +#ifdef DEBUG_NTFS +int dump_block(char *msg, char *buf, int size){ + int l = (size+15)/16; + int off; + int i, j; + int c; + printf("----- %s -----\n", msg); + for( i = 0, off = 0; i < l; i++, off+=16) + { + if(off<16) + printf("000%x:", off); + else if(off<256) + printf("00%x:", off); + else + printf("0%x:", off); + for(j=0;j<16;j++) + { + c = buf[off+j]&0xff; + if( c >= 16 ) + printf("%c%x",j==8?'-':' ',c); + else + printf("%c0%x",j==8?'-':' ',c); + } + printf(" "); + for(j=0;j<16;j++) { + char c = buf[off+j]; + printf("%c",c<' '||c>='\x7f'?'.':c); + } + printf("\n"); + } +} +#endif +#endif /* FSYS_NTFS */ diff --git a/fs/grubfs/fsys_reiserfs.c b/fs/grubfs/fsys_reiserfs.c new file mode 100644 index 0000000..52d4155 --- /dev/null +++ b/fs/grubfs/fsys_reiserfs.c @@ -0,0 +1,1219 @@ +/* fsys_reiserfs.c - an implementation for the ReiserFS filesystem */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef FSYS_REISERFS +#include "shared.h" +#include "filesys.h" + +#undef REISERDEBUG + +/* Some parts of this code (mainly the structures and defines) are + * from the original reiser fs code, as found in the linux kernel. + */ + +/* include/asm-i386/types.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; +typedef unsigned long long __u64; + +/* linux/posix_type.h */ +typedef long linux_off_t; + +#include + +/* include/linux/reiser_fs.h */ +/* This is the new super block of a journaling reiserfs system */ +struct reiserfs_super_block +{ + __u32 s_block_count; /* blocks count */ + __u32 s_free_blocks; /* free blocks count */ + __u32 s_root_block; /* root block number */ + __u32 s_journal_block; /* journal block number */ + __u32 s_journal_dev; /* journal device number */ + __u32 s_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */ + __u32 s_journal_trans_max; /* max number of blocks in a transaction. */ + __u32 s_journal_magic; /* random value made on fs creation */ + __u32 s_journal_max_batch; /* max number of blocks to batch into a trans */ + __u32 s_journal_max_commit_age; /* in seconds, how old can an async commit be */ + __u32 s_journal_max_trans_age; /* in seconds, how old can a transaction be */ + __u16 s_blocksize; /* block size */ + __u16 s_oid_maxsize; /* max size of object id array */ + __u16 s_oid_cursize; /* current size of object id array */ + __u16 s_state; /* valid or error */ + char s_magic[16]; /* reiserfs magic string indicates that file system is reiserfs */ + __u16 s_tree_height; /* height of disk tree */ + __u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ + __u16 s_version; + char s_unused[128]; /* zero filled by mkreiserfs */ +}; + +#define REISERFS_MAX_SUPPORTED_VERSION 2 +#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" +#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" + +#define MAX_HEIGHT 7 + +/* must be correct to keep the desc and commit structs at 4k */ +#define JOURNAL_TRANS_HALF 1018 + +/* first block written in a commit. */ +struct reiserfs_journal_desc { + __u32 j_trans_id; /* id of commit */ + __u32 j_len; /* length of commit. len +1 is the commit block */ + __u32 j_mount_id; /* mount id of this trans*/ + __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */ + char j_magic[12]; +}; + +/* last block written in a commit */ +struct reiserfs_journal_commit { + __u32 j_trans_id; /* must match j_trans_id from the desc block */ + __u32 j_len; /* ditto */ + __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */ + char j_digest[16]; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */ +}; + +/* this header block gets written whenever a transaction is considered + fully flushed, and is more recent than the last fully flushed + transaction. + fully flushed means all the log blocks and all the real blocks are + on disk, and this transaction does not need to be replayed. +*/ +struct reiserfs_journal_header { + /* id of last fully flushed transaction */ + __u32 j_last_flush_trans_id; + /* offset in the log of where to start replay after a crash */ + __u32 j_first_unflushed_offset; + /* mount id to detect very old transactions */ + __u32 j_mount_id; +}; + +/* magic string to find desc blocks in the journal */ +#define JOURNAL_DESC_MAGIC "ReIsErLB" + + +/* + * directories use this key as well as old files + */ +struct offset_v1 +{ + /* + * for regular files this is the offset to the first byte of the + * body, contained in the object-item, as measured from the start of + * the entire body of the object. + * + * for directory entries, k_offset consists of hash derived from + * hashing the name and using few bits (23 or more) of the resulting + * hash, and generation number that allows distinguishing names with + * hash collisions. If number of collisions overflows generation + * number, we return EEXIST. High order bit is 0 always + */ + __u32 k_offset; + __u32 k_uniqueness; +}; + +struct offset_v2 +{ + /* + * for regular files this is the offset to the first byte of the + * body, contained in the object-item, as measured from the start of + * the entire body of the object. + * + * for directory entries, k_offset consists of hash derived from + * hashing the name and using few bits (23 or more) of the resulting + * hash, and generation number that allows distinguishing names with + * hash collisions. If number of collisions overflows generation + * number, we return EEXIST. High order bit is 0 always + */ + __u64 k_offset:60; + __u64 k_type: 4; +}; + + +struct key +{ + /* packing locality: by default parent directory object id */ + __u32 k_dir_id; + /* object identifier */ + __u32 k_objectid; + /* the offset and node type (old and new form) */ + union + { + struct offset_v1 v1; + struct offset_v2 v2; + } + u; +}; + +#define KEY_SIZE (sizeof (struct key)) + +/* Header of a disk block. More precisely, header of a formatted leaf + or internal node, and not the header of an unformatted node. */ +struct block_head +{ + __u16 blk_level; /* Level of a block in the tree. */ + __u16 blk_nr_item; /* Number of keys/items in a block. */ + __u16 blk_free_space; /* Block free space in bytes. */ + struct key blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes + only) */ +}; +#define BLKH_SIZE (sizeof (struct block_head)) +#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ + +struct item_head +{ + struct key ih_key; /* Everything in the tree is found by searching for it based on its key.*/ + + union + { + __u16 ih_free_space; /* The free space in the last unformatted node of an indirect item if this + is an indirect item. This equals 0xFFFF iff this is a direct item or + stat data item. Note that the key, not this field, is used to determine + the item type, and thus which field this union contains. */ + __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory + entries in the directory item. */ + } + u; + __u16 ih_item_len; /* total size of the item body */ + __u16 ih_item_location; /* an offset to the item body within the block */ + __u16 ih_version; /* ITEM_VERSION_1 for all old items, + ITEM_VERSION_2 for new ones. + Highest bit is set by fsck + temporary, cleaned after all done */ +}; +/* size of item header */ +#define IH_SIZE (sizeof (struct item_head)) + +#define ITEM_VERSION_1 0 +#define ITEM_VERSION_2 1 +#define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \ + ? (ih)->ih_key.u.v1.k_offset \ + : (ih)->ih_key.u.v2.k_offset) + +#define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \ + ? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \ + : (ih)->ih_key.u.v2.k_type == V2_##type) + +/* FIXME these types look wrong. */ +struct disk_child +{ + unsigned long dc_block_number; /* Disk child's block number. */ + unsigned short dc_size; /* Disk child's used space. */ +}; + +#define DC_SIZE (sizeof (struct disk_child)) + +/* Stat Data on disk. + * + * Note that reiserfs has two different forms of stat data. Luckily + * the fields needed by grub are at the same position. + */ +struct stat_data +{ + __u16 sd_mode; /* file type, permissions */ + __u16 sd_notused1[3]; /* fields not needed by reiserfs */ + __u32 sd_size; /* file size */ + __u32 sd_size_hi; /* file size high 32 bits (since version 2) */ +}; + +struct reiserfs_de_head +{ + __u32 deh_offset; /* third component of the directory entry key */ + __u32 deh_dir_id; /* objectid of the parent directory of the + object, that is referenced by directory entry */ + __u32 deh_objectid;/* objectid of the object, that is referenced by + directory entry */ + __u16 deh_location;/* offset of name in the whole item */ + __u16 deh_state; /* whether 1) entry contains stat data (for + future), and 2) whether entry is hidden + (unlinked) */ +}; + +#define DEH_SIZE (sizeof (struct reiserfs_de_head)) + +#define DEH_Statdata (1 << 0) /* not used now */ +#define DEH_Visible (1 << 2) + +#define SD_OFFSET 0 +#define SD_UNIQUENESS 0 +#define DOT_OFFSET 1 +#define DOT_DOT_OFFSET 2 +#define DIRENTRY_UNIQUENESS 500 + +#define V1_TYPE_STAT_DATA 0x0 +#define V1_TYPE_DIRECT 0xffffffff +#define V1_TYPE_INDIRECT 0xfffffffe +#define V1_TYPE_DIRECTORY_MAX 0xfffffffd +#define V2_TYPE_STAT_DATA 0 +#define V2_TYPE_INDIRECT 1 +#define V2_TYPE_DIRECT 2 +#define V2_TYPE_DIRENTRY 3 + +#define REISERFS_ROOT_OBJECTID 2 +#define REISERFS_ROOT_PARENT_OBJECTID 1 +#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) +/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */ +#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) +#define REISERFS_OLD_BLOCKSIZE 4096 + +#define S_ISREG(mode) (((mode) & 0170000) == 0100000) +#define S_ISDIR(mode) (((mode) & 0170000) == 0040000) +#define S_ISLNK(mode) (((mode) & 0170000) == 0120000) + +#define PATH_MAX 1024 /* include/linux/limits.h */ +#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */ + +/* The size of the node cache */ +#define FSYSREISER_CACHE_SIZE 24*1024 +#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE +#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3 + +/* Info about currently opened file */ +struct fsys_reiser_fileinfo +{ + __u32 k_dir_id; + __u32 k_objectid; +}; + +/* In memory info about the currently mounted filesystem */ +struct fsys_reiser_info +{ + /* The last read item head */ + struct item_head *current_ih; + /* The last read item */ + char *current_item; + /* The information for the currently opened file */ + struct fsys_reiser_fileinfo fileinfo; + /* The start of the journal */ + __u32 journal_block; + /* The size of the journal */ + __u32 journal_block_count; + /* The first valid descriptor block in journal + (relative to journal_block) */ + __u32 journal_first_desc; + + /* The ReiserFS version. */ + __u16 version; + /* The current depth of the reiser tree. */ + __u16 tree_depth; + /* SECTOR_SIZE << blocksize_shift == blocksize. */ + __u8 blocksize_shift; + /* 1 << full_blocksize_shift == blocksize. */ + __u8 fullblocksize_shift; + /* The reiserfs block size (must be a power of 2) */ + __u16 blocksize; + /* The number of cached tree nodes */ + __u16 cached_slots; + /* The number of valid transactions in journal */ + __u16 journal_transactions; + + unsigned int blocks[MAX_HEIGHT]; + unsigned int next_key_nr[MAX_HEIGHT]; +}; + +/* The cached s+tree blocks in FSYS_BUF, see below + * for a more detailed description. + */ +#define ROOT ((char *)FSYS_BUF) +#define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift)) +#define LEAF CACHE (DISK_LEAF_NODE_LEVEL) + +#define BLOCKHEAD(cache) ((struct block_head *) cache) +#define ITEMHEAD ((struct item_head *) ((char *) LEAF + BLKH_SIZE)) +#define KEY(cache) ((struct key *) ((char *) cache + BLKH_SIZE)) +#define DC(cache) ((struct disk_child *) \ + ((char *) cache + BLKH_SIZE + KEY_SIZE * nr_item)) +/* The fsys_reiser_info block. + */ +#define INFO \ + ((struct fsys_reiser_info *) ((char *) FSYS_BUF + FSYSREISER_CACHE_SIZE)) +/* + * The journal cache. For each transaction it contains the number of + * blocks followed by the real block numbers of this transaction. + * + * If the block numbers of some transaction won't fit in this space, + * this list is stopped with a 0xffffffff marker and the remaining + * uncommitted transactions aren't cached. + */ +#define JOURNAL_START ((__u32 *) (INFO + 1)) +#define JOURNAL_END ((__u32 *) (FSYS_BUF + FSYS_BUFLEN)) + +static __inline__ int +is_power_of_two (unsigned long word) +{ + return (word & -word) == word; +} + +static int +journal_read (int block, int len, char *buffer) +{ + return devread ((INFO->journal_block + block) << INFO->blocksize_shift, + 0, len, buffer); +} + +/* Read a block from ReiserFS file system, taking the journal into + * account. If the block nr is in the journal, the block from the + * journal taken. + */ +static int +block_read (int blockNr, int start, int len, char *buffer) +{ + int transactions = INFO->journal_transactions; + int desc_block = INFO->journal_first_desc; + int journal_mask = INFO->journal_block_count - 1; + int translatedNr = blockNr; + __u32 *journal_table = JOURNAL_START; + while (transactions-- > 0) + { + int i = 0; + int j_len; + if (*journal_table != 0xffffffff) + { + /* Search for the blockNr in cached journal */ + j_len = *journal_table++; + while (i++ < j_len) + { + if (*journal_table++ == blockNr) + { + journal_table += j_len - i; + goto found; + } + } + } + else + { + /* This is the end of cached journal marker. The remaining + * transactions are still on disk. + */ + struct reiserfs_journal_desc desc; + struct reiserfs_journal_commit commit; + + if (! journal_read (desc_block, sizeof (desc), (char *) &desc)) + return 0; + + j_len = desc.j_len; + while (i < j_len && i < JOURNAL_TRANS_HALF) + if (desc.j_realblock[i++] == blockNr) + goto found; + + if (j_len >= JOURNAL_TRANS_HALF) + { + int commit_block = (desc_block + 1 + j_len) & journal_mask; + if (! journal_read (commit_block, + sizeof (commit), (char *) &commit)) + return 0; + while (i < j_len) + if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr) + goto found; + } + } + goto not_found; + + found: + translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask); +#ifdef REISERDEBUG + printf ("block_read: block %d is mapped to journal block %d.\n", + blockNr, translatedNr - INFO->journal_block); +#endif + /* We must continue the search, as this block may be overwritten + * in later transactions. + */ + not_found: + desc_block = (desc_block + 2 + j_len) & journal_mask; + } + return devread (translatedNr << INFO->blocksize_shift, start, len, buffer); +} + +/* Init the journal data structure. We try to cache as much as + * possible in the JOURNAL_START-JOURNAL_END space, but if it is full + * we can still read the rest from the disk on demand. + * + * The first number of valid transactions and the descriptor block of the + * first valid transaction are held in INFO. The transactions are all + * adjacent, but we must take care of the journal wrap around. + */ +static int +journal_init (void) +{ + unsigned int block_count = INFO->journal_block_count; + unsigned int desc_block; + unsigned int commit_block; + unsigned int next_trans_id; + struct reiserfs_journal_header header; + struct reiserfs_journal_desc desc; + struct reiserfs_journal_commit commit; + __u32 *journal_table = JOURNAL_START; + + journal_read (block_count, sizeof (header), (char *) &header); + desc_block = header.j_first_unflushed_offset; + if (desc_block >= block_count) + return 0; + + INFO->journal_first_desc = desc_block; + next_trans_id = header.j_last_flush_trans_id + 1; + +#ifdef REISERDEBUG + printf ("journal_init: last flushed %d\n", + header.j_last_flush_trans_id); +#endif + + while (1) + { + journal_read (desc_block, sizeof (desc), (char *) &desc); + if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0 + || desc.j_trans_id != next_trans_id + || desc.j_mount_id != header.j_mount_id) + /* no more valid transactions */ + break; + + commit_block = (desc_block + desc.j_len + 1) & (block_count - 1); + journal_read (commit_block, sizeof (commit), (char *) &commit); + if (desc.j_trans_id != commit.j_trans_id + || desc.j_len != commit.j_len) + /* no more valid transactions */ + break; + +#ifdef REISERDEBUG + printf ("Found valid transaction %d/%d at %d.\n", + desc.j_trans_id, desc.j_mount_id, desc_block); +#endif + + next_trans_id++; + if (journal_table < JOURNAL_END) + { + if ((journal_table + 1 + desc.j_len) >= JOURNAL_END) + { + /* The table is almost full; mark the end of the cached + * journal.*/ + *journal_table = 0xffffffff; + journal_table = JOURNAL_END; + } + else + { + int i; + /* Cache the length and the realblock numbers in the table. + * The block number of descriptor can easily be computed. + * and need not to be stored here. + */ + *journal_table++ = desc.j_len; + for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++) + { + *journal_table++ = desc.j_realblock[i]; +#ifdef REISERDEBUG + printf ("block %d is in journal %d.\n", + desc.j_realblock[i], desc_block); +#endif + } + for ( ; i < desc.j_len; i++) + { + *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF]; +#ifdef REISERDEBUG + printf ("block %d is in journal %d.\n", + commit.j_realblock[i-JOURNAL_TRANS_HALF], + desc_block); +#endif + } + } + } + desc_block = (commit_block + 1) & (block_count - 1); + } +#ifdef REISERDEBUG + printf ("Transaction %d/%d at %d isn't valid.\n", + desc.j_trans_id, desc.j_mount_id, desc_block); +#endif + + INFO->journal_transactions + = next_trans_id - header.j_last_flush_trans_id - 1; + return errnum == 0; +} + +/* check filesystem types and read superblock into memory buffer */ +int +reiserfs_mount (void) +{ + struct reiserfs_super_block super; + int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; + + if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) + || ! devread (superblock, 0, sizeof (struct reiserfs_super_block), + (char *) &super) + || (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 + && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) + || (/* check that this is not a copy inside the journal log */ + super.s_journal_block * super.s_blocksize + <= REISERFS_DISK_OFFSET_IN_BYTES)) + { + /* Try old super block position */ + superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; + if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) + || ! devread (superblock, 0, sizeof (struct reiserfs_super_block), + (char *) &super)) + return 0; + + if (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 + && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) + { + /* pre journaling super block ? */ + if (substring (REISERFS_SUPER_MAGIC_STRING, + (char*) ((char *) &super + 20)) > 0) + return 0; + + super.s_blocksize = REISERFS_OLD_BLOCKSIZE; + super.s_journal_block = 0; + super.s_version = 0; + } + } + + /* check the version number. */ + if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION) + return 0; + + INFO->version = super.s_version; + INFO->blocksize = super.s_blocksize; + INFO->fullblocksize_shift = log2 (super.s_blocksize); + INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS; + INFO->cached_slots = + (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1; + +#ifdef REISERDEBUG + printf ("reiserfs_mount: version=%d, blocksize=%d\n", + INFO->version, INFO->blocksize); +#endif /* REISERDEBUG */ + + /* Clear node cache. */ + memset (INFO->blocks, 0, sizeof (INFO->blocks)); + + if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE + || super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE + || (SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize) + return 0; + + /* Initialize journal code. If something fails we end with zero + * journal_transactions, so we don't access the journal at all. + */ + INFO->journal_transactions = 0; + if (super.s_journal_block != 0 && super.s_journal_dev == 0) + { + INFO->journal_block = super.s_journal_block; + INFO->journal_block_count = super.s_journal_size; + if (is_power_of_two (INFO->journal_block_count)) + journal_init (); + + /* Read in super block again, maybe it is in the journal */ + block_read (superblock >> INFO->blocksize_shift, + 0, sizeof (struct reiserfs_super_block), (char *) &super); + } + + if (! block_read (super.s_root_block, 0, INFO->blocksize, (char*) ROOT)) + return 0; + + INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level; + +#ifdef REISERDEBUG + printf ("root read_in: block=%d, depth=%d\n", + super.s_root_block, INFO->tree_depth); +#endif /* REISERDEBUG */ + + if (INFO->tree_depth >= MAX_HEIGHT) + return 0; + if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL) + { + /* There is only one node in the whole filesystem, + * which is simultanously leaf and root */ + memcpy (LEAF, ROOT, INFO->blocksize); + } + return 1; +} + +/***************** TREE ACCESSING METHODS *****************************/ + +/* I assume you are familiar with the ReiserFS tree, if not go to + * http://www.namesys.com/content_table.html + * + * My tree node cache is organized as following + * 0 ROOT node + * 1 LEAF node (if the ROOT is also a LEAF it is copied here + * 2-n other nodes on current path from bottom to top. + * if there is not enough space in the cache, the top most are + * omitted. + * + * I have only two methods to find a key in the tree: + * search_stat(dir_id, objectid) searches for the stat entry (always + * the first entry) of an object. + * next_key() gets the next key in tree order. + * + * This means, that I can only sequential reads of files are + * efficient, but this really doesn't hurt for grub. + */ + +/* Read in the node at the current path and depth into the node cache. + * You must set INFO->blocks[depth] before. + */ +static char * +read_tree_node (unsigned int blockNr, int depth) +{ + char* cache = CACHE(depth); + int num_cached = INFO->cached_slots; + if (depth < num_cached) + { + /* This is the cached part of the path. Check if same block is + * needed. + */ + if (blockNr == INFO->blocks[depth]) + return cache; + } + else + cache = CACHE(num_cached); + +#ifdef REISERDEBUG + printf (" next read_in: block=%d (depth=%d)\n", + blockNr, depth); +#endif /* REISERDEBUG */ + if (! block_read (blockNr, 0, INFO->blocksize, cache)) + return 0; + /* Make sure it has the right node level */ + if (BLOCKHEAD (cache)->blk_level != depth) + { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + + INFO->blocks[depth] = blockNr; + return cache; +} + +/* Get the next key, i.e. the key following the last retrieved key in + * tree order. INFO->current_ih and + * INFO->current_info are adapted accordingly. */ +static int +next_key (void) +{ + int depth; + struct item_head *ih = INFO->current_ih + 1; + char *cache; + +#ifdef REISERDEBUG + printf ("next_key:\n old ih: key %d:%d:%d:%d version:%d\n", + INFO->current_ih->ih_key.k_dir_id, + INFO->current_ih->ih_key.k_objectid, + INFO->current_ih->ih_key.u.v1.k_offset, + INFO->current_ih->ih_key.u.v1.k_uniqueness, + INFO->current_ih->ih_version); +#endif /* REISERDEBUG */ + + if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item]) + { + depth = DISK_LEAF_NODE_LEVEL; + /* The last item, was the last in the leaf node. + * Read in the next block + */ + do + { + if (depth == INFO->tree_depth) + { + /* There are no more keys at all. + * Return a dummy item with MAX_KEY */ + ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key; + goto found; + } + depth++; +#ifdef REISERDEBUG + printf (" depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]); +#endif /* REISERDEBUG */ + } + while (INFO->next_key_nr[depth] == 0); + + if (depth == INFO->tree_depth) + cache = ROOT; + else if (depth <= INFO->cached_slots) + cache = CACHE (depth); + else + { + cache = read_tree_node (INFO->blocks[depth], depth); + if (! cache) + return 0; + } + + do + { + int nr_item = BLOCKHEAD (cache)->blk_nr_item; + int key_nr = INFO->next_key_nr[depth]++; +#ifdef REISERDEBUG + printf (" depth=%d, i=%d/%d\n", depth, key_nr, nr_item); +#endif /* REISERDEBUG */ + if (key_nr == nr_item) + /* This is the last item in this block, set the next_key_nr to 0 */ + INFO->next_key_nr[depth] = 0; + + cache = read_tree_node (DC (cache)[key_nr].dc_block_number, --depth); + if (! cache) + return 0; + } + while (depth > DISK_LEAF_NODE_LEVEL); + + ih = ITEMHEAD; + } + found: + INFO->current_ih = ih; + INFO->current_item = &LEAF[ih->ih_item_location]; +#ifdef REISERDEBUG + printf (" new ih: key %d:%d:%d:%d version:%d\n", + INFO->current_ih->ih_key.k_dir_id, + INFO->current_ih->ih_key.k_objectid, + INFO->current_ih->ih_key.u.v1.k_offset, + INFO->current_ih->ih_key.u.v1.k_uniqueness, + INFO->current_ih->ih_version); +#endif /* REISERDEBUG */ + return 1; +} + +/* preconditions: reiserfs_mount already executed, therefore + * INFO block is valid + * returns: 0 if error (errnum is set), + * nonzero iff we were able to find the key successfully. + * postconditions: on a nonzero return, the current_ih and + * current_item fields describe the key that equals the + * searched key. INFO->next_key contains the next key after + * the searched key. + * side effects: messes around with the cache. + */ +static int +search_stat (__u32 dir_id, __u32 objectid) +{ + char *cache; + int depth; + int nr_item; + int i; + struct item_head *ih; +#ifdef REISERDEBUG + printf ("search_stat:\n key %d:%d:0:0\n", dir_id, objectid); +#endif /* REISERDEBUG */ + + depth = INFO->tree_depth; + cache = ROOT; + + while (depth > DISK_LEAF_NODE_LEVEL) + { + struct key *key; + nr_item = BLOCKHEAD (cache)->blk_nr_item; + + key = KEY (cache); + + for (i = 0; i < nr_item; i++) + { + if (key->k_dir_id > dir_id + || (key->k_dir_id == dir_id + && (key->k_objectid > objectid + || (key->k_objectid == objectid + && (key->u.v1.k_offset + | key->u.v1.k_uniqueness) > 0)))) + break; + key++; + } + +#ifdef REISERDEBUG + printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); +#endif /* REISERDEBUG */ + INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1; + cache = read_tree_node (DC (cache)[i].dc_block_number, --depth); + if (! cache) + return 0; + } + + /* cache == LEAF */ + nr_item = BLOCKHEAD (LEAF)->blk_nr_item; + ih = ITEMHEAD; + for (i = 0; i < nr_item; i++) + { + if (ih->ih_key.k_dir_id == dir_id + && ih->ih_key.k_objectid == objectid + && ih->ih_key.u.v1.k_offset == 0 + && ih->ih_key.u.v1.k_uniqueness == 0) + { +#ifdef REISERDEBUG + printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); +#endif /* REISERDEBUG */ + INFO->current_ih = ih; + INFO->current_item = &LEAF[ih->ih_item_location]; + return 1; + } + ih++; + } + errnum = ERR_FSYS_CORRUPT; + return 0; +} + +int +reiserfs_read (char *buf, int len) +{ + unsigned int blocksize; + unsigned int offset; + unsigned int to_read; + char *prev_buf = buf; + +#ifdef REISERDEBUG + printf ("reiserfs_read: filepos=%d len=%d, offset=%x:%x\n", + filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1); +#endif /* REISERDEBUG */ + + if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid + || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1) + { + search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid); + goto get_next_key; + } + + while (! errnum) + { + if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid) + break; + + offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1; + blocksize = INFO->current_ih->ih_item_len; + +#ifdef REISERDEBUG + printf (" loop: filepos=%d len=%d, offset=%d blocksize=%d\n", + filepos, len, offset, blocksize); +#endif /* REISERDEBUG */ + + if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT) + && offset < blocksize) + { +#ifdef REISERDEBUG + printf ("direct_read: offset=%d, blocksize=%d\n", + offset, blocksize); +#endif /* REISERDEBUG */ + to_read = blocksize - offset; + if (to_read > len) + to_read = len; + + if (disk_read_hook != NULL) + { + disk_read_func = disk_read_hook; + + block_read (INFO->blocks[DISK_LEAF_NODE_LEVEL], + (INFO->current_item - LEAF + offset), to_read, buf); + + disk_read_func = NULL; + } + else + memcpy (buf, INFO->current_item + offset, to_read); + goto update_buf_len; + } + else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT)) + { + blocksize = (blocksize >> 2) << INFO->fullblocksize_shift; +#ifdef REISERDEBUG + printf ("indirect_read: offset=%d, blocksize=%d\n", + offset, blocksize); +#endif /* REISERDEBUG */ + + while (offset < blocksize) + { + __u32 blocknr = ((__u32 *) INFO->current_item) + [offset >> INFO->fullblocksize_shift]; + int blk_offset = offset & (INFO->blocksize-1); + + to_read = INFO->blocksize - blk_offset; + if (to_read > len) + to_read = len; + + disk_read_func = disk_read_hook; + + /* Journal is only for meta data. Data blocks can be read + * directly without using block_read + */ + devread (blocknr << INFO->blocksize_shift, + blk_offset, to_read, buf); + + disk_read_func = NULL; + update_buf_len: + len -= to_read; + buf += to_read; + offset += to_read; + filepos += to_read; + if (len == 0) + goto done; + } + } + get_next_key: + next_key (); + } + done: + return errnum ? 0 : buf - prev_buf; +} + + +/* preconditions: reiserfs_mount already executed, therefore + * INFO block is valid + * returns: 0 if error, nonzero iff we were able to find the file successfully + * postconditions: on a nonzero return, INFO->fileinfo contains the info + * of the file we were trying to look up, filepos is 0 and filemax is + * the size of the file. + */ +int +reiserfs_dir (char *dirname) +{ + struct reiserfs_de_head *de_head; + char *rest, ch; + __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; +#ifndef STAGE1_5 + int do_possibilities = 0; +#endif /* ! STAGE1_5 */ + char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ + int link_count = 0; + int mode; + + dir_id = REISERFS_ROOT_PARENT_OBJECTID; + objectid = REISERFS_ROOT_OBJECTID; + + while (1) + { +#ifdef REISERDEBUG + printf ("dirname=%s\n", dirname); +#endif /* REISERDEBUG */ + + /* Search for the stat info first. */ + if (! search_stat (dir_id, objectid)) + return 0; + +#ifdef REISERDEBUG + printf ("sd_mode=%x sd_size=%d\n", + ((struct stat_data *) INFO->current_item)->sd_mode, + ((struct stat_data *) INFO->current_item)->sd_size); +#endif /* REISERDEBUG */ + + mode = ((struct stat_data *) INFO->current_item)->sd_mode; + + /* If we've got a symbolic link, then chase it. */ + if (S_ISLNK (mode)) + { + int len; + if (++link_count > MAX_LINK_COUNT) + { + errnum = ERR_SYMLINK_LOOP; + return 0; + } + + /* Get the symlink size. */ + filemax = ((struct stat_data *) INFO->current_item)->sd_size; + + /* Find out how long our remaining name is. */ + len = 0; + while (dirname[len] && !isspace (dirname[len])) + len++; + + if (filemax + len > sizeof (linkbuf) - 1) + { + errnum = ERR_FILELENGTH; + return 0; + } + + /* Copy the remaining name to the end of the symlink data. + Note that DIRNAME and LINKBUF may overlap! */ + grub_memmove (linkbuf + filemax, dirname, len+1); + + INFO->fileinfo.k_dir_id = dir_id; + INFO->fileinfo.k_objectid = objectid; + filepos = 0; + if (! next_key () + || reiserfs_read (linkbuf, filemax) != filemax) + { + if (! errnum) + errnum = ERR_FSYS_CORRUPT; + return 0; + } + +#ifdef REISERDEBUG + printf ("symlink=%s\n", linkbuf); +#endif /* REISERDEBUG */ + + dirname = linkbuf; + if (*dirname == '/') + { + /* It's an absolute link, so look it up in root. */ + dir_id = REISERFS_ROOT_PARENT_OBJECTID; + objectid = REISERFS_ROOT_OBJECTID; + } + else + { + /* Relative, so look it up in our parent directory. */ + dir_id = parent_dir_id; + objectid = parent_objectid; + } + + /* Now lookup the new name. */ + continue; + } + + /* if we have a real file (and we're not just printing possibilities), + then this is where we want to exit */ + + if (! *dirname || isspace (*dirname)) + { + if (! S_ISREG (mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + filepos = 0; + filemax = ((struct stat_data *) INFO->current_item)->sd_size; + + /* If this is a new stat data and size is > 4GB set filemax to + * maximum + */ + if (INFO->current_ih->ih_version == ITEM_VERSION_2 + && ((struct stat_data *) INFO->current_item)->sd_size_hi > 0) + filemax = 0xffffffff; + + INFO->fileinfo.k_dir_id = dir_id; + INFO->fileinfo.k_objectid = objectid; + return next_key (); + } + + /* continue with the file/directory name interpretation */ + while (*dirname == '/') + dirname++; + if (! S_ISDIR (mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++); + *rest = 0; + +# ifndef STAGE1_5 + if (print_possibilities && ch != '/') + do_possibilities = 1; +# endif /* ! STAGE1_5 */ + + while (1) + { + char *name_end; + int num_entries; + + if (! next_key ()) + return 0; +#ifdef REISERDEBUG + printf ("ih: key %d:%d:%d:%d version:%d\n", + INFO->current_ih->ih_key.k_dir_id, + INFO->current_ih->ih_key.k_objectid, + INFO->current_ih->ih_key.u.v1.k_offset, + INFO->current_ih->ih_key.u.v1.k_uniqueness, + INFO->current_ih->ih_version); +#endif /* REISERDEBUG */ + + if (INFO->current_ih->ih_key.k_objectid != objectid) + break; + + name_end = INFO->current_item + INFO->current_ih->ih_item_len; + de_head = (struct reiserfs_de_head *) INFO->current_item; + num_entries = INFO->current_ih->u.ih_entry_count; + while (num_entries > 0) + { + char *filename = INFO->current_item + de_head->deh_location; + char tmp = *name_end; + if ((de_head->deh_state & DEH_Visible)) + { + int cmp; + /* Directory names in ReiserFS are not null + * terminated. We write a temporary 0 behind it. + * NOTE: that this may overwrite the first block in + * the tree cache. That doesn't hurt as long as we + * don't call next_key () in between. + */ + *name_end = 0; + cmp = substring (dirname, filename); + *name_end = tmp; +# ifndef STAGE1_5 + if (do_possibilities) + { + if (cmp <= 0) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + *name_end = 0; + print_a_completion (filename); + *name_end = tmp; + } + } + else +# endif /* ! STAGE1_5 */ + if (cmp == 0) + goto found; + } + /* The beginning of this name marks the end of the next name. + */ + name_end = filename; + de_head++; + num_entries--; + } + } + +# ifndef STAGE1_5 + if (print_possibilities < 0) + return 1; +# endif /* ! STAGE1_5 */ + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; + + found: + + *rest = ch; + dirname = rest; + + parent_dir_id = dir_id; + parent_objectid = objectid; + dir_id = de_head->deh_dir_id; + objectid = de_head->deh_objectid; + } +} + +int +reiserfs_embed (int *start_sector, int needed_sectors) +{ + struct reiserfs_super_block super; + int num_sectors; + + if (! devread (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS, 0, + sizeof (struct reiserfs_super_block), (char *) &super)) + return 0; + + *start_sector = 1; /* reserve first sector for stage1 */ + if ((substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) <= 0 + || substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) <= 0) + && (/* check that this is not a super block copy inside + * the journal log */ + super.s_journal_block * super.s_blocksize + > REISERFS_DISK_OFFSET_IN_BYTES)) + num_sectors = (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1; + else + num_sectors = (REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1; + + return (needed_sectors <= num_sectors); +} +#endif /* FSYS_REISERFS */ diff --git a/fs/grubfs/fsys_ufs.c b/fs/grubfs/fsys_ufs.c new file mode 100644 index 0000000..29bef18 --- /dev/null +++ b/fs/grubfs/fsys_ufs.c @@ -0,0 +1,391 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (c) 2000, 2001 Free Software Foundation, Inc. + * Copyright (c) 2005 Rink Springer + * + * This file is based on FreeBSD 5.4-RELEASE's /sys/boot/common/ufsread.c, + * and has some minor patches so it'll work with Cromwell/GRUB. + * + */ +/*- + * Copyright (c) 2002 McAfee, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and McAfee Research,, the Security Research Division of + * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as + * part of the DARPA CHATS research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/*- + * Copyright (c) 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. + */ +#ifdef FSYS_UFS + +#include + +#include "shared.h" +#include "filesys.h" + +#include "ufs_dinode.h" +#include "ufs_fs.h" + +#ifdef __i386__ +/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase + (see sys/ufs/ffs/fs.h rev 1.39) so that i386 boot loader (boot2) can + support both UFS1 and UFS2 again. */ +#undef cgbase +#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) +#endif + +/* + * We use 4k `virtual' blocks for filesystem data, whatever the actual + * filesystem block size. FFS blocks are always a multiple of 4k. + */ +#define VBLKSHIFT 12 +#define VBLKSIZE (1 << VBLKSHIFT) +#define VBLKMASK (VBLKSIZE - 1) +#define DBPERVBLK (VBLKSIZE / DEV_BSIZE) +#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) +#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) +#define INO_TO_VBA(fs, ipervblk, x) \ + (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ + (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) +#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) +#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ + ((off) / VBLKSIZE) * DBPERVBLK) +#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) + +/* Buffers that must not span a 64k boundary. */ +struct dmadat { + char blkbuf[VBLKSIZE]; /* filesystem blocks */ + char indbuf[VBLKSIZE]; /* indir blocks */ + char sbbuf[SBLOCKSIZE]; /* superblock */ + char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ +}; +struct dmadat *dmadat = (struct dmadat*)FSYS_BUF; + +#define SUPERBLOCK ((struct fs*)dmadat->sbbuf) + +ino_t lookup(const char *); +ssize_t fsread(ino_t, void *, size_t); + +static int dsk_meta; +static uint32_t fs_off; +static ino_t cur_ino = 0; + +static inline int +dskread (void* buf, unsigned lba, unsigned nblk) +{ + return !devread (lba, 0, nblk * DEV_BSIZE, buf) ? -1 : 0; +} + +#if defined(UFS2_ONLY) +#define DIP(field) dp2.field +#elif defined(UFS1_ONLY) +#define DIP(field) dp1.field +#else +#define DIP(field) fs->fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field +#endif + +static __inline int +fsfind(const char *name, ino_t * ino) +{ + char buf[DEV_BSIZE]; + struct ufs_dirent *d; + char *s; + ssize_t n; +#ifndef UFS2_ONLY + static struct ufs1_dinode dp1; +#endif +#ifndef UFS1_ONLY + static struct ufs2_dinode dp2; +#endif + char* blkbuf = dmadat->blkbuf; + struct fs* fs = (struct fs *)dmadat->sbbuf; + + fs_off = 0; + while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) + for (s = buf; s < buf + DEV_BSIZE;) { + d = (void *)s; + if (!strcmp(name, d->d_name)) { + *ino = d->d_fileno; + + /* below is for grub, which wants the file size + */ + n = IPERVBLK(fs); + if (dskread(blkbuf, INO_TO_VBA(fs, n, (*ino)), DBPERVBLK)) + return -1; + n = INO_TO_VBO(n, (*ino)); +#if defined(UFS1_ONLY) + dp1 = ((struct ufs1_dinode *)blkbuf)[n]; +#elif defined(UFS2_ONLY) + dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#else + if (fs->fs_magic == FS_UFS1_MAGIC) + dp1 = ((struct ufs1_dinode *)blkbuf)[n]; + else + dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#endif + + filemax = DIP(di_size); + return d->d_type; + } + s += d->d_reclen; + } + return 0; +} + +ino_t +lookup(const char *path) +{ + char name[MAXNAMLEN + 1]; + const char *s; + ino_t ino; + ssize_t n; + int dt; + + ino = ROOTINO; + dt = DT_DIR; + name[0] = '/'; + name[1] = '\0'; + for (;;) { + if (*path == '/') + path++; + if (!*path) + break; + for (s = path; *s && *s != '/'; s++); + if ((n = s - path) > MAXNAMLEN) + return 0; + memcpy(name, path, n); + name[n] = 0; + if (dt != DT_DIR) { + printk("%s: not a directory.\n", name); + return (0); + } + if ((dt = fsfind(name, &ino)) <= 0) + break; + path = s; + } + return dt == DT_REG ? ino : 0; +} + +/* + * Possible superblock locations ordered from most to least likely. + */ +static int sblock_try[] = SBLOCKSEARCH; + +ssize_t +fsread(ino_t inode, void *buf, size_t nbyte) +{ +#ifndef UFS2_ONLY + static struct ufs1_dinode dp1; +#endif +#ifndef UFS1_ONLY + static struct ufs2_dinode dp2; +#endif + static ino_t inomap; + char *blkbuf; + void *indbuf; + struct fs *fs; + char *s; + size_t n, nb, size, off, vboff; + ufs_lbn_t lbn; + ufs2_daddr_t addr, vbaddr; + static ufs2_daddr_t blkmap, indmap; + unsigned int u; + + + blkbuf = dmadat->blkbuf; + indbuf = dmadat->indbuf; + fs = (struct fs *)dmadat->sbbuf; + if (!dsk_meta) { + inomap = 0; + for (n = 0; sblock_try[n] != -1; n++) { + if (dskread(fs, sblock_try[n] / DEV_BSIZE, + SBLOCKSIZE / DEV_BSIZE)) + return -1; + if (( +#if defined(UFS1_ONLY) + fs->fs_magic == FS_UFS1_MAGIC +#elif defined(UFS2_ONLY) + (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_sblockloc == sblock_try[n]) +#else + fs->fs_magic == FS_UFS1_MAGIC || + (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_sblockloc == sblock_try[n]) +#endif + ) && + fs->fs_bsize <= MAXBSIZE && + fs->fs_bsize >= sizeof(struct fs)) + break; + } + if (sblock_try[n] == -1) { + printk("Not ufs\n"); + return -1; + } + dsk_meta++; + } + if (!inode) + return 0; + if (inomap != inode) { + n = IPERVBLK(fs); + if (dskread(blkbuf, INO_TO_VBA(fs, n, inode), DBPERVBLK)) + return -1; + n = INO_TO_VBO(n, inode); +#if defined(UFS1_ONLY) + dp1 = ((struct ufs1_dinode *)blkbuf)[n]; +#elif defined(UFS2_ONLY) + dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#else + if (fs->fs_magic == FS_UFS1_MAGIC) + dp1 = ((struct ufs1_dinode *)blkbuf)[n]; + else + dp2 = ((struct ufs2_dinode *)blkbuf)[n]; +#endif + inomap = inode; + fs_off = 0; + blkmap = indmap = 0; + } + s = buf; + size = DIP(di_size); + n = size - fs_off; + if (nbyte > n) + nbyte = n; + nb = nbyte; + while (nb) { + lbn = lblkno(fs, fs_off); + off = blkoff(fs, fs_off); + if (lbn < NDADDR) { + addr = DIP(di_db[lbn]); + } else if (lbn < NDADDR + NINDIR(fs)) { + n = INDIRPERVBLK(fs); + addr = DIP(di_ib[0]); + u = (unsigned int)(lbn - NDADDR) / (n * DBPERVBLK); + vbaddr = fsbtodb(fs, addr) + u; + if (indmap != vbaddr) { + if (dskread(indbuf, vbaddr, DBPERVBLK)) + return -1; + indmap = vbaddr; + } + n = (lbn - NDADDR) & (n - 1); +#if defined(UFS1_ONLY) + addr = ((ufs1_daddr_t *)indbuf)[n]; +#elif defined(UFS2_ONLY) + addr = ((ufs2_daddr_t *)indbuf)[n]; +#else + if (fs->fs_magic == FS_UFS1_MAGIC) + addr = ((ufs1_daddr_t *)indbuf)[n]; + else + addr = ((ufs2_daddr_t *)indbuf)[n]; +#endif + } else { + return -1; + } + vbaddr = fsbtodb(fs, addr) + (off >> VBLKSHIFT) * DBPERVBLK; + vboff = off & VBLKMASK; + n = sblksize(fs, size, lbn) - (off & ~VBLKMASK); + if (n > VBLKSIZE) + n = VBLKSIZE; + if (blkmap != vbaddr) { + if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) + return -1; + blkmap = vbaddr; + } + n -= vboff; + if (n > nb) + n = nb; + memcpy(s, blkbuf + vboff, n); + s += n; + fs_off += n; + nb -= n; + } + return nbyte; +} + +int +ufs_mount (void) +{ + int i, retval = 0; + + /* + * We don't care about stuff being in disklabels or not. If the magic + * matches, we're good to go. + */ + for (i = 0; sblock_try[i] != -1; ++i) + { + if (! (part_length < (sblock_try[i] + (SBLOCKSIZE / DEV_BSIZE)) + || ! devread (0, sblock_try[i], SBLOCKSIZE, (char *) SUPERBLOCK))) + { + if ( +#if defined(UFS1_ONLY) + SUPERBLOCK->fs_magic == FS_UFS1_MAGIC +#elif defined(UFS2_ONLY) + (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC && + SUPERBLOCK->fs_sblockloc == sblock_try[i]) +#else + SUPERBLOCK->fs_magic == FS_UFS1_MAGIC || + (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC && + SUPERBLOCK->fs_sblockloc == sblock_try[i]) +#endif + ) { + retval = 1; break; + } + } + } + return retval; +} + +int +ufs_read (char *buf, int len) +{ + return fsread(cur_ino, buf, len); +} + +int +ufs_dir (char *dirname) +{ + cur_ino = lookup(dirname); + return cur_ino & 0xffffffff; +} + +int +ufs_embed (int* start_sector, int needed_sectors) +{ + /* TODO; unused by Cromwell */ + return 0; +} + +#endif /* FSYS_UFS */ diff --git a/fs/grubfs/fsys_vstafs.c b/fs/grubfs/fsys_vstafs.c new file mode 100644 index 0000000..db014b9 --- /dev/null +++ b/fs/grubfs/fsys_vstafs.c @@ -0,0 +1,254 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef FSYS_VSTAFS + +#include "shared.h" +#include "filesys.h" +#include "vstafs.h" + + +static void get_file_info (int sector); +static struct dir_entry *vstafs_readdir (long sector); +static struct dir_entry *vstafs_nextdir (void); + + +#define FIRST_SECTOR ((struct first_sector *) FSYS_BUF) +#define FILE_INFO ((struct fs_file *) (int) FIRST_SECTOR + 8192) +#define DIRECTORY_BUF ((struct dir_entry *) (int) FILE_INFO + 512) + +#define ROOT_SECTOR 1 + +/* + * In f_sector we store the sector number in which the information about + * the found file is. + */ +extern int filepos; +static int f_sector; + +int +vstafs_mount (void) +{ + int retval = 1; + + if( (((current_drive & 0x80) || (current_slice != 0)) + && current_slice != PC_SLICE_TYPE_VSTAFS) + || ! devread (0, 0, BLOCK_SIZE, (char *) FSYS_BUF) + || FIRST_SECTOR->fs_magic != 0xDEADFACE) + retval = 0; + + return retval; +} + +static void +get_file_info (int sector) +{ + devread (sector, 0, BLOCK_SIZE, (char *) FILE_INFO); +} + +static int curr_ext, current_direntry, current_blockpos; +static struct alloc *a; + +static struct dir_entry * +vstafs_readdir (long sector) +{ + /* + * Get some information from the current directory + */ + get_file_info (sector); + if (FILE_INFO->type != 2) + { + errnum = ERR_FILE_NOT_FOUND; + return 0; + } + + a = FILE_INFO->blocks; + curr_ext = 0; + devread (a[curr_ext].a_start, 0, 512, (char *) DIRECTORY_BUF); + current_direntry = 11; + current_blockpos = 0; + + return &DIRECTORY_BUF[10]; +} + +static struct dir_entry * +vstafs_nextdir (void) +{ + if (current_direntry > 15) + { + current_direntry = 0; + if (++current_blockpos > (a[curr_ext].a_len - 1)) + { + current_blockpos = 0; + curr_ext++; + } + + if (curr_ext < FILE_INFO->extents) + { + devread (a[curr_ext].a_start + current_blockpos, 0, + 512, (char *) DIRECTORY_BUF); + } + else + { + /* errnum =ERR_FILE_NOT_FOUND; */ + return 0; + } + } + + return &DIRECTORY_BUF[current_direntry++]; +} + +int +vstafs_dir (char *dirname) +{ + char *fn, ch; + struct dir_entry *d; + /* int l, i, s; */ + + /* + * Read in the entries of the current directory. + */ + f_sector = ROOT_SECTOR; + do + { + if (! (d = vstafs_readdir (f_sector))) + { + return 0; + } + + /* + * Find the file in the path + */ + while (*dirname == '/') dirname++; + fn = dirname; + while ((ch = *fn) && ch != '/' && ! isspace (ch)) fn++; + *fn = 0; + + do + { + if (d->name[0] == 0 || d->name[0] & 0x80) + continue; + +#ifndef STAGE1_5 + if (print_possibilities && ch != '/' + && (! *dirname || strcmp (dirname, d->name) <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + + printf (" %s", d->name); + } +#endif + if (! grub_strcmp (dirname, d->name)) + { + f_sector = d->start; + get_file_info (f_sector); + filemax = FILE_INFO->len; + break; + } + } + while ((d =vstafs_nextdir ())); + + *(dirname = fn) = ch; + if (! d) + { + if (print_possibilities < 0) + { +#ifndef STAGE1_5 + putchar ('\n'); +#endif + return 1; + } + + errnum = ERR_FILE_NOT_FOUND; + return 0; + } + } + while (*dirname && ! isspace (ch)); + + return 1; +} + +int +vstafs_read (char *addr, int len) +{ + struct alloc *a; + int size, ret = 0, offset, curr_len = 0; + int curr_ext; + char extent; + int ext_size; + char *curr_pos; + + get_file_info (f_sector); + size = FILE_INFO->len-VSTAFS_START_DATA; + a = FILE_INFO->blocks; + + if (filepos > 0) + { + if (filepos < a[0].a_len * 512 - VSTAFS_START_DATA) + { + offset = filepos + VSTAFS_START_DATA; + extent = 0; + curr_len = a[0].a_len * 512 - offset - filepos; + } + else + { + ext_size = a[0].a_len * 512 - VSTAFS_START_DATA; + offset = filepos - ext_size; + extent = 1; + do + { + curr_len -= ext_size; + offset -= ext_size; + ext_size = a[extent+1].a_len * 512; + } + while (extent < FILE_INFO->extents && offset>ext_size); + } + } + else + { + offset = VSTAFS_START_DATA; + extent = 0; + curr_len = a[0].a_len * 512 - offset; + } + + curr_pos = addr; + if (curr_len > len) + curr_len = len; + + for (curr_ext=extent; + curr_ext < FILE_INFO->extents; + curr_len = a[curr_ext].a_len * 512, curr_pos += curr_len, curr_ext++) + { + ret += curr_len; + size -= curr_len; + if (size < 0) + { + ret += size; + curr_len += size; + } + + devread (a[curr_ext].a_start,offset, curr_len, curr_pos); + offset = 0; + } + + return ret; +} + +#endif /* FSYS_VSTAFS */ diff --git a/fs/grubfs/fsys_xfs.c b/fs/grubfs/fsys_xfs.c new file mode 100644 index 0000000..dec1dd3 --- /dev/null +++ b/fs/grubfs/fsys_xfs.c @@ -0,0 +1,632 @@ +/* fsys_xfs.c - an implementation for the SGI XFS file system */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2001,2002 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef FSYS_XFS + +#include "shared.h" +#include "filesys.h" +#include "xfs.h" + +#define MAX_LINK_COUNT 8 + +typedef struct xad { + xfs_fileoff_t offset; + xfs_fsblock_t start; + xfs_filblks_t len; +} xad_t; + +struct xfs_info { + int bsize; + int dirbsize; + int isize; + unsigned int agblocks; + int bdlog; + int blklog; + int inopblog; + int agblklog; + int agnolog; + unsigned int nextents; + xfs_daddr_t next; + xfs_daddr_t daddr; + xfs_dablk_t forw; + xfs_dablk_t dablk; + xfs_bmbt_rec_32_t *xt; + xfs_bmbt_ptr_t ptr0; + int btnode_ptr0_off; + int i8param; + int dirpos; + int dirmax; + int blkoff; + int fpos; + xfs_ino_t rootino; +}; + +static struct xfs_info xfs; + +#define dirbuf ((char *)FSYS_BUF) +#define filebuf ((char *)FSYS_BUF + 4096) +#define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192)) +#define icore (inode->di_core) + +#define mask32lo(n) (((__uint32_t)1 << (n)) - 1) + +#define XFS_INO_MASK(k) ((__uint32_t)((1ULL << (k)) - 1)) +#define XFS_INO_OFFSET_BITS xfs.inopblog +#define XFS_INO_AGBNO_BITS xfs.agblklog +#define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog) +#define XFS_INO_AGNO_BITS xfs.agnolog + +static inline xfs_agblock_t +agino2agbno (xfs_agino_t agino) +{ + return agino >> XFS_INO_OFFSET_BITS; +} + +static inline xfs_agnumber_t +ino2agno (xfs_ino_t ino) +{ + return ino >> XFS_INO_AGINO_BITS; +} + +static inline xfs_agino_t +ino2agino (xfs_ino_t ino) +{ + return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS); +} + +static inline int +ino2offset (xfs_ino_t ino) +{ + return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS); +} + +static inline __const__ __uint16_t +le16 (__uint16_t x) +{ +#ifdef __i386__ + __asm__("xchgb %b0,%h0" \ + : "=q" (x) \ + : "0" (x)); \ + return x; +#else + return __be16_to_cpu(x); +#endif +} + +static inline __const__ __uint32_t +le32 (__uint32_t x) +{ +#ifdef __i386__ +#if 1 + /* 386 doesn't have bswap. So what. */ + __asm__("bswap %0" : "=r" (x) : "0" (x)); +#else + /* This is slower but this works on all x86 architectures. */ + __asm__("xchgb %b0, %h0" \ + "\n\troll $16, %0" \ + "\n\txchgb %b0, %h0" \ + : "=q" (x) : "0" (x)); +#endif + return x; +#else + return __be32_to_cpu(x); +#endif +} + +static inline __const__ __uint64_t +le64 (__uint64_t x) +{ + __uint32_t h = x >> 32; + __uint32_t l = x & ((1ULL<<32)-1); + return (((__uint64_t)le32(l)) << 32) | ((__uint64_t)(le32(h))); +} + + +static xfs_fsblock_t +xt_start (xfs_bmbt_rec_32_t *r) +{ + return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) | + (((xfs_fsblock_t)le32 (r->l2)) << 11) | + (((xfs_fsblock_t)le32 (r->l3)) >> 21); +} + +static xfs_fileoff_t +xt_offset (xfs_bmbt_rec_32_t *r) +{ + return (((xfs_fileoff_t)le32 (r->l0) & + mask32lo(31)) << 23) | + (((xfs_fileoff_t)le32 (r->l1)) >> 9); +} + +static xfs_filblks_t +xt_len (xfs_bmbt_rec_32_t *r) +{ + return le32(r->l3) & mask32lo(21); +} + +static inline int +xfs_highbit32(__uint32_t v) +{ + int i; + + if (--v) { + for (i = 0; i < 31; i++, v >>= 1) { + if (v == 0) + return i; + } + } + return 0; +} + +static int +isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len) +{ + return (key >= offset) ? (key < offset + len ? 1 : 0) : 0; +} + +static xfs_daddr_t +agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno) +{ + return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog; +} + +static xfs_daddr_t +fsb2daddr (xfs_fsblock_t fsbno) +{ + return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog), + (xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog))); +} + +#undef offsetof +#define offsetof(t,m) ((int)&(((t *)0)->m)) + +static inline int +btroot_maxrecs (void) +{ + int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize; + + return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) / + (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)); +} + +static int +di_read (xfs_ino_t ino) +{ + xfs_agino_t agino; + xfs_agnumber_t agno; + xfs_agblock_t agbno; + xfs_daddr_t daddr; + int offset; + + agno = ino2agno (ino); + agino = ino2agino (ino); + agbno = agino2agbno (agino); + offset = ino2offset (ino); + daddr = agb2daddr (agno, agbno); + + devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode); + + xfs.ptr0 = *(xfs_bmbt_ptr_t *) + (inode->di_u.di_c + sizeof(xfs_bmdr_block_t) + + btroot_maxrecs ()*sizeof(xfs_bmbt_key_t)); + + return 1; +} + +static void +init_extents (void) +{ + xfs_bmbt_ptr_t ptr0; + xfs_btree_lblock_t h; + + switch (icore.di_format) { + case XFS_DINODE_FMT_EXTENTS: + xfs.xt = inode->di_u.di_bmx; + xfs.nextents = le32 (icore.di_nextents); + break; + case XFS_DINODE_FMT_BTREE: + ptr0 = xfs.ptr0; + for (;;) { + xfs.daddr = fsb2daddr (le64(ptr0)); + devread (xfs.daddr, 0, + sizeof(xfs_btree_lblock_t), (char *)&h); + if (!h.bb_level) { + xfs.nextents = le16(h.bb_numrecs); + xfs.next = fsb2daddr (le64(h.bb_rightsib)); + xfs.fpos = sizeof(xfs_btree_block_t); + return; + } + devread (xfs.daddr, xfs.btnode_ptr0_off, + sizeof(xfs_bmbt_ptr_t), (char *)&ptr0); + } + } +} + +static xad_t * +next_extent (void) +{ + static xad_t xad; + + switch (icore.di_format) { + case XFS_DINODE_FMT_EXTENTS: + if (xfs.nextents == 0) + return NULL; + break; + case XFS_DINODE_FMT_BTREE: + if (xfs.nextents == 0) { + xfs_btree_lblock_t h; + if (xfs.next == 0) + return NULL; + xfs.daddr = xfs.next; + devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h); + xfs.nextents = le16(h.bb_numrecs); + xfs.next = fsb2daddr (le64(h.bb_rightsib)); + xfs.fpos = sizeof(xfs_btree_block_t); + } + /* Yeah, I know that's slow, but I really don't care */ + devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf); + xfs.xt = (xfs_bmbt_rec_32_t *)filebuf; + xfs.fpos += sizeof(xfs_bmbt_rec_32_t); + } + xad.offset = xt_offset (xfs.xt); + xad.start = xt_start (xfs.xt); + xad.len = xt_len (xfs.xt); + ++xfs.xt; + --xfs.nextents; + + return &xad; +} + +/* + * Name lies - the function reads only first 100 bytes + */ +static void +xfs_dabread (void) +{ + xad_t *xad; + xfs_fileoff_t offset;; + + init_extents (); + while ((xad = next_extent ())) { + offset = xad->offset; + if (isinxt (xfs.dablk, offset, xad->len)) { + devread (fsb2daddr (xad->start + xfs.dablk - offset), + 0, 100, dirbuf); + break; + } + } +} + +static inline xfs_ino_t +sf_ino (char *sfe, int namelen) +{ + void *p = sfe + namelen + 3; + + return (xfs.i8param == 0) + ? le64(*(xfs_ino_t *)p) : le32(*(__uint32_t *)p); +} + +static inline xfs_ino_t +sf_parent_ino (void) +{ + return (xfs.i8param == 0) + ? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent)) + : le32(*(__uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent)); +} + +static inline int +roundup8 (int n) +{ + return ((n+7)&~7); +} + +static char * +next_dentry (xfs_ino_t *ino) +{ + int namelen = 1; + int toread; + static char *usual[2] = {".", ".."}; + static xfs_dir2_sf_entry_t *sfe; + char *name = usual[0]; + + if (xfs.dirpos >= xfs.dirmax) { + if (xfs.forw == 0) + return NULL; + xfs.dablk = xfs.forw; + xfs_dabread (); +#define h ((xfs_dir2_leaf_hdr_t *)dirbuf) + xfs.dirmax = le16 (h->count) - le16 (h->stale); + xfs.forw = le32 (h->info.forw); +#undef h + xfs.dirpos = 0; + } + + switch (icore.di_format) { + case XFS_DINODE_FMT_LOCAL: + switch (xfs.dirpos) { + case -2: + *ino = 0; + break; + case -1: + *ino = sf_parent_ino (); + ++name; + ++namelen; + sfe = (xfs_dir2_sf_entry_t *) + (inode->di_u.di_c + + sizeof(xfs_dir2_sf_hdr_t) + - xfs.i8param); + break; + default: + namelen = sfe->namelen; + *ino = sf_ino ((char *)sfe, namelen); + name = sfe->name; + sfe = (xfs_dir2_sf_entry_t *) + ((char *)sfe + namelen + 11 - xfs.i8param); + } + break; + case XFS_DINODE_FMT_BTREE: + case XFS_DINODE_FMT_EXTENTS: +#define dau ((xfs_dir2_data_union_t *)dirbuf) + for (;;) { + if (xfs.blkoff >= xfs.dirbsize) { + xfs.blkoff = sizeof(xfs_dir2_data_hdr_t); + filepos &= ~(xfs.dirbsize - 1); + filepos |= xfs.blkoff; + } + xfs_read (dirbuf, 4); + xfs.blkoff += 4; + if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) { + toread = roundup8 (le16(dau->unused.length)) - 4; + xfs.blkoff += toread; + filepos += toread; + continue; + } + break; + } + xfs_read ((char *)dirbuf + 4, 5); + *ino = le64 (dau->entry.inumber); + namelen = dau->entry.namelen; +#undef dau + toread = roundup8 (namelen + 11) - 9; + xfs_read (dirbuf, toread); + name = (char *)dirbuf; + xfs.blkoff += toread + 5; + } + ++xfs.dirpos; + name[namelen] = 0; + + return name; +} + +static char * +first_dentry (xfs_ino_t *ino) +{ + xfs.forw = 0; + switch (icore.di_format) { + case XFS_DINODE_FMT_LOCAL: + xfs.dirmax = inode->di_u.di_dir2sf.hdr.count; + xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4; + xfs.dirpos = -2; + break; + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + filepos = 0; + xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t)); + if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) { +#define tail ((xfs_dir2_block_tail_t *)dirbuf) + filepos = xfs.dirbsize - sizeof(*tail); + xfs_read (dirbuf, sizeof(*tail)); + xfs.dirmax = le32 (tail->count) - le32 (tail->stale); +#undef tail + } else { + xfs.dablk = (1ULL << 35) >> xfs.blklog; +#define h ((xfs_dir2_leaf_hdr_t *)dirbuf) +#define n ((xfs_da_intnode_t *)dirbuf) + for (;;) { + xfs_dabread (); + if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC)) + || (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) { + xfs.dirmax = le16 (h->count) - le16 (h->stale); + xfs.forw = le32 (h->info.forw); + break; + } + xfs.dablk = le32 (n->btree[0].before); + } +#undef n +#undef h + } + xfs.blkoff = sizeof(xfs_dir2_data_hdr_t); + filepos = xfs.blkoff; + xfs.dirpos = 0; + } + return next_dentry (ino); +} + +int +xfs_mount (void) +{ + xfs_sb_t super; + + if (!devread (0, 0, sizeof(super), (char *)&super) + || (le32(super.sb_magicnum) != XFS_SB_MAGIC) + || ((le16(super.sb_versionnum) + & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) { + return 0; + } + + xfs.bsize = le32 (super.sb_blocksize); + xfs.blklog = super.sb_blocklog; + xfs.bdlog = xfs.blklog - SECTOR_BITS; + xfs.rootino = le64 (super.sb_rootino); + xfs.isize = le16 (super.sb_inodesize); + xfs.agblocks = le32 (super.sb_agblocks); + xfs.dirbsize = xfs.bsize << super.sb_dirblklog; + + xfs.inopblog = super.sb_inopblog; + xfs.agblklog = super.sb_agblklog; + xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount)); + + xfs.btnode_ptr0_off = + ((xfs.bsize - sizeof(xfs_btree_block_t)) / + (sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t))) + * sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t); + + return 1; +} + +int +xfs_read (char *buf, int len) +{ + xad_t *xad; + xfs_fileoff_t endofprev, endofcur, offset; + xfs_filblks_t xadlen; + int toread, startpos, endpos; + + if (icore.di_format == XFS_DINODE_FMT_LOCAL) { + grub_memmove (buf, inode->di_u.di_c + filepos, len); + filepos += len; + return len; + } + + startpos = filepos; + endpos = filepos + len; + endofprev = (xfs_fileoff_t)-1; + init_extents (); + while (len > 0 && (xad = next_extent ())) { + offset = xad->offset; + xadlen = xad->len; + if (isinxt (filepos >> xfs.blklog, offset, xadlen)) { + endofcur = (offset + xadlen) << xfs.blklog; + toread = (endofcur >= endpos) + ? len : (endofcur - filepos); + + disk_read_func = disk_read_hook; + devread (fsb2daddr (xad->start), + filepos - (offset << xfs.blklog), toread, buf); + disk_read_func = NULL; + + buf += toread; + len -= toread; + filepos += toread; + } else if (offset > endofprev) { + toread = ((offset << xfs.blklog) >= endpos) + ? len : ((offset - endofprev) << xfs.blklog); + len -= toread; + filepos += toread; + for (; toread; toread--) { + *buf++ = 0; + } + continue; + } + endofprev = offset + xadlen; + } + + return filepos - startpos; +} + +int +xfs_dir (char *dirname) +{ + xfs_ino_t ino, parent_ino, new_ino; + xfs_fsize_t di_size; + int di_mode; + int cmp, n, link_count; + char linkbuf[xfs.bsize]; + char *rest, *name, ch; + + parent_ino = ino = xfs.rootino; + link_count = 0; + for (;;) { + di_read (ino); + di_size = le64 (icore.di_size); + di_mode = le16 (icore.di_mode); + + if ((di_mode & IFMT) == IFLNK) { + if (++link_count > MAX_LINK_COUNT) { + errnum = ERR_SYMLINK_LOOP; + return 0; + } + if (di_size < xfs.bsize - 1) { + filepos = 0; + filemax = di_size; + n = xfs_read (linkbuf, filemax); + } else { + errnum = ERR_FILELENGTH; + return 0; + } + + ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino; + while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++)); + linkbuf[n] = 0; + dirname = linkbuf; + continue; + } + + if (!*dirname || isspace (*dirname)) { + if ((di_mode & IFMT) != IFREG) { + errnum = ERR_BAD_FILETYPE; + return 0; + } + filepos = 0; + filemax = di_size; + return 1; + } + + if ((di_mode & IFMT) != IFDIR) { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + for (; *dirname == '/'; dirname++); + + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); + *rest = 0; + + name = first_dentry (&new_ino); + for (;;) { + cmp = (!*dirname) ? -1 : substring (dirname, name); +#ifndef STAGE1_5 + if (print_possibilities && ch != '/' && cmp <= 0) { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion (name); + } else +#endif + if (cmp == 0) { + parent_ino = ino; + if (new_ino) + ino = new_ino; + *(dirname = rest) = ch; + break; + } + name = next_dentry (&new_ino); + if (name == NULL) { + if (print_possibilities < 0) + return 1; + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; + } + } + } +} + +#endif /* FSYS_XFS */ diff --git a/fs/grubfs/glue.h b/fs/grubfs/glue.h new file mode 100644 index 0000000..bc76db4 --- /dev/null +++ b/fs/grubfs/glue.h @@ -0,0 +1,48 @@ +#ifndef __GLUE_H +#define __GLUE_H + +#include "asm/types.h" +#include "openbios/config.h" +#include "libc/byteorder.h" + +typedef uint64_t sector_t; + +int devopen(void); + +int devread(unsigned long sector, unsigned long byte_offset, + unsigned long byte_len, void *buf); + +int file_open(const char *filename); +int file_read(void *buf, unsigned long len); +int file_seek(unsigned long offset); +unsigned long file_size(void); +void file_close(void); + +int mount_fs(void); + +extern int using_devsize; + +/* + * some of the filesystem drivers don't correctly provide their + * prototypes. we fix this here so we can leave them untouched. + */ + +int ffs_mount (void); +int ffs_read (char *buf, int len); +int ffs_dir (char *dirname); +int ffs_embed (int *start_sector, int needed_sectors); + +int vstafs_mount (void); +int vstafs_dir (char *dirname); +int vstafs_read (char *addr, int len); + +int ntfs_mount (void); +int ntfs_dir (char *dirname); +int ntfs_read (char *addr, int len); + +int affs_mount (void); +int affs_dir (char *dirname); +int affs_read (char *addr, int len); + + +#endif /* FS_H */ diff --git a/fs/grubfs/grubfs_fs.c b/fs/grubfs/grubfs_fs.c new file mode 100644 index 0000000..cc2b1d7 --- /dev/null +++ b/fs/grubfs/grubfs_fs.c @@ -0,0 +1,310 @@ +/* + * + * + * grub vfs + * + * Copyright (C) 2004 Stefan Reinauer + * Copyright (C) 2004 Samuel Rydh + * + * inspired by HFS code from Samuel Rydh + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/fs.h" +#include "filesys.h" +#include "glue.h" +#include "libc/diskio.h" + +/************************************************************************/ +/* grub GLOBALS (horrible... but difficult to fix) */ +/************************************************************************/ + +/* the grub drivers want these: */ +int filepos; +int filemax; +grub_error_t errnum; +char FSYS_BUF[FSYS_BUFLEN]; + +/* we fake this for now, assuming that the filesystem is not corrupt */ +unsigned long part_length=(unsigned long)-1; + +/* these are not even used by us, instead + * the grub fs drivers want them: + */ +int fsmax; +void (*disk_read_hook) (int, int, int); +void (*disk_read_func) (int, int, int); + + +/************************************************************************/ +/* filsystem table */ +/************************************************************************/ + +typedef struct fsys_entry { + char *name; + int (*mount_func) (void); + int (*read_func) (char *buf, int len); + int (*dir_func) (char *dirname); + void (*close_func) (void); + int (*embed_func) (int *start_sector, int needed_sectors); +} fsys_entry_t; + +struct fsys_entry fsys_table[] = { +# ifdef CONFIG_FSYS_FAT + {"fat", fat_mount, fat_read, fat_dir, 0, 0}, +# endif +# ifdef CONFIG_FSYS_EXT2FS + {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0}, +# endif +# ifdef CONFIG_FSYS_MINIX + {"minix", minix_mount, minix_read, minix_dir, 0, 0}, +# endif +# ifdef CONFIG_FSYS_REISERFS + {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, 0, reiserfs_embed}, +# endif +# ifdef CONFIG_FSYS_JFS + {"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed}, +# endif +# ifdef CONFIG_FSYS_XFS + {"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0}, +# endif +# ifdef CONFIG_FSYS_UFS + {"ufs", ufs_mount, ufs_read, ufs_dir, 0, ufs_embed}, +# endif +# ifdef CONFIG_FSYS_ISO9660 + {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0}, +# endif +# ifdef CONFIG_FSYS_NTFS + {"ntfs", ntfs_mount, ntfs_read, ntfs_dir, 0, 0}, +# endif +# ifdef CONFIG_FSYS_AFFS + {"affs", affs_mount, affs_read, affs_dir, 0, 0}, +# endif +}; + +/* We don't provide a file search mechanism (yet) */ +typedef struct { + unsigned long pos; + unsigned long len; + const char *path; + fs_ops_t *fs; +} grubfile_t; + +typedef struct { + struct fsys_entry *fsys; + grubfile_t *fd; + int dev_fd; +} grubfs_t; + +static grubfs_t dummy_fs; +static grubfs_t *curfs=&dummy_fs; + +/************************************************************************/ +/* file/fs ops */ +/************************************************************************/ + +static void +grubfs_file_close( file_desc_t *fd ) +{ + grubfile_t *gf = (grubfile_t *)fd; + + if (gf->path) + free((void *)(gf->path)); + free(fd); + filepos=0; + filemax=0; +} + +static int +grubfs_file_lseek( file_desc_t *fd, off_t offs, int whence ) +{ + grubfile_t *file = (grubfile_t*)fd; + unsigned long newpos; + + switch( whence ) { + case SEEK_CUR: + if (offs < 0 && (unsigned long) -offs > file->pos) + newpos = 0; + else + newpos = file->pos + offs; + break; + case SEEK_END: + if (offs < 0 && (unsigned long) -offs > file->len) + newpos = 0; + else + newpos = file->len + offs; + break; + default: + case SEEK_SET: + newpos = (offs < 0) ? 0 : offs; + break; + } + if (newpos > file->len) + newpos = file->len; + + file->pos = newpos; + + return newpos; +} + +static int +grubfs_file_read( file_desc_t *fd, void *buf, size_t count ) +{ + grubfile_t *file = (grubfile_t*)fd; + curfs = (grubfs_t *)file->fs->fs_data; + int ret; + + filepos=file->pos; + filemax=file->len; + + ret=curfs->fsys->read_func(buf, count); + + file->pos=filepos; + return ret; +} + +static char * +get_path( file_desc_t *fd, char *retbuf, int len ) +{ + const char *path=((grubfile_t *)fd)->path; + + if(strlen(path) > len) + return NULL; + + strcpy( retbuf, path ); + + return retbuf; +} + +static file_desc_t * +open_path( fs_ops_t *fs, const char *path ) +{ + grubfile_t *ret = NULL; + curfs = (grubfs_t *)fs->fs_data; + char *s=(char *)path; + + while(*s) { + if(*s=='\\') *s='/'; + s++; + } +#ifdef CONFIG_DEBUG_FS + printk("Path=%s\n",path); +#endif + if (!curfs->fsys->dir_func((char *) path)) { + printk("File not found\n"); + return NULL; + } + ret=malloc(sizeof(grubfile_t)); + + ret->pos=filepos; + ret->len=filemax; + ret->path=strdup(path); + ret->fs=fs; + + return (file_desc_t *)ret; +} + +static void +close_fs( fs_ops_t *fs ) +{ + free( fs->fs_data ); + fs->fs_data = NULL; + + /* callers responsibility to call free(fs) */ +} + +static char * +grubfs_get_fstype( fs_ops_t *fs ) +{ + grubfs_t *gfs = (grubfs_t*)fs->fs_data; + return gfs->fsys->name; +} + +static fs_ops_t grubfs_ops = { + .close_fs = close_fs, + .open_path = open_path, + .get_path = get_path, + .close = grubfs_file_close, + .read = grubfs_file_read, + .lseek = grubfs_file_lseek, + + .get_fstype = grubfs_get_fstype, +}; + +/* mount */ +int +fs_grubfs_open( int fd, fs_ops_t *fs ) +{ + grubfs_t *gfs; + int i; + + curfs->dev_fd = fd; + + for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) { +#ifdef CONFIG_DEBUG_FS + printk("Trying %s\n", fsys_table[i].name); +#endif + if (fsys_table[i].mount_func()) { + fsys_entry_t *fsys = &fsys_table[i]; +#ifdef CONFIG_DEBUG_FS + printk("Mounted %s\n", fsys->name); +#endif + + gfs = malloc(sizeof(*gfs)); + gfs->fsys = fsys; + gfs->dev_fd = fd; + + *fs=grubfs_ops; + fs->fs_data = (void*)gfs; + return 0; + } + } + printk("Unknown filesystem type\n"); + return -1; +} + + +/************************************************************************/ +/* I/O glue (called by grub source) */ +/************************************************************************/ + +int +devread( unsigned long sector, unsigned long byte_offset, + unsigned long byte_len, void *buf ) +{ + llong offs = (llong)sector * 512 + byte_offset; + +#ifdef CONFIG_DEBUG_FS + //printk("devread s=%x buf=%x, fd=%x\n",sector, buf, curfs->dev_fd); +#endif + + if( !curfs ) { +#ifdef CONFIG_DEBUG_FS + printk("devread: fsys == NULL!\n"); +#endif + return -1; + } + + if( seek_io(curfs->dev_fd, offs) ) { + printk("seek failure\n"); + return -1; + } + return (read_io(curfs->dev_fd, buf, byte_len) == byte_len) ? 1:0; +} + +int +file_read( void *buf, unsigned long len ) +{ + if (filepos < 0 || filepos > filemax) + filepos = filemax; + if (len < 0 || len > filemax-filepos) + len = filemax - filepos; + errnum = 0; + return curfs->fsys->read_func( buf, len ); +} diff --git a/fs/grubfs/iso9660.h b/fs/grubfs/iso9660.h new file mode 100644 index 0000000..06a7906 --- /dev/null +++ b/fs/grubfs/iso9660.h @@ -0,0 +1,168 @@ +/* + * ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader) + * including Rock Ridge Extensions support + * + * Copyright (C) 1998, 1999 Kousuke Takai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * References: + * linux/fs/isofs/rock.[ch] + * mkisofs-1.11.1/diag/isoinfo.c + * mkisofs-1.11.1/iso9660.h + * (all are written by Eric Youngdale) + */ + +/* + * Modified by SONE Takeshi to work with FILO + */ + +#ifndef _ISO9660_H_ +#define _ISO9660_H_ + +#define ISO_SECTOR_BITS (11) +#define ISO_SECTOR_SIZE (1<= file system block size >= PBSIZE >= DISIZE + */ +#define PBSIZE 512 /* physical block size (in byte) */ +#define DISIZE 512 /* on-disk inode size (in byte) */ +#define L2DISIZE 9 +#define INOSPERIAG 4096 /* number of disk inodes per iag */ +#define L2INOSPERIAG 12 +#define INOSPEREXT 32 /* number of disk inode per extent */ +#define L2INOSPEREXT 5 + +/* Minimum number of bytes supported for a JFS partition */ +#define MINJFS (0x1000000) + +/* + * fixed byte offset address + */ +#define SUPER1_OFF 0x8000 /* primary superblock */ + +#define AITBL_OFF (SUPER1_OFF + PSIZE + (PSIZE << 1)) + +/* + * fixed reserved inode number + */ +/* aggregate inode */ +#define AGGREGATE_I 1 /* aggregate inode map inode */ +#define FILESYSTEM_I 16 /* 1st/only fileset inode in ait: + * fileset inode map inode + */ + +/* per fileset inode */ +#define ROOT_I 2 /* fileset root inode */ + +/* + * directory configuration + */ +#define JFS_NAME_MAX 255 +#define JFS_PATH_MAX PSIZE + +#if 0 +typedef unsigned char u8; +typedef char s8; +typedef unsigned short u16; +typedef short s16; +typedef unsigned int u32; +typedef int s32; +typedef unsigned long long u64; +typedef long long s64; +#endif + +typedef u16 UniChar; + +/* these from jfs_btree.h */ + +/* btpaget_t flag */ +#define BT_TYPE 0x07 /* B+-tree index */ +#define BT_ROOT 0x01 /* root page */ +#define BT_LEAF 0x02 /* leaf page */ +#define BT_INTERNAL 0x04 /* internal page */ +#define BT_RIGHTMOST 0x10 /* rightmost page */ +#define BT_LEFTMOST 0x20 /* leftmost page */ + +/* those are from jfs_types.h */ + +struct timestruc_t { + u32 tv_sec; + u32 tv_nsec; +}; + +/* + * physical xd (pxd) + */ +typedef struct { + unsigned len:24; + unsigned addr1:8; + u32 addr2; +} pxd_t; + +/* xd_t field extraction */ +#define lengthPXD(pxd) ((pxd)->len) +#define addressPXD(pxd) (((s64)((pxd)->addr1)) << 32 | ((pxd)->addr2)) + +/* + * data extent descriptor (dxd) + */ +typedef struct { + unsigned flag:8; /* 1: flags */ + unsigned rsrvd:24; /* 3: */ + u32 size; /* 4: size in byte */ + unsigned len:24; /* 3: length in unit of fsblksize */ + unsigned addr1:8; /* 1: address in unit of fsblksize */ + u32 addr2; /* 4: address in unit of fsblksize */ +} dxd_t; /* - 16 - */ + +/* + * DASD limit information - stored in directory inode + */ +typedef struct dasd { + u8 thresh; /* Alert Threshold (in percent) */ + u8 delta; /* Alert Threshold delta (in percent) */ + u8 rsrvd1; + u8 limit_hi; /* DASD limit (in logical blocks) */ + u32 limit_lo; /* DASD limit (in logical blocks) */ + u8 rsrvd2[3]; + u8 used_hi; /* DASD usage (in logical blocks) */ + u32 used_lo; /* DASD usage (in logical blocks) */ +} dasd_t; + + +/* from jfs_superblock.h */ + +#define JFS_MAGIC 0x3153464A /* "JFS1" */ + +struct jfs_superblock +{ + u32 s_magic; /* 4: magic number */ + u32 s_version; /* 4: version number */ + + s64 s_size; /* 8: aggregate size in hardware/LVM blocks; + * VFS: number of blocks + */ + s32 s_bsize; /* 4: aggregate block size in bytes; + * VFS: fragment size + */ + s16 s_l2bsize; /* 2: log2 of s_bsize */ + s16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */ + s32 s_pbsize; /* 4: hardware/LVM block size in bytes */ + s16 s_l2pbsize; /* 2: log2 of s_pbsize */ + s16 pad; /* 2: padding necessary for alignment */ + + u32 s_agsize; /* 4: allocation group size in aggr. blocks */ + + u32 s_flag; /* 4: aggregate attributes: + * see jfs_filsys.h + */ + u32 s_state; /* 4: mount/unmount/recovery state: + * see jfs_filsys.h + */ + s32 s_compress; /* 4: > 0 if data compression */ + + pxd_t s_ait2; /* 8: first extent of secondary + * aggregate inode table + */ + + pxd_t s_aim2; /* 8: first extent of secondary + * aggregate inode map + */ + u32 s_logdev; /* 4: device address of log */ + s32 s_logserial; /* 4: log serial number at aggregate mount */ + pxd_t s_logpxd; /* 8: inline log extent */ + + pxd_t s_fsckpxd; /* 8: inline fsck work space extent */ + + struct timestruc_t s_time; /* 8: time last updated */ + + s32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for + * the fsck service log. + * N.B. These blocks are divided among the + * versions kept. This is not a per + * version size. + * N.B. These blocks are included in the + * length field of s_fsckpxd. + */ + s8 s_fscklog; /* 1: which fsck service log is most recent + * 0 => no service log data yet + * 1 => the first one + * 2 => the 2nd one + */ + char s_fpack[11]; /* 11: file system volume name + * N.B. This must be 11 bytes to + * conform with the OS/2 BootSector + * requirements + */ + + /* extendfs() parameter under s_state & FM_EXTENDFS */ + s64 s_xsize; /* 8: extendfs s_size */ + pxd_t s_xfsckpxd; /* 8: extendfs fsckpxd */ + pxd_t s_xlogpxd; /* 8: extendfs logpxd */ + /* - 128 byte boundary - */ + + /* + * DFS VFS support (preliminary) + */ + char s_attach; /* 1: VFS: flag: set when aggregate is attached + */ + u8 rsrvd4[7]; /* 7: reserved - set to 0 */ + + u64 totalUsable; /* 8: VFS: total of 1K blocks which are + * available to "normal" (non-root) users. + */ + u64 minFree; /* 8: VFS: # of 1K blocks held in reserve for + * exclusive use of root. This value can be 0, + * and if it is then totalUsable will be equal + * to # of blocks in aggregate. I believe this + * means that minFree + totalUsable = # blocks. + * In that case, we don't need to store both + * totalUsable and minFree since we can compute + * one from the other. I would guess minFree + * would be the one we should store, and + * totalUsable would be the one we should + * compute. (Just a guess...) + */ + + u64 realFree; /* 8: VFS: # of free 1K blocks can be used by + * "normal" users. It may be this is something + * we should compute when asked for instead of + * storing in the superblock. I don't know how + * often this information is needed. + */ + /* + * graffiti area + */ +}; + +/* from jfs_dtree.h */ + +/* + * entry segment/slot + * + * an entry consists of type dependent head/only segment/slot and + * additional segments/slots linked vi next field; + * N.B. last/only segment of entry is terminated by next = -1; + */ +/* + * directory page slot + */ +typedef struct { + s8 next; /* 1: */ + s8 cnt; /* 1: */ + UniChar name[15]; /* 30: */ +} dtslot_t; /* (32) */ + +#define DTSLOTDATALEN 15 + +/* + * internal node entry head/only segment + */ +typedef struct { + pxd_t xd; /* 8: child extent descriptor */ + + s8 next; /* 1: */ + u8 namlen; /* 1: */ + UniChar name[11]; /* 22: 2-byte aligned */ +} idtentry_t; /* (32) */ + +/* + * leaf node entry head/only segment + * + * For legacy filesystems, name contains 13 unichars -- no index field + */ +typedef struct { + u32 inumber; /* 4: 4-byte aligned */ + s8 next; /* 1: */ + u8 namlen; /* 1: */ + UniChar name[11]; /* 22: 2-byte aligned */ + u32 index; /* 4: index into dir_table */ +} ldtentry_t; /* (32) */ + +#define DTLHDRDATALEN 11 + +/* + * dir_table used for directory traversal during readdir +*/ + +/* + * Maximum entry in inline directory table + */ + +typedef struct dir_table_slot { + u8 rsrvd; /* 1: */ + u8 flag; /* 1: 0 if free */ + u8 slot; /* 1: slot within leaf page of entry */ + u8 addr1; /* 1: upper 8 bits of leaf page address */ + u32 addr2; /* 4: lower 32 bits of leaf page address -OR- + index of next entry when this entry was deleted */ +} dir_table_slot_t; /* (8) */ + +/* + * directory root page (in-line in on-disk inode): + * + * cf. dtpage_t below. + */ +typedef union { + struct { + dasd_t DASD; /* 16: DASD limit/usage info F226941 */ + + u8 flag; /* 1: */ + s8 nextindex; /* 1: next free entry in stbl */ + s8 freecnt; /* 1: free count */ + s8 freelist; /* 1: freelist header */ + + u32 idotdot; /* 4: parent inode number */ + + s8 stbl[8]; /* 8: sorted entry index table */ + } header; /* (32) */ + + dtslot_t slot[9]; +} dtroot_t; + +/* + * directory regular page: + * + * entry slot array of 32 byte slot + * + * sorted entry slot index table (stbl): + * contiguous slots at slot specified by stblindex, + * 1-byte per entry + * 512 byte block: 16 entry tbl (1 slot) + * 1024 byte block: 32 entry tbl (1 slot) + * 2048 byte block: 64 entry tbl (2 slot) + * 4096 byte block: 128 entry tbl (4 slot) + * + * data area: + * 512 byte block: 16 - 2 = 14 slot + * 1024 byte block: 32 - 2 = 30 slot + * 2048 byte block: 64 - 3 = 61 slot + * 4096 byte block: 128 - 5 = 123 slot + * + * N.B. index is 0-based; index fields refer to slot index + * except nextindex which refers to entry index in stbl; + * end of entry stot list or freelist is marked with -1. + */ +typedef union { + struct { + s64 next; /* 8: next sibling */ + s64 prev; /* 8: previous sibling */ + + u8 flag; /* 1: */ + s8 nextindex; /* 1: next entry index in stbl */ + s8 freecnt; /* 1: */ + s8 freelist; /* 1: slot index of head of freelist */ + + u8 maxslot; /* 1: number of slots in page slot[] */ + s8 stblindex; /* 1: slot index of start of stbl */ + u8 rsrvd[2]; /* 2: */ + + pxd_t self; /* 8: self pxd */ + } header; /* (32) */ + + dtslot_t slot[128]; +} dtpage_t; + +/* from jfs_xtree.h */ + +/* + * extent allocation descriptor (xad) + */ +typedef struct xad { + unsigned flag:8; /* 1: flag */ + unsigned rsvrd:16; /* 2: reserved */ + unsigned off1:8; /* 1: offset in unit of fsblksize */ + u32 off2; /* 4: offset in unit of fsblksize */ + unsigned len:24; /* 3: length in unit of fsblksize */ + unsigned addr1:8; /* 1: address in unit of fsblksize */ + u32 addr2; /* 4: address in unit of fsblksize */ +} xad_t; /* (16) */ + +/* xad_t field extraction */ +#define offsetXAD(xad) (((s64)((xad)->off1)) << 32 | ((xad)->off2)) +#define addressXAD(xad) (((s64)((xad)->addr1)) << 32 | ((xad)->addr2)) +#define lengthXAD(xad) ((xad)->len) + +/* possible values for maxentry */ +#define XTPAGEMAXSLOT 256 +#define XTENTRYSTART 2 + +/* + * xtree page: + */ +typedef union { + struct xtheader { + s64 next; /* 8: */ + s64 prev; /* 8: */ + + u8 flag; /* 1: */ + u8 rsrvd1; /* 1: */ + s16 nextindex; /* 2: next index = number of entries */ + s16 maxentry; /* 2: max number of entries */ + s16 rsrvd2; /* 2: */ + + pxd_t self; /* 8: self */ + } header; /* (32) */ + + xad_t xad[XTPAGEMAXSLOT]; /* 16 * maxentry: xad array */ +} xtpage_t; + +/* from jfs_dinode.h */ + +struct dinode { + /* + * I. base area (128 bytes) + * ------------------------ + * + * define generic/POSIX attributes + */ + u32 di_inostamp; /* 4: stamp to show inode belongs to fileset */ + s32 di_fileset; /* 4: fileset number */ + u32 di_number; /* 4: inode number, aka file serial number */ + u32 di_gen; /* 4: inode generation number */ + + pxd_t di_ixpxd; /* 8: inode extent descriptor */ + + s64 di_size; /* 8: size */ + s64 di_nblocks; /* 8: number of blocks allocated */ + + u32 di_nlink; /* 4: number of links to the object */ + + u32 di_uid; /* 4: user id of owner */ + u32 di_gid; /* 4: group id of owner */ + + u32 di_mode; /* 4: attribute, format and permission */ + + struct timestruc_t di_atime; /* 8: time last data accessed */ + struct timestruc_t di_ctime; /* 8: time last status changed */ + struct timestruc_t di_mtime; /* 8: time last data modified */ + struct timestruc_t di_otime; /* 8: time created */ + + dxd_t di_acl; /* 16: acl descriptor */ + + dxd_t di_ea; /* 16: ea descriptor */ + + s32 di_next_index; /* 4: Next available dir_table index */ + + s32 di_acltype; /* 4: Type of ACL */ + + /* + * Extension Areas. + * + * Historically, the inode was partitioned into 4 128-byte areas, + * the last 3 being defined as unions which could have multiple + * uses. The first 96 bytes had been completely unused until + * an index table was added to the directory. It is now more + * useful to describe the last 3/4 of the inode as a single + * union. We would probably be better off redesigning the + * entire structure from scratch, but we don't want to break + * commonality with OS/2's JFS at this time. + */ + union { + struct { + /* + * This table contains the information needed to + * find a directory entry from a 32-bit index. + * If the index is small enough, the table is inline, + * otherwise, an x-tree root overlays this table + */ + dir_table_slot_t _table[12]; /* 96: inline */ + + dtroot_t _dtroot; /* 288: dtree root */ + } _dir; /* (384) */ +#define di_dirtable u._dir._table +#define di_dtroot u._dir._dtroot +#define di_parent di_dtroot.header.idotdot +#define di_DASD di_dtroot.header.DASD + + struct { + union { + u8 _data[96]; /* 96: unused */ + struct { + void *_imap; /* 4: unused */ + u32 _gengen; /* 4: generator */ + } _imap; + } _u1; /* 96: */ +#define di_gengen u._file._u1._imap._gengen + + union { + xtpage_t _xtroot; + struct { + u8 unused[16]; /* 16: */ + dxd_t _dxd; /* 16: */ + union { + u32 _rdev; /* 4: */ + u8 _fastsymlink[128]; + } _u; + u8 _inlineea[128]; + } _special; + } _u2; + } _file; +#define di_xtroot u._file._u2._xtroot +#define di_dxd u._file._u2._special._dxd +#define di_btroot di_xtroot +#define di_inlinedata u._file._u2._special._u +#define di_rdev u._file._u2._special._u._rdev +#define di_fastsymlink u._file._u2._special._u._fastsymlink +#define di_inlineea u._file._u2._special._inlineea + } u; +}; + +typedef struct dinode dinode_t; + +/* di_mode */ +#define IFMT 0xF000 /* S_IFMT - mask of file type */ +#define IFDIR 0x4000 /* S_IFDIR - directory */ +#define IFREG 0x8000 /* S_IFREG - regular file */ +#define IFLNK 0xA000 /* S_IFLNK - symbolic link */ + +/* extended mode bits (on-disk inode di_mode) */ +#define INLINEEA 0x00040000 /* inline EA area free */ + +/* from jfs_imap.h */ + +#define EXTSPERIAG 128 /* number of disk inode extent per iag */ +#define SMAPSZ 4 /* number of words per summary map */ +#define MAXAG 128 /* maximum number of allocation groups */ + +/* + * inode allocation map: + * + * inode allocation map consists of + * . the inode map control page and + * . inode allocation group pages (per 4096 inodes) + * which are addressed by standard JFS xtree. + */ +/* + * inode allocation group page (per 4096 inodes of an AG) + */ +typedef struct { + s64 agstart; /* 8: starting block of ag */ + s32 iagnum; /* 4: inode allocation group number */ + s32 inofreefwd; /* 4: ag inode free list forward */ + s32 inofreeback; /* 4: ag inode free list back */ + s32 extfreefwd; /* 4: ag inode extent free list forward */ + s32 extfreeback; /* 4: ag inode extent free list back */ + s32 iagfree; /* 4: iag free list */ + + /* summary map: 1 bit per inode extent */ + s32 inosmap[SMAPSZ]; /* 16: sum map of mapwords w/ free inodes; + * note: this indicates free and backed + * inodes, if the extent is not backed the + * value will be 1. if the extent is + * backed but all inodes are being used the + * value will be 1. if the extent is + * backed but at least one of the inodes is + * free the value will be 0. + */ + s32 extsmap[SMAPSZ]; /* 16: sum map of mapwords w/ free extents */ + s32 nfreeinos; /* 4: number of free inodes */ + s32 nfreeexts; /* 4: number of free extents */ + /* (72) */ + u8 pad[1976]; /* 1976: pad to 2048 bytes */ + /* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */ + u32 wmap[EXTSPERIAG]; /* 512: working allocation map */ + u32 pmap[EXTSPERIAG]; /* 512: persistent allocation map */ + pxd_t inoext[EXTSPERIAG]; /* 1024: inode extent addresses */ +} iag_t; /* (4096) */ + +#endif /* _JFS_H_ */ diff --git a/fs/grubfs/shared.h b/fs/grubfs/shared.h new file mode 100644 index 0000000..b3034e0 --- /dev/null +++ b/fs/grubfs/shared.h @@ -0,0 +1,3 @@ +/* Sorry, nothing is shared here ;) Just for GRUB compatibility. */ + +#include "glue.h" diff --git a/fs/grubfs/ufs_dinode.h b/fs/grubfs/ufs_dinode.h new file mode 100644 index 0000000..f3f7fca --- /dev/null +++ b/fs/grubfs/ufs_dinode.h @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dinode.h 8.3 (Berkeley) 1/21/94 + * $FreeBSD: src/sys/ufs/ufs/dinode.h,v 1.13.2.1 2005/01/31 23:27:01 imp Exp $ + */ + +#ifndef _UFS_UFS_DINODE_H_ +#define _UFS_UFS_DINODE_H_ + +/* + * The root inode is the root of the filesystem. Inode 0 can't be used for + * normal purposes and historically bad blocks were linked to inode 1, thus + * the root inode is 2. (Inode 1 is no longer used for this purpose, however + * numerous dump tapes make this assumption, so we are stuck with it). + */ +#define ROOTINO ((ino_t)2) + +/* + * The Whiteout inode# is a dummy non-zero inode number which will + * never be allocated to a real file. It is used as a place holder + * in the directory entry which has been tagged as a DT_W entry. + * See the comments about ROOTINO above. + */ +#define WINO ((ino_t)1) + +/* + * The size of physical and logical block numbers and time fields in UFS. + */ +typedef int32_t ufs1_daddr_t; +typedef int64_t ufs2_daddr_t; +typedef int64_t ufs_lbn_t; +typedef int64_t ufs_time_t; + +/* File permissions. */ +#define IEXEC 0000100 /* Executable. */ +#define IWRITE 0000200 /* Writeable. */ +#define IREAD 0000400 /* Readable. */ +#define ISVTX 0001000 /* Sticky bit. */ +#define ISGID 0002000 /* Set-gid. */ +#define ISUID 0004000 /* Set-uid. */ + +/* File types. */ +#define IFMT 0170000 /* Mask of file type. */ +#define IFIFO 0010000 /* Named pipe (fifo). */ +#define IFCHR 0020000 /* Character device. */ +#define IFDIR 0040000 /* Directory file. */ +#define IFBLK 0060000 /* Block device. */ +#define IFREG 0100000 /* Regular file. */ +#define IFLNK 0120000 /* Symbolic link. */ +#define IFSOCK 0140000 /* UNIX domain socket. */ +#define IFWHT 0160000 /* Whiteout. */ + +/* + * A dinode contains all the meta-data associated with a UFS2 file. + * This structure defines the on-disk format of a dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ + +#define NXADDR 2 /* External addresses in inode. */ +#define NDADDR 12 /* Direct addresses in inode. */ +#define NIADDR 3 /* Indirect addresses in inode. */ + +struct ufs2_dinode { + uint16_t di_mode; /* 0: IFMT, permissions; see below. */ + int16_t di_nlink; /* 2: File link count. */ + uint32_t di_uid; /* 4: File owner. */ + uint32_t di_gid; /* 8: File group. */ + uint32_t di_blksize; /* 12: Inode blocksize. */ + uint64_t di_size; /* 16: File byte count. */ + uint64_t di_blocks; /* 24: Bytes actually held. */ + ufs_time_t di_atime; /* 32: Last access time. */ + ufs_time_t di_mtime; /* 40: Last modified time. */ + ufs_time_t di_ctime; /* 48: Last inode change time. */ + ufs_time_t di_birthtime; /* 56: Inode creation time. */ + int32_t di_mtimensec; /* 64: Last modified time. */ + int32_t di_atimensec; /* 68: Last access time. */ + int32_t di_ctimensec; /* 72: Last inode change time. */ + int32_t di_birthnsec; /* 76: Inode creation time. */ + int32_t di_gen; /* 80: Generation number. */ + uint32_t di_kernflags; /* 84: Kernel flags. */ + uint32_t di_flags; /* 88: Status flags (chflags). */ + int32_t di_extsize; /* 92: External attributes block. */ + ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */ + ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */ + ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */ + int64_t di_spare[3]; /* 232: Reserved; currently unused */ +}; + +/* + * The di_db fields may be overlaid with other information for + * file types that do not have associated disk storage. Block + * and character devices overlay the first data block with their + * dev_t value. Short symbolic links place their path in the + * di_db area. + */ +#define di_rdev di_db[0] + +/* + * A UFS1 dinode contains all the meta-data associated with a UFS1 file. + * This structure defines the on-disk format of a UFS1 dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ +struct ufs1_dinode { + uint16_t di_mode; /* 0: IFMT, permissions; see below. */ + int16_t di_nlink; /* 2: File link count. */ + union { + uint16_t oldids[2]; /* 4: Ffs: old user and group ids. */ + } di_u; + uint64_t di_size; /* 8: File byte count. */ + int32_t di_atime; /* 16: Last access time. */ + int32_t di_atimensec; /* 20: Last access time. */ + int32_t di_mtime; /* 24: Last modified time. */ + int32_t di_mtimensec; /* 28: Last modified time. */ + int32_t di_ctime; /* 32: Last inode change time. */ + int32_t di_ctimensec; /* 36: Last inode change time. */ + ufs1_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */ + ufs1_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */ + uint32_t di_flags; /* 100: Status flags (chflags). */ + int32_t di_blocks; /* 104: Blocks actually held. */ + int32_t di_gen; /* 108: Generation number. */ + uint32_t di_uid; /* 112: File owner. */ + uint32_t di_gid; /* 116: File group. */ + int32_t di_spare[2]; /* 120: Reserved; currently unused */ +}; +#define di_ogid di_u.oldids[1] +#define di_ouid di_u.oldids[0] + +#endif /* _UFS_UFS_DINODE_H_ */ diff --git a/fs/grubfs/ufs_fs.h b/fs/grubfs/ufs_fs.h new file mode 100644 index 0000000..bd2d9bf --- /dev/null +++ b/fs/grubfs/ufs_fs.h @@ -0,0 +1,635 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fs.h 8.13 (Berkeley) 3/21/95 + * $FreeBSD: src/sys/ufs/ffs/fs.h,v 1.43.2.3 2005/02/28 16:04:53 delphij Exp $ + */ + +#ifndef _UFS_FFS_FS_H_ +#define _UFS_FFS_FS_H_ + +/* + * Each disk drive contains some number of filesystems. + * A filesystem consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A filesystem is described by its super-block, which in turn + * describes the cylinder groups. The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss. This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For filesystem fs, the offsets of the various blocks of interest + * are given in the super block as: + * [fs->fs_sblkno] Super-block + * [fs->fs_cblkno] Cylinder group block + * [fs->fs_iblkno] Inode blocks + * [fs->fs_dblkno] Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * Depending on the architecture and the media, the superblock may + * reside in any one of four places. For tiny media where every block + * counts, it is placed at the very front of the partition. Historically, + * UFS1 placed it 8K from the front to leave room for the disk label and + * a small bootstrap. For UFS2 it got moved to 64K from the front to leave + * room for the disk label and a bigger bootstrap, and for really piggy + * systems we check at 256K from the front if the first three fail. In + * all cases the size of the superblock will be SBLOCKSIZE. All values are + * given in byte-offset form, so they do not imply a sector size. The + * SBLOCKSEARCH specifies the order in which the locations should be searched. + */ +#define SBLOCK_FLOPPY 0 +#define SBLOCK_UFS1 8192 +#define SBLOCK_UFS2 65536 +#define SBLOCK_PIGGY 262144 +#define SBLOCKSIZE 8192 +#define SBLOCKSEARCH \ + { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } + +/* + * Max number of fragments per block. This value is NOT tweakable. + */ +#define MAXFRAG 8 + +/* + * Addresses stored in inodes are capable of addressing fragments + * of `blocks'. File system blocks of at most size MAXBSIZE can + * be optionally broken into 2, 4, or 8 pieces, each of which is + * addressable; these pieces may be DEV_BSIZE, or some multiple of + * a DEV_BSIZE unit. + * + * Large files consist of exclusively large data blocks. To avoid + * undue wasted disk space, the last data block of a small file may be + * allocated as only as many fragments of a large block as are + * necessary. The filesystem format retains only a single pointer + * to such a fragment, which is a piece of a single large block that + * has been divided. The size of such a fragment is determinable from + * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. + * + * The filesystem records space availability at the fragment level; + * to determine block availability, aligned fragments are examined. + */ + +/* + * MINBSIZE is the smallest allowable block size. + * In order to insure that it is possible to create files of size + * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. + * MINBSIZE must be big enough to hold a cylinder group block, + * thus changes to (struct cg) must keep its size within MINBSIZE. + * Note that super blocks are always of size SBSIZE, + * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. + */ +#define MINBSIZE 4096 + +/* + * The path name on which the filesystem is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + */ +#define MAXMNTLEN 468 + +/* + * The volume name for this filesystem is maintained in fs_volname. + * MAXVOLLEN defines the length of the buffer allocated. + */ +#define MAXVOLLEN 32 + +/* + * There is a 128-byte region in the superblock reserved for in-core + * pointers to summary information. Originally this included an array + * of pointers to blocks of struct csum; now there are just a few + * pointers and the remaining space is padded with fs_ocsp[]. + * + * NOCSPTRS determines the size of this padding. One pointer (fs_csp) + * is taken away to point to a contiguous array of struct csum for + * all cylinder groups; a second (fs_maxcluster) points to an array + * of cluster sizes that is computed as cylinder groups are inspected, + * and the third points to an array that tracks the creation of new + * directories. A fourth pointer, fs_active, is used when creating + * snapshots; it points to a bitmap of cylinder groups for which the + * free-block bitmap has changed since the snapshot operation began. + */ +#define NOCSPTRS ((128 / sizeof(void *)) - 4) + +/* + * A summary of contiguous blocks of various sizes is maintained + * in each cylinder group. Normally this is set by the initial + * value of fs_maxcontig. To conserve space, a maximum summary size + * is set by FS_MAXCONTIG. + */ +#define FS_MAXCONTIG 16 + +/* + * MINFREE gives the minimum acceptable percentage of filesystem + * blocks which may be free. If the freelist drops below this level + * only the superuser may continue to allocate blocks. This may + * be set to 0 if no reserve of free blocks is deemed necessary, + * however throughput drops by fifty percent if the filesystem + * is run at between 95% and 100% full; thus the minimum default + * value of fs_minfree is 5%. However, to get good clustering + * performance, 10% is a better choice. hence we use 10% as our + * default value. With 10% free space, fragmentation is not a + * problem, so we choose to optimize for time. + */ +#define MINFREE 8 +#define DEFAULTOPT FS_OPTTIME + +/* + * Grigoriy Orlov has done some extensive work to fine + * tune the layout preferences for directories within a filesystem. + * His algorithm can be tuned by adjusting the following parameters + * which tell the system the average file size and the average number + * of files per directory. These defaults are well selected for typical + * filesystems, but may need to be tuned for odd cases like filesystems + * being used for squid caches or news spools. + */ +#define AVFILESIZ 16384 /* expected average file size */ +#define AFPDIR 64 /* expected number of files per directory */ + +/* + * The maximum number of snapshot nodes that can be associated + * with each filesystem. This limit affects only the number of + * snapshot files that can be recorded within the superblock so + * that they can be found when the filesystem is mounted. However, + * maintaining too many will slow the filesystem performance, so + * having this limit is a good idea. + */ +#define FSMAXSNAP 20 + +/* + * Used to identify special blocks in snapshots: + * + * BLK_NOCOPY - A block that was unallocated at the time the snapshot + * was taken, hence does not need to be copied when written. + * BLK_SNAP - A block held by another snapshot that is not needed by this + * snapshot. When the other snapshot is freed, the BLK_SNAP entries + * are converted to BLK_NOCOPY. These are needed to allow fsck to + * identify blocks that are in use by other snapshots (which are + * expunged from this snapshot). + */ +#define BLK_NOCOPY ((ufs2_daddr_t)(1)) +#define BLK_SNAP ((ufs2_daddr_t)(2)) + +/* + * Sysctl values for the fast filesystem. + */ +#define FFS_ADJ_REFCNT 1 /* adjust inode reference count */ +#define FFS_ADJ_BLKCNT 2 /* adjust inode used block count */ +#define FFS_BLK_FREE 3 /* free range of blocks in map */ +#define FFS_DIR_FREE 4 /* free specified dir inodes in map */ +#define FFS_FILE_FREE 5 /* free specified file inodes in map */ +#define FFS_SET_FLAGS 6 /* set filesystem flags */ +#define FFS_ADJ_NDIR 7 /* adjust number of directories */ +#define FFS_ADJ_NBFREE 8 /* adjust number of free blocks */ +#define FFS_ADJ_NIFREE 9 /* adjust number of free inodes */ +#define FFS_ADJ_NFFREE 10 /* adjust number of free frags */ +#define FFS_ADJ_NUMCLUSTERS 11 /* adjust number of free clusters */ +#define FFS_MAXID 12 /* number of valid ffs ids */ + +/* + * Command structure passed in to the filesystem to adjust filesystem values. + */ +#define FFS_CMD_VERSION 0x19790518 /* version ID */ +struct fsck_cmd { + int32_t version; /* version of command structure */ + int32_t handle; /* reference to filesystem to be changed */ + int64_t value; /* inode or block number to be affected */ + int64_t size; /* amount or range to be adjusted */ + int64_t spare; /* reserved for future use */ +}; + +/* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks. These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + */ +struct csum { + int32_t cs_ndir; /* number of directories */ + int32_t cs_nbfree; /* number of free blocks */ + int32_t cs_nifree; /* number of free inodes */ + int32_t cs_nffree; /* number of free frags */ +}; +struct csum_total { + int64_t cs_ndir; /* number of directories */ + int64_t cs_nbfree; /* number of free blocks */ + int64_t cs_nifree; /* number of free inodes */ + int64_t cs_nffree; /* number of free frags */ + int64_t cs_numclusters; /* number of free clusters */ + int64_t cs_spare[3]; /* future expansion */ +}; + +/* + * Super block for an FFS filesystem. + */ +struct fs { + int32_t fs_firstfield; /* historic filesystem linked list, */ + int32_t fs_unused_1; /* used for incore super blocks */ + int32_t fs_sblkno; /* offset of super-block in filesys */ + int32_t fs_cblkno; /* offset of cyl-block in filesys */ + int32_t fs_iblkno; /* offset of inode-blocks in filesys */ + int32_t fs_dblkno; /* offset of first data after cg */ + int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */ + int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */ + int32_t fs_old_time; /* last time written */ + int32_t fs_old_size; /* number of blocks in fs */ + int32_t fs_old_dsize; /* number of data blocks in fs */ + int32_t fs_ncg; /* number of cylinder groups */ + int32_t fs_bsize; /* size of basic blocks in fs */ + int32_t fs_fsize; /* size of frag blocks in fs */ + int32_t fs_frag; /* number of frags in a block in fs */ +/* these are configuration parameters */ + int32_t fs_minfree; /* minimum percentage of free blocks */ + int32_t fs_old_rotdelay; /* num of ms for optimal next block */ + int32_t fs_old_rps; /* disk revolutions per second */ +/* these fields can be computed from the others */ + int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ + int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ + int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */ + int32_t fs_fshift; /* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ + int32_t fs_maxcontig; /* max number of contiguous blks */ + int32_t fs_maxbpg; /* max number of blks per cyl group */ +/* these fields can be computed from the others */ + int32_t fs_fragshift; /* block to frag shift */ + int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int32_t fs_sbsize; /* actual size of super block */ + int32_t fs_spare1[2]; /* old fs_csmask */ + /* old fs_csshift */ + int32_t fs_nindir; /* value of NINDIR */ + int32_t fs_inopb; /* value of INOPB */ + int32_t fs_old_nspf; /* value of NSPF */ +/* yet another configuration parameter */ + int32_t fs_optim; /* optimization preference, see below */ + int32_t fs_old_npsect; /* # sectors/track including spares */ + int32_t fs_old_interleave; /* hardware sector interleave */ + int32_t fs_old_trackskew; /* sector 0 skew, per track */ + int32_t fs_id[2]; /* unique filesystem id */ +/* sizes determined by number of cylinder groups and their sizes */ + int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */ + int32_t fs_cssize; /* size of cyl grp summary area */ + int32_t fs_cgsize; /* cylinder group size */ + int32_t fs_spare2; /* old fs_ntrak */ + int32_t fs_old_nsect; /* sectors per track */ + int32_t fs_old_spc; /* sectors per cylinder */ + int32_t fs_old_ncyl; /* cylinders in filesystem */ + int32_t fs_old_cpg; /* cylinders per group */ + int32_t fs_ipg; /* inodes per group */ + int32_t fs_fpg; /* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ + struct csum fs_old_cstotal; /* cylinder summary information */ +/* these fields are cleared at mount time */ + int8_t fs_fmod; /* super block modified flag */ + int8_t fs_clean; /* filesystem is clean flag */ + int8_t fs_ronly; /* mounted read-only flag */ + int8_t fs_old_flags; /* old FS_ flags */ + char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ + char fs_volname[MAXVOLLEN]; /* volume name */ + uint64_t fs_swuid; /* system-wide uid */ + int32_t fs_pad; /* due to alignment of fs_swuid */ +/* these fields retain the current block allocation info */ + int32_t fs_cgrotor; /* last cg searched */ + void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */ + uint8_t *fs_contigdirs; /* # of contiguously allocated dirs */ + struct csum *fs_csp; /* cg summary info buffer for fs_cs */ + int32_t *fs_maxcluster; /* max cluster in each cyl group */ + unsigned int *fs_active; /* used by snapshots to track fs */ + int32_t fs_old_cpc; /* cyl per cycle in postbl */ + int32_t fs_maxbsize; /* maximum blocking factor permitted */ + int64_t fs_sparecon64[17]; /* old rotation block list head */ + int64_t fs_sblockloc; /* byte offset of standard superblock */ + struct csum_total fs_cstotal; /* cylinder summary information */ + ufs_time_t fs_time; /* last time written */ + int64_t fs_size; /* number of blocks in fs */ + int64_t fs_dsize; /* number of data blocks in fs */ + ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int64_t fs_pendingblocks; /* blocks in process of being freed */ + int32_t fs_pendinginodes; /* inodes in process of being freed */ + int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ + int32_t fs_avgfilesize; /* expected average file size */ + int32_t fs_avgfpdir; /* expected # of files per directory */ + int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */ + int32_t fs_sparecon32[26]; /* reserved for future constants */ + int32_t fs_flags; /* see FS_ flags below */ + int32_t fs_contigsumsize; /* size of cluster summary array */ + int32_t fs_maxsymlinklen; /* max length of an internal symlink */ + int32_t fs_old_inodefmt; /* format of on-disk inodes */ + uint64_t fs_maxfilesize; /* maximum representable file size */ + int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */ + int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */ + int32_t fs_state; /* validate fs_clean field */ + int32_t fs_old_postblformat; /* format of positional layout tables */ + int32_t fs_old_nrpos; /* number of rotational positions */ + int32_t fs_spare5[2]; /* old fs_postbloff */ + /* old fs_rotbloff */ + int32_t fs_magic; /* magic number */ +}; + +/* Sanity checking. */ +#ifdef CTASSERT +CTASSERT(sizeof(struct fs) == 1376); +#endif + +/* + * Filesystem identification + */ +#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast filesystem magic number */ +#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */ +#define FS_BAD_MAGIC 0x19960408 /* UFS incomplete newfs magic number */ +#define FS_OKAY 0x7c269d38 /* superblock checksum */ +#define FS_42INODEFMT -1 /* 4.2BSD inode format */ +#define FS_44INODEFMT 2 /* 4.4BSD inode format */ + +/* + * Preference for optimization. + */ +#define FS_OPTTIME 0 /* minimize allocation time */ +#define FS_OPTSPACE 1 /* minimize disk fragmentation */ + +/* + * Filesystem flags. + * + * The FS_UNCLEAN flag is set by the kernel when the filesystem was + * mounted with fs_clean set to zero. The FS_DOSOFTDEP flag indicates + * that the filesystem should be managed by the soft updates code. + * Note that the FS_NEEDSFSCK flag is set and cleared only by the + * fsck utility. It is set when background fsck finds an unexpected + * inconsistency which requires a traditional foreground fsck to be + * run. Such inconsistencies should only be found after an uncorrectable + * disk error. A foreground fsck will clear the FS_NEEDSFSCK flag when + * it has successfully cleaned up the filesystem. The kernel uses this + * flag to enforce that inconsistent filesystems be mounted read-only. + * The FS_INDEXDIRS flag when set indicates that the kernel maintains + * on-disk auxiliary indexes (such as B-trees) for speeding directory + * accesses. Kernels that do not support auxiliary indicies clear the + * flag to indicate that the indicies need to be rebuilt (by fsck) before + * they can be used. + * + * FS_ACLS indicates that ACLs are administratively enabled for the + * file system, so they should be loaded from extended attributes, + * observed for access control purposes, and be administered by object + * owners. FS_MULTILABEL indicates that the TrustedBSD MAC Framework + * should attempt to back MAC labels into extended attributes on the + * file system rather than maintain a single mount label for all + * objects. + */ +#define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ +#define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ +#define FS_NEEDSFSCK 0x04 /* filesystem needs sync fsck before mount */ +#define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */ +#define FS_ACLS 0x10 /* file system has ACLs enabled */ +#define FS_MULTILABEL 0x20 /* file system is MAC multi-label */ +#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */ + +/* + * Macros to access bits in the fs_active array. + */ +#define ACTIVECGNUM(fs, cg) ((fs)->fs_active[(cg) / (NBBY * sizeof(int))]) +#define ACTIVECGOFF(cg) (1 << ((cg) % (NBBY * sizeof(int)))) + +/* + * The size of a cylinder group is calculated by CGSIZE. The maximum size + * is limited by the fact that cylinder groups are at most one block. + * Its size is derived from the size of the maps maintained in the + * cylinder group and the (struct cg) size. + */ +#define CGSIZE(fs) \ + /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ + /* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \ + /* old boff */ (fs)->fs_old_cpg * sizeof(uint16_t) + \ + /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ + /* block map */ howmany((fs)->fs_fpg, NBBY) +\ + /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ + /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ + /* cluster map */ howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY))) + +/* + * The minimal number of cylinder groups that should be created. + */ +#define MINCYLGRPS 4 + +/* + * Convert cylinder group to base address of its global summary info. + */ +#define fs_cs(fs, indx) fs_csp[indx] + +/* + * Cylinder group block for a filesystem. + */ +#define CG_MAGIC 0x090255 +struct cg { + int32_t cg_firstfield; /* historic cyl groups linked list */ + int32_t cg_magic; /* magic number */ + int32_t cg_old_time; /* time last written */ + int32_t cg_cgx; /* we are the cgx'th cylinder group */ + int16_t cg_old_ncyl; /* number of cyl's this cg */ + int16_t cg_old_niblk; /* number of inode blocks this cg */ + int32_t cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + int32_t cg_rotor; /* position of last used block */ + int32_t cg_frotor; /* position of last used frag */ + int32_t cg_irotor; /* position of last used inode */ + int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ + int32_t cg_old_btotoff; /* (int32) block totals per cylinder */ + int32_t cg_old_boff; /* (uint16) free block positions */ + int32_t cg_iusedoff; /* (uint8) used inode map */ + int32_t cg_freeoff; /* (uint8) free block map */ + int32_t cg_nextfreeoff; /* (uint8) next available space */ + int32_t cg_clustersumoff; /* (uint32) counts of avail clusters */ + int32_t cg_clusteroff; /* (uint8) free cluster map */ + int32_t cg_nclusterblks; /* number of clusters this cg */ + int32_t cg_niblk; /* number of inode blocks this cg */ + int32_t cg_initediblk; /* last initialized inode */ + int32_t cg_sparecon32[3]; /* reserved for future use */ + ufs_time_t cg_time; /* time last written */ + int64_t cg_sparecon64[3]; /* reserved for future use */ + uint8_t cg_space[1]; /* space for cylinder group maps */ +/* actually longer */ +}; + +/* + * Macros for access to cylinder group array structures + */ +#define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) +#define cg_inosused(cgp) \ + ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_iusedoff)) +#define cg_blksfree(cgp) \ + ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_freeoff)) +#define cg_clustersfree(cgp) \ + ((uint8_t *)((uint8_t *)(cgp) + (cgp)->cg_clusteroff)) +#define cg_clustersum(cgp) \ + ((int32_t *)((uintptr_t)(cgp) + (cgp)->cg_clustersumoff)) + +/* + * Turn filesystem block numbers into disk block addresses. + * This maps filesystem blocks to device size blocks. + */ +#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb) +#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc filesystem addresses of cylinder group data structures. + */ +#define cgbase(fs, c) (((ufs2_daddr_t)(fs)->fs_fpg) * (c)) +#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ +#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ +#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ +#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ +#define cgstart(fs, c) \ + ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) : \ + (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))) + +/* + * Macros for handling inode numbers: + * inode number to filesystem block offset. + * inode number to cylinder group number. + * inode number to filesystem block address. + */ +#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) +#define ino_to_fsba(fs, x) \ + ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ + (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) +#define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) + +/* + * Give cylinder group number for a filesystem block. + * Give cylinder group block number for a filesystem block. + */ +#define dtog(fs, d) ((d) / (fs)->fs_fpg) +#define dtogd(fs, d) ((d) % (fs)->fs_fpg) + +/* + * Extract the bits for a block from a map. + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define blkmap(fs, map, loc) \ + (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \ + ((loc) & (fs)->fs_qbmask) +#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ + ((loc) & (fs)->fs_qfmask) +#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \ + (((off_t)(frag)) << (fs)->fs_fshift) +#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \ + (((off_t)(blk)) << (fs)->fs_bshift) +/* Use this only when `blk' is known to be small, e.g., < NDADDR. */ +#define smalllblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \ + ((blk) << (fs)->fs_bshift) +#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \ + ((loc) >> (fs)->fs_bshift) +#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ + ((loc) >> (fs)->fs_fshift) +#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \ + (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask) +#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \ + (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) +#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \ + ((frags) >> (fs)->fs_fragshift) +#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \ + ((blks) << (fs)->fs_fragshift) +#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \ + ((fsb) & ((fs)->fs_frag - 1)) +#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \ + ((fsb) &~ ((fs)->fs_frag - 1)) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve. + */ +#define freespace(fs, percentreserved) \ + (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ + (fs)->fs_cstotal.cs_nffree - \ + (((off_t)((fs)->fs_dsize)) * (percentreserved) / 100)) + +/* + * Determining the size of a file block in the filesystem. + */ +#define blksize(fs, ip, lbn) \ + (((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) +#define sblksize(fs, size, lbn) \ + (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (size))))) + + +/* + * Number of inodes in a secondary storage block/fragment. + */ +#define INOPB(fs) ((fs)->fs_inopb) +#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) + +/* + * Number of indirects in a filesystem block. + */ +#define NINDIR(fs) ((fs)->fs_nindir) + +extern int inside[], around[]; +extern char *fragtbl[]; + +struct ufs_dirent { + uint32_t d_fileno; /* file number of entry */ + uint16_t d_reclen; /* length of this record */ + uint8_t d_type; /* file type, see below */ + uint8_t d_namlen; /* length of string in d_name */ +#define MAXNAMLEN 255 + char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ +}; + +/* + * File types + */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +/* XXX: We hardcode BSIZE and BSIZE_SHIFT here. fsys_ffs seems to do the same, + * so we should get away with it :-) */ +#define DEV_BSIZE 512 +#define DEV_BSHIFT 9 /* 2**9 = 512 */ +#define MAXBSIZE 8192 + +typedef unsigned int ino_t; + +#endif diff --git a/fs/grubfs/vstafs.h b/fs/grubfs/vstafs.h new file mode 100644 index 0000000..cc7820c --- /dev/null +++ b/fs/grubfs/vstafs.h @@ -0,0 +1,88 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef VSTAFS_H +#define VSTAFS_H 1 + + +#define LINE 16 +#define BLOCK_SIZE 512 +#define VSTAFS_START_DATA 320 + +struct bootrecord +{ + unsigned char flag; + unsigned char s_sector; + unsigned char s_head; + unsigned char s_cylinder; + unsigned char p_type; + unsigned char e_sector; + unsigned char e_head; + unsigned char e_cylinder; + unsigned long start_lba; + unsigned long nr_sector_lba; +}; + +struct alloc +{ + unsigned long a_start; + unsigned long a_len; +}; + +struct first_sector +{ + unsigned long fs_magic; + unsigned long fs_size; + unsigned long fs_extsize; + unsigned long fs_free; + struct alloc fs_freesecs[0]; +}; + +struct prot +{ + unsigned char len; + unsigned char pdefault; + unsigned char id[7]; + unsigned char bits[7]; +}; + +struct fs_file +{ + unsigned long prev; + unsigned long rev; + unsigned long len; + unsigned short type; + unsigned short nlink; + struct prot pprot; + unsigned int owner; + unsigned int extents; + struct alloc blocks[32]; + long fs_ctime, fs_mtime; /* it is not lon but time_t */ + char pad[16]; + char data[0]; +}; + +struct dir_entry +{ + char name[28]; + unsigned long start; +}; + +#endif /* ! VSTAFS_H */ diff --git a/fs/grubfs/xfs.h b/fs/grubfs/xfs.h new file mode 100644 index 0000000..2725669 --- /dev/null +++ b/fs/grubfs/xfs.h @@ -0,0 +1,546 @@ +/* xfs.h - an extraction from xfsprogs-1.3.5/include/xfs* into one file */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _BITS_TYPES_H +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef short __int16_t; +typedef unsigned short __uint16_t; +typedef int __int32_t; +typedef unsigned int __uint32_t; +typedef long long __int64_t; +typedef unsigned long long __uint64_t; +#endif + +typedef __uint64_t xfs_ino_t; +typedef __uint32_t xfs_agino_t; +typedef __int64_t xfs_daddr_t; +typedef __int64_t xfs_off_t; +typedef __uint8_t uuid_t[16]; + + +/* those are from xfs_types.h */ + +typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ +typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ +typedef __uint32_t xfs_agnumber_t; /* allocation group number */ +typedef __int32_t xfs_extnum_t; /* # of extents in a file */ +typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ +typedef __int64_t xfs_fsize_t; /* bytes in a file */ + +typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ +typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ + +/* + * Disk based types: + */ +typedef __uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_drtbno_t; /* extent (block) in realtime area */ +typedef __uint64_t xfs_dfiloff_t; /* block number in a file */ + +typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_fileoff_t; /* block number in a file */ +typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ + + +/* those are from xfs_sb.h */ + +#define XFS_SB_MAGIC 0x58465342 /* 'XFSB'*/ +#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ +#define XFS_SB_VERSION_NUMBITS 0x000f + +typedef struct xfs_sb +{ + __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ + __uint32_t sb_blocksize; /* logical block size, bytes */ + xfs_drfsbno_t sb_dblocks; /* number of data blocks */ + xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */ + xfs_drtbno_t sb_rextents; /* number of realtime extents */ + uuid_t sb_uuid; /* file system unique id */ + xfs_dfsbno_t sb_logstart; /* starting block of log if internal */ + xfs_ino_t sb_rootino; /* root inode number */ + xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ + xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ + xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ + xfs_agblock_t sb_agblocks; /* size of an allocation group */ + xfs_agnumber_t sb_agcount; /* number of allocation groups */ + xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ + xfs_extlen_t sb_logblocks; /* number of log blocks */ + __uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ + __uint16_t sb_sectsize; /* volume sector size, bytes */ + __uint16_t sb_inodesize; /* inode size, bytes */ + __uint16_t sb_inopblock; /* inodes per block */ + char sb_fname[12]; /* file system name */ + __uint8_t sb_blocklog; /* log2 of sb_blocksize */ + __uint8_t sb_sectlog; /* log2 of sb_sectsize */ + __uint8_t sb_inodelog; /* log2 of sb_inodesize */ + __uint8_t sb_inopblog; /* log2 of sb_inopblock */ + __uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ + __uint8_t sb_rextslog; /* log2 of sb_rextents */ + __uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ + __uint8_t sb_imax_pct; /* max % of fs for inode space */ + /* statistics */ + /* + * These fields must remain contiguous. If you really + * want to change their layout, make sure you fix the + * code in xfs_trans_apply_sb_deltas(). + */ + __uint64_t sb_icount; /* allocated inodes */ + __uint64_t sb_ifree; /* free inodes */ + __uint64_t sb_fdblocks; /* free data blocks */ + __uint64_t sb_frextents; /* free realtime extents */ + /* + * End contiguous fields. + */ + xfs_ino_t sb_uquotino; /* user quota inode */ + xfs_ino_t sb_gquotino; /* group quota inode */ + __uint16_t sb_qflags; /* quota flags */ + __uint8_t sb_flags; /* misc. flags */ + __uint8_t sb_shared_vn; /* shared version number */ + xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ + __uint32_t sb_unit; /* stripe or raid unit */ + __uint32_t sb_width; /* stripe or raid width */ + __uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ + __uint8_t sb_dummy[7]; /* padding */ +} xfs_sb_t; + + +/* those are from xfs_btree.h */ + +/* + * Long form header: bmap btrees. + */ +typedef struct xfs_btree_lblock +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ + xfs_dfsbno_t bb_leftsib; /* left sibling block or NULLDFSBNO */ + xfs_dfsbno_t bb_rightsib; /* right sibling block or NULLDFSBNO */ +} xfs_btree_lblock_t; + +/* + * Combined header and structure, used by common code. + */ +typedef struct xfs_btree_hdr +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_btree_hdr_t; + +typedef struct xfs_btree_block +{ + xfs_btree_hdr_t bb_h; /* header */ + union { + struct { + xfs_agblock_t bb_leftsib; + xfs_agblock_t bb_rightsib; + } s; /* short form pointers */ + struct { + xfs_dfsbno_t bb_leftsib; + xfs_dfsbno_t bb_rightsib; + } l; /* long form pointers */ + } bb_u; /* rest */ +} xfs_btree_block_t; + +/* those are from xfs_bmap_btree.h */ + +/* + * Bmap root header, on-disk form only. + */ +typedef struct xfs_bmdr_block +{ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_bmdr_block_t; + +/* + * Bmap btree record and extent descriptor. + * For 32-bit kernels, + * l0:31 is an extent flag (value 1 indicates non-normal). + * l0:0-30 and l1:9-31 are startoff. + * l1:0-8, l2:0-31, and l3:21-31 are startblock. + * l3:0-20 are blockcount. + * For 64-bit kernels, + * l0:63 is an extent flag (value 1 indicates non-normal). + * l0:9-62 are startoff. + * l0:0-8 and l1:21-63 are startblock. + * l1:0-20 are blockcount. + */ + +#define BMBT_USE_64 1 + +typedef struct xfs_bmbt_rec_32 +{ + __uint32_t l0, l1, l2, l3; +} xfs_bmbt_rec_32_t; +typedef struct xfs_bmbt_rec_64 +{ + __uint64_t l0, l1; +} xfs_bmbt_rec_64_t; + +#if BMBT_USE_64 +typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ +typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#else /* !BMBT_USE_64 */ +typedef __uint32_t xfs_bmbt_rec_base_t; /* use this for casts */ +typedef xfs_bmbt_rec_32_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#endif /* BMBT_USE_64 */ + +/* + * Key structure for non-leaf levels of the tree. + */ +typedef struct xfs_bmbt_key +{ + xfs_dfiloff_t br_startoff; /* starting file offset */ +} xfs_bmbt_key_t, xfs_bmdr_key_t; + +typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_lblock xfs_bmbt_block_t; + + +/* those are from xfs_dir2.h */ +/* + * Directory version 2. + * There are 4 possible formats: + * shortform + * single block - data with embedded leaf at the end + * multiple data blocks, single leaf+freeindex block + * data blocks, node&leaf blocks (btree), freeindex blocks + * + * The shortform format is in xfs_dir2_sf.h. + * The single block format is in xfs_dir2_block.h. + * The data block format is in xfs_dir2_data.h. + * The leaf and freeindex block formats are in xfs_dir2_leaf.h. + * Node blocks are the same as the other version, in xfs_da_btree.h. + */ + +/* + * Byte offset in data block and shortform entry. + */ +typedef __uint16_t xfs_dir2_data_off_t; + +/* + * Byte offset in a directory. + */ +typedef xfs_off_t xfs_dir2_off_t; + +/* those are from xfs_da_btree.h */ +/*======================================================================== + * Directory Structure when greater than XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This structure is common to both leaf nodes and non-leaf nodes in the Btree. + * + * Is is used to manage a doubly linked list of all blocks at the same + * level in the Btree, and to identify which type of block this is. + */ +#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ +#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ + +typedef struct xfs_da_blkinfo { + xfs_dablk_t forw; /* previous block in list */ + xfs_dablk_t back; /* following block in list */ + __uint16_t magic; /* validity check on block */ + __uint16_t pad; /* unused */ +} xfs_da_blkinfo_t; + +/* + * This is the structure of the root and intermediate nodes in the Btree. + * The leaf nodes are defined above. + * + * Entries are not packed. + * + * Since we have duplicate keys, use a binary search but always follow + * all match in the block, not just the first match found. + */ + +typedef struct xfs_da_intnode { + struct xfs_da_node_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active entries */ + __uint16_t level; /* level above leaves (leaf == 0) */ + } hdr; + struct xfs_da_node_entry { + xfs_dahash_t hashval; /* hash value for this descendant */ + xfs_dablk_t before; /* Btree block before this key */ + } btree[1]; /* variable sized array of keys */ +} xfs_da_intnode_t; + + +/* those are from xfs_dir2_data.h */ +/* + * Directory format 2, data block structures. + */ + +/* + * Constants. + */ +#define XFS_DIR2_DATA_FREE_TAG 0xffff +#define XFS_DIR2_DATA_FD_COUNT 3 + +/* + * Structures. + */ + +/* + * Describe a free area in the data block. + * The freespace will be formatted as a xfs_dir2_data_unused_t. + */ +typedef struct xfs_dir2_data_free { + xfs_dir2_data_off_t offset; /* start of freespace */ + xfs_dir2_data_off_t length; /* length of freespace */ +} xfs_dir2_data_free_t; + +/* + * Header for the data blocks. + * Always at the beginning of a directory-sized block. + * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. + */ +typedef struct xfs_dir2_data_hdr { + __uint32_t magic; /* XFS_DIR2_DATA_MAGIC */ + /* or XFS_DIR2_BLOCK_MAGIC */ + xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; +} xfs_dir2_data_hdr_t; + +/* + * Active entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_entry { + xfs_ino_t inumber; /* inode number */ + __uint8_t namelen; /* name length */ + __uint8_t name[1]; /* name bytes, no null */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_entry_t; + +/* + * Unused entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_unused { + __uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */ + xfs_dir2_data_off_t length; /* total free length */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_unused_t; + +typedef union { + xfs_dir2_data_entry_t entry; + xfs_dir2_data_unused_t unused; +} xfs_dir2_data_union_t; + + +/* those are from xfs_dir2_leaf.h */ +/* + * Directory version 2, leaf block structures. + */ + +/* + * Leaf block header. + */ +typedef struct xfs_dir2_leaf_hdr { + xfs_da_blkinfo_t info; /* header for da routines */ + __uint16_t count; /* count of entries */ + __uint16_t stale; /* count of stale entries */ +} xfs_dir2_leaf_hdr_t; + + +/* those are from xfs_dir2_block.h */ +/* + * xfs_dir2_block.h + * Directory version 2, single block format structures + */ + +/* + * The single block format is as follows: + * xfs_dir2_data_hdr_t structure + * xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures + * xfs_dir2_leaf_entry_t structures + * xfs_dir2_block_tail_t structure + */ + +#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: for one block dirs */ + +typedef struct xfs_dir2_block_tail { + __uint32_t count; /* count of leaf entries */ + __uint32_t stale; /* count of stale lf entries */ +} xfs_dir2_block_tail_t; + + +/* those are from xfs_dir2_sf.h */ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +/* + * Inode number stored as 8 8-bit values. + */ +typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t; + +/* + * Inode number stored as 4 8-bit values. + * Works a lot of the time, when all the inode numbers in a directory + * fit in 32 bits. + */ +typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t; + +typedef union { + xfs_dir2_ino8_t i8; + xfs_dir2_ino4_t i4; +} xfs_dir2_inou_t; + +/* + * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. + * Only need 16 bits, this is the byte offset into the single block form. + */ +typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tightly as possible. The header + * and the elements must be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir2_sf_hdr { + __uint8_t count; /* count of entries */ + __uint8_t i8count; /* count of 8-byte inode #s */ + xfs_dir2_inou_t parent; /* parent dir inode number */ +} xfs_dir2_sf_hdr_t; + +typedef struct xfs_dir2_sf_entry { + __uint8_t namelen; /* actual name length */ + xfs_dir2_sf_off_t offset; /* saved offset */ + __uint8_t name[1]; /* name, variable size */ + xfs_dir2_inou_t inumber; /* inode number, var. offset */ +} xfs_dir2_sf_entry_t; + +typedef struct xfs_dir2_sf { + xfs_dir2_sf_hdr_t hdr; /* shortform header */ + xfs_dir2_sf_entry_t list[1]; /* shortform entries */ +} xfs_dir2_sf_t; + +/* those are from xfs_dinode.h */ + +#define XFS_DINODE_VERSION_1 1 +#define XFS_DINODE_VERSION_2 2 +#define XFS_DINODE_MAGIC 0x494e /* 'IN' */ + +/* + * Disk inode structure. + * This is just the header; the inode is expanded to fill a variable size + * with the last field expanding. It is split into the core and "other" + * because we only need the core part in the in-core inode. + */ +typedef struct xfs_timestamp { + __int32_t t_sec; /* timestamp seconds */ + __int32_t t_nsec; /* timestamp nanoseconds */ +} xfs_timestamp_t; + +/* + * Note: Coordinate changes to this structure with the XFS_DI_* #defines + * below and the offsets table in xfs_ialloc_log_di(). + */ +typedef struct xfs_dinode_core +{ + __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ + __uint16_t di_mode; /* mode and type of file */ + __int8_t di_version; /* inode version */ + __int8_t di_format; /* format of di_c data */ + __uint16_t di_onlink; /* old number of links to file */ + __uint32_t di_uid; /* owner's user id */ + __uint32_t di_gid; /* owner's group id */ + __uint32_t di_nlink; /* number of links to file */ + __uint16_t di_projid; /* owner's project id */ + __uint8_t di_pad[10]; /* unused, zeroed space */ + xfs_timestamp_t di_atime; /* time last accessed */ + xfs_timestamp_t di_mtime; /* time last modified */ + xfs_timestamp_t di_ctime; /* time created/inode modified */ + xfs_fsize_t di_size; /* number of bytes in file */ + xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */ + xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ + xfs_extnum_t di_nextents; /* number of extents in data fork */ + xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ + __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ + __int8_t di_aformat; /* format of attr fork's data */ + __uint32_t di_dmevmask; /* DMIG event mask */ + __uint16_t di_dmstate; /* DMIG state info */ + __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ + __uint32_t di_gen; /* generation number */ +} xfs_dinode_core_t; + +typedef struct xfs_dinode +{ + xfs_dinode_core_t di_core; + xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ + union { + xfs_bmdr_block_t di_bmbt; /* btree root block */ + xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */ + xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */ + char di_c[1]; /* local contents */ + } di_u; +} xfs_dinode_t; + +/* + * Values for di_format + */ +typedef enum xfs_dinode_fmt +{ + XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */ + XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */ + /* LNK: di_symlink */ + XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */ + XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */ + XFS_DINODE_FMT_UUID /* MNT: di_uuid */ +} xfs_dinode_fmt_t; + +/* + * File types (mode field) + */ +#define IFMT 0170000 /* type of file */ +#define IFDIR 0040000 /* directory */ +#define IFREG 0100000 /* regular */ +#define IFLNK 0120000 /* symbolic link */ diff --git a/fs/hfs/block.c b/fs/hfs/block.c new file mode 100644 index 0000000..b87990e --- /dev/null +++ b/fs/hfs/block.c @@ -0,0 +1,612 @@ +/* +* libhfs - library for reading and writing Macintosh HFS volumes +* Copyright (C) 1996-1998 Robert Leslie +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +* $Id: block.c,v 1.11 1998/11/02 22:08:52 rob Exp $ +*/ + +#include "openbios/config.h" + +#include "libhfs.h" +#include "volume.h" +#include "block.h" +#include "os.h" + +#define INUSE(b) ((b)->flags & HFS_BUCKET_INUSE) +#define DIRTY(b) ((b)->flags & HFS_BUCKET_DIRTY) + +/* + * NAME: block->init() + * DESCRIPTION: initialize a volume's block cache + */ +int b_init(hfsvol *vol) +{ + bcache *cache; + int i; + + ASSERT(vol->cache == 0); + + cache = ALLOC(bcache, 1); + if (cache == 0) + ERROR(ENOMEM, 0); + + vol->cache = cache; + + cache->vol = vol; + cache->tail = &cache->chain[HFS_CACHESZ - 1]; + + cache->hits = 0; + cache->misses = 0; + + for (i = 0; i < HFS_CACHESZ; ++i) + { + bucket *b = &cache->chain[i]; + + b->flags = 0; + b->count = 0; + + b->bnum = 0; + b->data = &cache->pool[i]; + + b->cnext = b + 1; + b->cprev = b - 1; + + b->hnext = 0; + b->hprev = 0; + } + + cache->chain[0].cprev = cache->tail; + cache->tail->cnext = &cache->chain[0]; + + for (i = 0; i < HFS_HASHSZ; ++i) + cache->hash[i] = 0; + + return 0; + +fail: + return -1; +} + +# ifdef DEBUG +/* + * NAME: block->showstats() + * DESCRIPTION: output cache hit/miss ratio + */ +void b_showstats(const bcache *cache) +{ + fprintf(stderr, "BLOCK: CACHE vol 0x%lx \"%s\" hit/miss ratio = %.3f\n", + (unsigned long) cache->vol, cache->vol->mdb.drVN, + (float) cache->hits / (float) cache->misses); +} + +/* + * NAME: block->dumpcache() + * DESCRIPTION: dump the cache tables for a volume + */ +void b_dumpcache(const bcache *cache) +{ + const bucket *b; + int i; + + fprintf(stderr, "BLOCK CACHE DUMP:\n"); + + for (i = 0, b = cache->tail->cnext; i < HFS_CACHESZ; ++i, b = b->cnext) + { + if (INUSE(b)) + { + fprintf(stderr, "\t %lu", b->bnum); + if (DIRTY(b)) + fprintf(stderr, "*"); + + fprintf(stderr, ":%u", b->count); + } + } + + fprintf(stderr, "\n"); + + fprintf(stderr, "BLOCK HASH DUMP:\n"); + + for (i = 0; i < HFS_HASHSZ; ++i) + { + int seen = 0; + + for (b = cache->hash[i]; b; b = b->hnext) + { + if (! seen) + fprintf(stderr, " %d:", i); + + if (INUSE(b)) + { + fprintf(stderr, " %lu", b->bnum); + if (DIRTY(b)) + fprintf(stderr, "*"); + + fprintf(stderr, ":%u", b->count); + } + + seen = 1; + } + + if (seen) + fprintf(stderr, "\n"); + } +} +# endif + +/* + * NAME: fillchain() + * DESCRIPTION: fill a chain of bucket buffers with a single read + */ +static +int fillchain(hfsvol *vol, bucket **bptr, unsigned int *count) +{ + bucket *blist[HFS_BLOCKBUFSZ], **start = bptr; + unsigned long bnum=-2; // XXX + unsigned int len, i; + + for (len = 0; len < HFS_BLOCKBUFSZ && + (unsigned int) (bptr - start) < *count; ++bptr) + { + if (INUSE(*bptr)) + continue; + + if (len > 0 && (*bptr)->bnum != bnum) + break; + + blist[len++] = *bptr; + bnum = (*bptr)->bnum + 1; + } + + *count = bptr - start; + + if (len == 0) + goto done; + else if (len == 1) + { + if (b_readpb(vol, vol->vstart + blist[0]->bnum, + blist[0]->data, 1) == -1) + goto fail; + } + else + { + block buffer[HFS_BLOCKBUFSZ]; + + if (b_readpb(vol, vol->vstart + blist[0]->bnum, buffer, len) == -1) + goto fail; + + for (i = 0; i < len; ++i) + memcpy(blist[i]->data, buffer[i], HFS_BLOCKSZ); + } + + for (i = 0; i < len; ++i) + { + blist[i]->flags |= HFS_BUCKET_INUSE; + blist[i]->flags &= ~HFS_BUCKET_DIRTY; + } + +done: + return 0; + +fail: + return -1; +} + + +/* + * NAME: compare() + * DESCRIPTION: comparison function for qsort of cache bucket pointers + */ +static +int compare(const bucket **b1, const bucket **b2) +{ + long diff; + + diff = (*b1)->bnum - (*b2)->bnum; + + if (diff < 0) + return -1; + else if (diff > 0) + return 1; + else + return 0; +} + +/* + * NAME: dobuckets() + * DESCRIPTION: fill or flush an array of cache buckets to a volume + */ +static +int dobuckets(hfsvol *vol, bucket **chain, unsigned int len, + int (*func)(hfsvol *, bucket **, unsigned int *)) +{ + unsigned int count, i; + int result = 0; + + qsort(chain, len, sizeof(*chain), + (int (*)(const void *, const void *)) compare); + + for (i = 0; i < len; i += count) + { + count = len - i; + if (func(vol, chain + i, &count) == -1) + result = -1; + } + + return result; +} + +# define fillbuckets(vol, chain, len) dobuckets(vol, chain, len, fillchain) + +/* + * NAME: block->finish() + * DESCRIPTION: commit and free a volume's block cache + */ +int b_finish(hfsvol *vol) +{ + int result = 0; + + if (vol->cache == 0) + goto done; + +# ifdef DEBUG + b_dumpcache(vol->cache); +# endif + + FREE(vol->cache); + vol->cache = 0; + +done: + return result; +} + +/* + * NAME: findbucket() + * DESCRIPTION: locate a bucket in the cache, and/or its hash slot + */ +static +bucket *findbucket(bcache *cache, unsigned long bnum, bucket ***hslot) +{ + bucket *b; + + *hslot = &cache->hash[bnum & (HFS_HASHSZ - 1)]; + + for (b = **hslot; b; b = b->hnext) + { + if (INUSE(b) && b->bnum == bnum) + break; + } + + return b; +} + +/* + * NAME: reuse() + * DESCRIPTION: free a bucket for reuse, flushing if necessary + */ +static +int reuse(bcache *cache, bucket *b, unsigned long bnum) +{ + bucket *chain[HFS_BLOCKBUFSZ], *bptr; + int i; + +# ifdef DEBUG + if (INUSE(b)) + fprintf(stderr, "BLOCK: CACHE reusing bucket containing " + "vol 0x%lx block %lu:%u\n", + (unsigned long) cache->vol, b->bnum, b->count); +# endif + + if (INUSE(b) && DIRTY(b)) + { + /* flush most recently unused buckets */ + + for (bptr = b, i = 0; i < HFS_BLOCKBUFSZ; ++i) + { + chain[i] = bptr; + bptr = bptr->cprev; + } + } + + b->flags &= ~HFS_BUCKET_INUSE; + b->count = 1; + b->bnum = bnum; + + return 0; +} + +/* + * NAME: cplace() + * DESCRIPTION: move a bucket to an appropriate place near head of the chain + */ +static +void cplace(bcache *cache, bucket *b) +{ + bucket *p; + + for (p = cache->tail->cnext; p->count > 1; p = p->cnext) + --p->count; + + b->cnext->cprev = b->cprev; + b->cprev->cnext = b->cnext; + + if (cache->tail == b) + cache->tail = b->cprev; + + b->cprev = p->cprev; + b->cnext = p; + + p->cprev->cnext = b; + p->cprev = b; +} + +/* + * NAME: hplace() + * DESCRIPTION: move a bucket to the head of its hash slot + */ +static +void hplace(bucket **hslot, bucket *b) +{ + if (*hslot != b) + { + if (b->hprev) + *b->hprev = b->hnext; + if (b->hnext) + b->hnext->hprev = b->hprev; + + b->hprev = hslot; + b->hnext = *hslot; + + if (*hslot) + (*hslot)->hprev = &b->hnext; + + *hslot = b; + } +} + +/* + * NAME: getbucket() + * DESCRIPTION: fetch a bucket from the cache, or an empty one to be filled + */ +static +bucket *getbucket(bcache *cache, unsigned long bnum, int fill) +{ + bucket **hslot, *b, *p, *bptr, + *chain[HFS_BLOCKBUFSZ], **slots[HFS_BLOCKBUFSZ]; + + b = findbucket(cache, bnum, &hslot); + + if (b) + { + /* cache hit; move towards head of cache chain */ + + ++cache->hits; + + if (++b->count > b->cprev->count && + b != cache->tail->cnext) + { + p = b->cprev; + + p->cprev->cnext = b; + b->cnext->cprev = p; + + p->cnext = b->cnext; + b->cprev = p->cprev; + + p->cprev = b; + b->cnext = p; + + if (cache->tail == b) + cache->tail = p; + } + } + else + { + /* cache miss; reuse least-used cache bucket */ + + ++cache->misses; + + b = cache->tail; + + if (reuse(cache, b, bnum) == -1) + goto fail; + + if (fill) + { + unsigned int len = 0; + + chain[len] = b; + slots[len++] = hslot; + + for (bptr = b->cprev; + len < (HFS_BLOCKBUFSZ >> 1) && ++bnum < cache->vol->vlen; + bptr = bptr->cprev) + { + if (findbucket(cache, bnum, &hslot)) + break; + + if (reuse(cache, bptr, bnum) == -1) + goto fail; + + chain[len] = bptr; + slots[len++] = hslot; + } + + if (fillbuckets(cache->vol, chain, len) == -1) + goto fail; + + while (--len) + { + cplace(cache, chain[len]); + hplace(slots[len], chain[len]); + } + + hslot = slots[0]; + } + + /* move bucket to appropriate place in chain */ + + cplace(cache, b); + } + + /* insert at front of hash chain */ + + hplace(hslot, b); + + return b; + +fail: + return 0; +} + +/* + * NAME: block->readpb() + * DESCRIPTION: read blocks from the physical medium (bypassing cache) + */ +int b_readpb(hfsvol *vol, unsigned long bnum, block *bp, unsigned int blen) +{ + unsigned long nblocks; + +# ifdef DEBUG + fprintf(stderr, "BLOCK: READ vol 0x%lx block %lu", + (unsigned long) vol, bnum); + if (blen > 1) + fprintf(stderr, "+%u[..%lu]\n", blen - 1, bnum + blen - 1); + else + fprintf(stderr, "\n"); +# endif + + nblocks = os_seek(vol->os_fd, bnum, HFS_BLOCKSZ_BITS ); + if (nblocks == (unsigned long) -1) + goto fail; + + if (nblocks != bnum) + ERROR(EIO, "block seek failed for read"); + + nblocks = os_read(vol->os_fd, bp, blen, HFS_BLOCKSZ_BITS); + if (nblocks == (unsigned long) -1) + goto fail; + + if (nblocks != blen) + ERROR(EIO, "incomplete block read"); + + return 0; + +fail: + return -1; +} + + +/* + * NAME: block->readlb() + * DESCRIPTION: read a logical block from a volume (or from the cache) + */ +int b_readlb(hfsvol *vol, unsigned long bnum, block *bp) +{ + if (vol->vlen > 0 && bnum >= vol->vlen) + ERROR(EIO, "read nonexistent logical block"); + + if (vol->cache) + { + bucket *b; + + b = getbucket(vol->cache, bnum, 1); + if (b == 0) + goto fail; + + memcpy(bp, b->data, HFS_BLOCKSZ); + } + else + { + if (b_readpb(vol, vol->vstart + bnum, bp, 1) == -1) + goto fail; + } + + return 0; + +fail: + return -1; +} + +/* + * NAME: block->readab() + * DESCRIPTION: read a block from an allocation block from a volume + */ +int b_readab(hfsvol *vol, unsigned int anum, unsigned int index, block *bp) +{ + /* verify the allocation block exists and is marked as in-use */ + + if (anum >= vol->mdb.drNmAlBlks) + ERROR(EIO, "read nonexistent allocation block"); + else if (vol->vbm && ! BMTST(vol->vbm, anum)) + ERROR(EIO, "read unallocated block"); + + return b_readlb(vol, vol->mdb.drAlBlSt + anum * vol->lpa + index, bp); + +fail: + return -1; +} + + +/* + * NAME: block->size() + * DESCRIPTION: return the number of physical blocks on a volume's medium + */ +unsigned long b_size(hfsvol *vol) +{ + unsigned long low, high, mid; + block b; + + high = os_seek(vol->os_fd, -1, HFS_BLOCKSZ_BITS); + + if (high != (unsigned long) -1 && high > 0) + return high; + + /* manual size detection: first check there is at least 1 block in medium */ + + if (b_readpb(vol, 0, &b, 1) == -1) + ERROR(EIO, "size of medium indeterminable or empty"); + + for (low = 0, high = 2880; + high > 0 && b_readpb(vol, high - 1, &b, 1) != -1; + high <<= 1) + low = high - 1; + + if (high == 0) + ERROR(EIO, "size of medium indeterminable or too large"); + + /* common case: 1440K floppy */ + + if (low == 2879 && b_readpb(vol, 2880, &b, 1) == -1) + return 2880; + + /* binary search for other sizes */ + + while (low < high - 1) + { + mid = (low + high) >> 1; + + if (b_readpb(vol, mid, &b, 1) == -1) + high = mid; + else + low = mid; + } + + return low + 1; + +fail: + return 0; +} diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c new file mode 100644 index 0000000..1e0a029 --- /dev/null +++ b/fs/hfs/btree.c @@ -0,0 +1,229 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: btree.c,v 1.10 1998/11/02 22:08:54 rob Exp $ + */ + +#include "openbios/config.h" + +#include "libhfs.h" +#include "btree.h" +#include "data.h" +#include "file.h" +#include "block.h" +#include "node.h" + +/* + * NAME: btree->getnode() + * DESCRIPTION: retrieve a numbered node from a B*-tree file + */ +int bt_getnode(node *np, btree *bt, unsigned long nnum) +{ + block *bp = &np->data; + const byte *ptr; + int i; + + np->bt = bt; + np->nnum = nnum; + +# if 0 + fprintf(stderr, "BTREE: GET vol \"%s\" btree \"%s\" node %lu\n", + bt->f.vol->mdb.drVN, bt->f.name, np->nnum); +# endif + + /* verify the node exists and is marked as in-use */ + + if (nnum > 0 && nnum >= bt->hdr.bthNNodes) + ERROR(EIO, "read nonexistent b*-tree node"); + else if (bt->map && ! BMTST(bt->map, nnum)) + ERROR(EIO, "read unallocated b*-tree node"); + + if (f_getblock(&bt->f, nnum, bp) == -1) + goto fail; + + ptr = *bp; + + d_fetchul(&ptr, &np->nd.ndFLink); + d_fetchul(&ptr, &np->nd.ndBLink); + d_fetchsb(&ptr, &np->nd.ndType); + d_fetchsb(&ptr, &np->nd.ndNHeight); + d_fetchuw(&ptr, &np->nd.ndNRecs); + d_fetchsw(&ptr, &np->nd.ndResv2); + + if (np->nd.ndNRecs > HFS_MAX_NRECS) + ERROR(EIO, "too many b*-tree node records"); + + i = np->nd.ndNRecs + 1; + + ptr = *bp + HFS_BLOCKSZ - (2 * i); + + while (i--) + d_fetchuw(&ptr, &np->roff[i]); + + return 0; + +fail: + return -1; +} + + +/* + * NAME: btree->readhdr() + * DESCRIPTION: read the header node of a B*-tree + */ +int bt_readhdr(btree *bt) +{ + const byte *ptr; + byte *map = 0; + int i; + unsigned long nnum; + + if (bt_getnode(&bt->hdrnd, bt, 0) == -1) + goto fail; + + if (bt->hdrnd.nd.ndType != ndHdrNode || + bt->hdrnd.nd.ndNRecs != 3 || + bt->hdrnd.roff[0] != 0x00e || + bt->hdrnd.roff[1] != 0x078 || + bt->hdrnd.roff[2] != 0x0f8 || + bt->hdrnd.roff[3] != 0x1f8) + ERROR(EIO, "malformed b*-tree header node"); + + /* read header record */ + + ptr = HFS_NODEREC(bt->hdrnd, 0); + + d_fetchuw(&ptr, &bt->hdr.bthDepth); + d_fetchul(&ptr, &bt->hdr.bthRoot); + d_fetchul(&ptr, &bt->hdr.bthNRecs); + d_fetchul(&ptr, &bt->hdr.bthFNode); + d_fetchul(&ptr, &bt->hdr.bthLNode); + d_fetchuw(&ptr, &bt->hdr.bthNodeSize); + d_fetchuw(&ptr, &bt->hdr.bthKeyLen); + d_fetchul(&ptr, &bt->hdr.bthNNodes); + d_fetchul(&ptr, &bt->hdr.bthFree); + + for (i = 0; i < 76; ++i) + d_fetchsb(&ptr, &bt->hdr.bthResv[i]); + + if (bt->hdr.bthNodeSize != HFS_BLOCKSZ) + ERROR(EINVAL, "unsupported b*-tree node size"); + + /* read map record; construct btree bitmap */ + /* don't set bt->map until we're done, since getnode() checks it */ + + map = ALLOC(byte, HFS_MAP1SZ); + if (map == 0) + ERROR(ENOMEM, 0); + + memcpy(map, HFS_NODEREC(bt->hdrnd, 2), HFS_MAP1SZ); + bt->mapsz = HFS_MAP1SZ; + + /* read continuation map records, if any */ + + nnum = bt->hdrnd.nd.ndFLink; + + while (nnum) + { + node n; + byte *newmap; + + if (bt_getnode(&n, bt, nnum) == -1) + goto fail; + + if (n.nd.ndType != ndMapNode || + n.nd.ndNRecs != 1 || + n.roff[0] != 0x00e || + n.roff[1] != 0x1fa) + ERROR(EIO, "malformed b*-tree map node"); + + newmap = REALLOC(map, byte, bt->mapsz + HFS_MAPXSZ); + if (newmap == 0) + ERROR(ENOMEM, 0); + + map = newmap; + + memcpy(map + bt->mapsz, HFS_NODEREC(n, 0), HFS_MAPXSZ); + bt->mapsz += HFS_MAPXSZ; + + nnum = n.nd.ndFLink; + } + + bt->map = map; + + return 0; + +fail: + FREE(map); + return -1; +} + + +/* + * NAME: btree->search() + * DESCRIPTION: locate a data record given a search key + */ +int bt_search(btree *bt, const byte *key, node *np) +{ + int found = 0; + unsigned long nnum; + + nnum = bt->hdr.bthRoot; + + if (nnum == 0) + ERROR(ENOENT, 0); + + while (1) + { + const byte *rec; + + if (bt_getnode(np, bt, nnum) == -1) + { + found = -1; + goto fail; + } + + found = n_search(np, key); + + switch (np->nd.ndType) + { + case ndIndxNode: + if (np->rnum == -1) + ERROR(ENOENT, 0); + + rec = HFS_NODEREC(*np, np->rnum); + nnum = d_getul(HFS_RECDATA(rec)); + + break; + + case ndLeafNode: + if (! found) + ERROR(ENOENT, 0); + + goto done; + + default: + found = -1; + ERROR(EIO, "unexpected b*-tree node"); + } + } + +done: +fail: + return found; +} diff --git a/fs/hfs/build.xml b/fs/hfs/build.xml new file mode 100644 index 0000000..90f6e2b --- /dev/null +++ b/fs/hfs/build.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/fs/hfs/data.c b/fs/hfs/data.c new file mode 100644 index 0000000..91c6c3d --- /dev/null +++ b/fs/hfs/data.c @@ -0,0 +1,475 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: data.c,v 1.7 1998/11/02 22:08:57 rob Exp $ + */ + +#include "openbios/config.h" +#include "data.h" + +#define TIMEDIFF 2082844800UL + +static +time_t tzdiff = -1; + +const +unsigned char hfs_charorder[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + + 0x20, 0x22, 0x23, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + + 0x47, 0x48, 0x58, 0x5a, 0x5e, 0x60, 0x67, 0x69, + 0x6b, 0x6d, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7f, + 0x8d, 0x8f, 0x91, 0x93, 0x96, 0x98, 0x9f, 0xa1, + 0xa3, 0xa5, 0xa8, 0xaa, 0xab, 0xac, 0xad, 0xae, + + 0x54, 0x48, 0x58, 0x5a, 0x5e, 0x60, 0x67, 0x69, + 0x6b, 0x6d, 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7f, + 0x8d, 0x8f, 0x91, 0x93, 0x96, 0x98, 0x9f, 0xa1, + 0xa3, 0xa5, 0xa8, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + + 0x4c, 0x50, 0x5c, 0x62, 0x7d, 0x81, 0x9a, 0x55, + 0x4a, 0x56, 0x4c, 0x4e, 0x50, 0x5c, 0x62, 0x64, + 0x65, 0x66, 0x6f, 0x70, 0x71, 0x72, 0x7d, 0x89, + 0x8a, 0x8b, 0x81, 0x83, 0x9c, 0x9d, 0x9e, 0x9a, + + 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0x95, + 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0x52, 0x85, + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xcb, 0x57, 0x8c, 0xcc, 0x52, 0x85, + + 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0x26, + 0x27, 0xd4, 0x20, 0x4a, 0x4e, 0x83, 0x87, 0x87, + 0xd5, 0xd6, 0x24, 0x25, 0x2d, 0x2e, 0xd7, 0xd8, + 0xa7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +/* + * NAME: data->getsb() + * DESCRIPTION: marshal 1 signed byte into local host format + */ +signed char d_getsb(register const unsigned char *ptr) +{ + return ptr[0]; +} + +/* + * NAME: data->getub() + * DESCRIPTION: marshal 1 unsigned byte into local host format + */ +unsigned char d_getub(register const unsigned char *ptr) +{ + return ptr[0]; +} + +/* + * NAME: data->getsw() + * DESCRIPTION: marshal 2 signed bytes into local host format + */ +signed short d_getsw(register const unsigned char *ptr) +{ + return + ((( signed short) ptr[0] << 8) | + ((unsigned short) ptr[1] << 0)); +} + +/* + * NAME: data->getuw() + * DESCRIPTION: marshal 2 unsigned bytes into local host format + */ +unsigned short d_getuw(register const unsigned char *ptr) +{ + return + (((unsigned short) ptr[0] << 8) | + ((unsigned short) ptr[1] << 0)); +} + +/* + * NAME: data->getsl() + * DESCRIPTION: marshal 4 signed bytes into local host format + */ +signed long d_getsl(register const unsigned char *ptr) +{ + return + ((( signed long) ptr[0] << 24) | + ((unsigned long) ptr[1] << 16) | + ((unsigned long) ptr[2] << 8) | + ((unsigned long) ptr[3] << 0)); +} + +/* + * NAME: data->getul() + * DESCRIPTION: marshal 4 unsigned bytes into local host format + */ +unsigned long d_getul(register const unsigned char *ptr) +{ + return + (((unsigned long) ptr[0] << 24) | + ((unsigned long) ptr[1] << 16) | + ((unsigned long) ptr[2] << 8) | + ((unsigned long) ptr[3] << 0)); +} + +/* + * NAME: data->putsb() + * DESCRIPTION: marshal 1 signed byte out in big-endian format + */ +void d_putsb(register unsigned char *ptr, + register signed char data) +{ + *ptr = data; +} + +/* + * NAME: data->putub() + * DESCRIPTION: marshal 1 unsigned byte out in big-endian format + */ +void d_putub(register unsigned char *ptr, + register unsigned char data) +{ + *ptr = data; +} + +/* + * NAME: data->putsw() + * DESCRIPTION: marshal 2 signed bytes out in big-endian format + */ +void d_putsw(register unsigned char *ptr, + register signed short data) +{ + *ptr++ = ((unsigned short) data & 0xff00) >> 8; + *ptr = ((unsigned short) data & 0x00ff) >> 0; +} + +/* + * NAME: data->putuw() + * DESCRIPTION: marshal 2 unsigned bytes out in big-endian format + */ +void d_putuw(register unsigned char *ptr, + register unsigned short data) +{ + *ptr++ = (data & 0xff00) >> 8; + *ptr = (data & 0x00ff) >> 0; +} + +/* + * NAME: data->putsl() + * DESCRIPTION: marshal 4 signed bytes out in big-endian format + */ +void d_putsl(register unsigned char *ptr, + register signed long data) +{ + *ptr++ = ((unsigned long) data & 0xff000000UL) >> 24; + *ptr++ = ((unsigned long) data & 0x00ff0000UL) >> 16; + *ptr++ = ((unsigned long) data & 0x0000ff00UL) >> 8; + *ptr = ((unsigned long) data & 0x000000ffUL) >> 0; +} + +/* + * NAME: data->putul() + * DESCRIPTION: marshal 4 unsigned bytes out in big-endian format + */ +void d_putul(register unsigned char *ptr, + register unsigned long data) +{ + *ptr++ = (data & 0xff000000UL) >> 24; + *ptr++ = (data & 0x00ff0000UL) >> 16; + *ptr++ = (data & 0x0000ff00UL) >> 8; + *ptr = (data & 0x000000ffUL) >> 0; +} + +/* + * NAME: data->fetchsb() + * DESCRIPTION: incrementally retrieve a signed byte of data + */ +void d_fetchsb(register const unsigned char **ptr, + register signed char *dest) +{ + *dest = *(*ptr)++; +} + +/* + * NAME: data->fetchub() + * DESCRIPTION: incrementally retrieve an unsigned byte of data + */ +void d_fetchub(register const unsigned char **ptr, + register unsigned char *dest) +{ + *dest = *(*ptr)++; +} + +/* + * NAME: data->fetchsw() + * DESCRIPTION: incrementally retrieve a signed word of data + */ +void d_fetchsw(register const unsigned char **ptr, + register signed short *dest) +{ + *dest = + ((( signed short) (*ptr)[0] << 8) | + ((unsigned short) (*ptr)[1] << 0)); + *ptr += 2; +} + +/* + * NAME: data->fetchuw() + * DESCRIPTION: incrementally retrieve an unsigned word of data + */ +void d_fetchuw(register const unsigned char **ptr, + register unsigned short *dest) +{ + *dest = + (((unsigned short) (*ptr)[0] << 8) | + ((unsigned short) (*ptr)[1] << 0)); + *ptr += 2; +} + +/* + * NAME: data->fetchsl() + * DESCRIPTION: incrementally retrieve a signed long word of data + */ +void d_fetchsl(register const unsigned char **ptr, + register signed long *dest) +{ + *dest = + ((( signed long) (*ptr)[0] << 24) | + ((unsigned long) (*ptr)[1] << 16) | + ((unsigned long) (*ptr)[2] << 8) | + ((unsigned long) (*ptr)[3] << 0)); + *ptr += 4; +} + +/* + * NAME: data->fetchul() + * DESCRIPTION: incrementally retrieve an unsigned long word of data + */ +void d_fetchul(register const unsigned char **ptr, + register unsigned long *dest) +{ + *dest = + (((unsigned long) (*ptr)[0] << 24) | + ((unsigned long) (*ptr)[1] << 16) | + ((unsigned long) (*ptr)[2] << 8) | + ((unsigned long) (*ptr)[3] << 0)); + *ptr += 4; +} + +/* + * NAME: data->storesb() + * DESCRIPTION: incrementally store a signed byte of data + */ +void d_storesb(register unsigned char **ptr, + register signed char data) +{ + *(*ptr)++ = data; +} + +/* + * NAME: data->storeub() + * DESCRIPTION: incrementally store an unsigned byte of data + */ +void d_storeub(register unsigned char **ptr, + register unsigned char data) +{ + *(*ptr)++ = data; +} + +/* + * NAME: data->storesw() + * DESCRIPTION: incrementally store a signed word of data + */ +void d_storesw(register unsigned char **ptr, + register signed short data) +{ + *(*ptr)++ = ((unsigned short) data & 0xff00) >> 8; + *(*ptr)++ = ((unsigned short) data & 0x00ff) >> 0; +} + +/* + * NAME: data->storeuw() + * DESCRIPTION: incrementally store an unsigned word of data + */ +void d_storeuw(register unsigned char **ptr, + register unsigned short data) +{ + *(*ptr)++ = (data & 0xff00) >> 8; + *(*ptr)++ = (data & 0x00ff) >> 0; +} + +/* + * NAME: data->storesl() + * DESCRIPTION: incrementally store a signed long word of data + */ +void d_storesl(register unsigned char **ptr, + register signed long data) +{ + *(*ptr)++ = ((unsigned long) data & 0xff000000UL) >> 24; + *(*ptr)++ = ((unsigned long) data & 0x00ff0000UL) >> 16; + *(*ptr)++ = ((unsigned long) data & 0x0000ff00UL) >> 8; + *(*ptr)++ = ((unsigned long) data & 0x000000ffUL) >> 0; +} + +/* + * NAME: data->storeul() + * DESCRIPTION: incrementally store an unsigned long word of data + */ +void d_storeul(register unsigned char **ptr, + register unsigned long data) +{ + *(*ptr)++ = (data & 0xff000000UL) >> 24; + *(*ptr)++ = (data & 0x00ff0000UL) >> 16; + *(*ptr)++ = (data & 0x0000ff00UL) >> 8; + *(*ptr)++ = (data & 0x000000ffUL) >> 0; +} + +/* + * NAME: data->fetchstr() + * DESCRIPTION: incrementally retrieve a string + */ +void d_fetchstr(const unsigned char **ptr, char *dest, unsigned size) +{ + unsigned len; + + len = d_getub(*ptr); + + if (len > 0 && len < size) + memcpy(dest, *ptr + 1, len); + else + len = 0; + + dest[len] = 0; + + *ptr += size; +} + +/* + * NAME: data->storestr() + * DESCRIPTION: incrementally store a string + */ +void d_storestr(unsigned char **ptr, const char *src, unsigned size) +{ + unsigned len; + + len = strlen(src); + if (len > --size) + len = 0; + + d_storeub(ptr, len); + + memcpy(*ptr, src, len); + memset(*ptr + len, 0, size - len); + + *ptr += size; +} + +/* + * NAME: data->relstring() + * DESCRIPTION: compare two strings as per MacOS for HFS + */ +int d_relstring(const char *str1, const char *str2) +{ + register int diff; + + while (*str1 && *str2) + { + diff = hfs_charorder[(unsigned char) *str1] - + hfs_charorder[(unsigned char) *str2]; + + if (diff) + return diff; + + ++str1, ++str2; + } + + if (! *str1 && *str2) + return -1; + else if (*str1 && ! *str2) + return 1; + + return 0; +} + +/* + * NAME: calctzdiff() + * DESCRIPTION: calculate the timezone difference between local time and UTC + */ +static +void calctzdiff(void) +{ +# ifdef HAVE_MKTIME + + time_t t; + int isdst; + struct tm tm; + const struct tm *tmp; + + time(&t); + isdst = localtime(&t)->tm_isdst; + + tmp = gmtime(&t); + if (tmp) + { + tm = *tmp; + tm.tm_isdst = isdst; + + tzdiff = t - mktime(&tm); + } + else + tzdiff = 0; + +# else + + tzdiff = 0; + +# endif +} + +/* + * NAME: data->ltime() + * DESCRIPTION: convert MacOS time to local time + */ +time_t d_ltime(unsigned long mtime) +{ + if (tzdiff == -1) + calctzdiff(); + + return (time_t) (mtime - TIMEDIFF) - tzdiff; +} + +/* + * NAME: data->mtime() + * DESCRIPTION: convert local time to MacOS time + */ +unsigned long d_mtime(time_t ltime) +{ + if (tzdiff == -1) + calctzdiff(); + + return (unsigned long) (ltime + tzdiff) + TIMEDIFF; +} diff --git a/fs/hfs/file.c b/fs/hfs/file.c new file mode 100644 index 0000000..3d82d6e --- /dev/null +++ b/fs/hfs/file.c @@ -0,0 +1,191 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: file.c,v 1.9 1998/11/02 22:08:59 rob Exp $ + */ + +#include "openbios/config.h" +#include "libhfs.h" +#include "file.h" +#include "btree.h" +#include "record.h" +#include "volume.h" + +/* + * NAME: file->init() + * DESCRIPTION: initialize file structure + */ +void f_init(hfsfile *file, hfsvol *vol, long cnid, const char *name) +{ + int i; + + file->vol = vol; + file->parid = 0; + + strcpy(file->name, name); + + file->cat.cdrType = cdrFilRec; + file->cat.cdrResrv2 = 0; + + file->cat.u.fil.filFlags = 0; + file->cat.u.fil.filTyp = 0; + + file->cat.u.fil.filUsrWds.fdType = 0; + file->cat.u.fil.filUsrWds.fdCreator = 0; + file->cat.u.fil.filUsrWds.fdFlags = 0; + file->cat.u.fil.filUsrWds.fdLocation.v = 0; + file->cat.u.fil.filUsrWds.fdLocation.h = 0; + file->cat.u.fil.filUsrWds.fdFldr = 0; + + file->cat.u.fil.filFlNum = cnid; + file->cat.u.fil.filStBlk = 0; + file->cat.u.fil.filLgLen = 0; + file->cat.u.fil.filPyLen = 0; + file->cat.u.fil.filRStBlk = 0; + file->cat.u.fil.filRLgLen = 0; + file->cat.u.fil.filRPyLen = 0; + file->cat.u.fil.filCrDat = 0; + file->cat.u.fil.filMdDat = 0; + file->cat.u.fil.filBkDat = 0; + + file->cat.u.fil.filFndrInfo.fdIconID = 0; + for (i = 0; i < 4; ++i) + file->cat.u.fil.filFndrInfo.fdUnused[i] = 0; + file->cat.u.fil.filFndrInfo.fdComment = 0; + file->cat.u.fil.filFndrInfo.fdPutAway = 0; + + file->cat.u.fil.filClpSize = 0; + + for (i = 0; i < 3; ++i) + { + file->cat.u.fil.filExtRec[i].xdrStABN = 0; + file->cat.u.fil.filExtRec[i].xdrNumABlks = 0; + + file->cat.u.fil.filRExtRec[i].xdrStABN = 0; + file->cat.u.fil.filRExtRec[i].xdrNumABlks = 0; + } + + file->cat.u.fil.filResrv = 0; + + f_selectfork(file, fkData); + + file->flags = 0; + + file->prev = 0; + file->next = 0; +} + +/* + * NAME: file->selectfork() + * DESCRIPTION: choose a fork for file operations + */ +void f_selectfork(hfsfile *file, int fork) +{ + file->fork = fork; + + memcpy(&file->ext, fork == fkData ? + &file->cat.u.fil.filExtRec : &file->cat.u.fil.filRExtRec, + sizeof(ExtDataRec)); + + file->fabn = 0; + file->pos = 0; +} + +/* + * NAME: file->getptrs() + * DESCRIPTION: make pointers to the current fork's lengths and extents + */ +void f_getptrs(hfsfile *file, ExtDataRec **extrec, + unsigned long **lglen, unsigned long **pylen) +{ + if (file->fork == fkData) + { + if (extrec) + *extrec = &file->cat.u.fil.filExtRec; + if (lglen) + *lglen = &file->cat.u.fil.filLgLen; + if (pylen) + *pylen = &file->cat.u.fil.filPyLen; + } + else + { + if (extrec) + *extrec = &file->cat.u.fil.filRExtRec; + if (lglen) + *lglen = &file->cat.u.fil.filRLgLen; + if (pylen) + *pylen = &file->cat.u.fil.filRPyLen; + } +} + +/* + * NAME: file->doblock() + * DESCRIPTION: read or write a numbered block from a file + */ +int f_doblock(hfsfile *file, unsigned long num, block *bp, + int (*func)(hfsvol *, unsigned int, unsigned int, block *)) +{ + unsigned int abnum; + unsigned int blnum; + unsigned int fabn; + int i; + + abnum = num / file->vol->lpa; + blnum = num % file->vol->lpa; + + /* locate the appropriate extent record */ + + fabn = file->fabn; + + if (abnum < fabn) + { + ExtDataRec *extrec; + + f_getptrs(file, &extrec, 0, 0); + + fabn = file->fabn = 0; + memcpy(&file->ext, extrec, sizeof(ExtDataRec)); + } + else + abnum -= fabn; + + while (1) + { + unsigned int n; + + for (i = 0; i < 3; ++i) + { + n = file->ext[i].xdrNumABlks; + + if (abnum < n) + return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp); + + fabn += n; + abnum -= n; + } + + if (v_extsearch(file, fabn, &file->ext, 0) <= 0) + goto fail; + + file->fabn = fabn; + } + +fail: + return -1; +} + diff --git a/fs/hfs/hfs.c b/fs/hfs/hfs.c new file mode 100644 index 0000000..b8b1266 --- /dev/null +++ b/fs/hfs/hfs.c @@ -0,0 +1,737 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: hfs.c,v 1.15 1998/11/02 22:09:00 rob Exp $ + */ + +#include "openbios/config.h" +#include "libhfs.h" +#include "data.h" +#include "block.h" +#include "medium.h" +#include "file.h" +#include "btree.h" +#include "node.h" +#include "record.h" +#include "volume.h" + +const char *hfs_error = "no error"; /* static error string */ + +hfsvol *hfs_mounts; /* linked list of mounted volumes */ + +static +hfsvol *curvol; /* current volume */ + + +/* + * NAME: getvol() + * DESCRIPTION: validate a volume reference + */ +static +int getvol(hfsvol **vol) +{ + if (*vol == 0) + { + if (curvol == 0) + ERROR(EINVAL, "no volume is current"); + + *vol = curvol; + } + + return 0; + +fail: + return -1; +} + +/* High-Level Volume Routines ============================================== */ + +/* + * NAME: hfs->mount() + * DESCRIPTION: open an HFS volume; return volume descriptor or 0 (error) + */ +hfsvol *hfs_mount( int os_fd, int pnum) +{ + hfsvol *vol, *check; + int mode = HFS_MODE_RDONLY; + + /* see if the volume is already mounted */ + for (check = hfs_mounts; check; check = check->next) + { + if (check->pnum == pnum && v_same(check, os_fd) == 1) + { + vol = check; + goto done; + } + } + + vol = ALLOC(hfsvol, 1); + if (vol == 0) + ERROR(ENOMEM, 0); + + v_init(vol, mode); + + vol->flags |= HFS_VOL_READONLY; + if( v_open(vol, os_fd) == -1 ) + goto fail; + + /* mount the volume */ + + if (v_geometry(vol, pnum) == -1 || + v_mount(vol) == -1) + goto fail; + + /* add to linked list of volumes */ + + vol->prev = 0; + vol->next = hfs_mounts; + + if (hfs_mounts) + hfs_mounts->prev = vol; + + hfs_mounts = vol; + +done: + ++vol->refs; + curvol = vol; + + return vol; + +fail: + if (vol) + { + v_close(vol); + FREE(vol); + } + + return 0; +} + + +/* + * NAME: hfs->umount() + * DESCRIPTION: close an HFS volume + */ +int hfs_umount(hfsvol *vol) +{ + int result = 0; + + if (getvol(&vol) == -1) + goto fail; + + if (--vol->refs) + { + goto done; + } + + /* close all open files and directories */ + + while (vol->files) + { + if (hfs_close(vol->files) == -1) + result = -1; + } + + while (vol->dirs) + { + if (hfs_closedir(vol->dirs) == -1) + result = -1; + } + + /* close medium */ + + if (v_close(vol) == -1) + result = -1; + + /* remove from linked list of volumes */ + + if (vol->prev) + vol->prev->next = vol->next; + if (vol->next) + vol->next->prev = vol->prev; + + if (vol == hfs_mounts) + hfs_mounts = vol->next; + if (vol == curvol) + curvol = 0; + + FREE(vol); + +done: + return result; + +fail: + return -1; +} + +/* + * NAME: hfs->umountall() + * DESCRIPTION: unmount all mounted volumes + */ +void hfs_umountall(void) +{ + while (hfs_mounts) + hfs_umount(hfs_mounts); +} + +/* + * NAME: hfs->getvol() + * DESCRIPTION: return a pointer to a mounted volume + */ +hfsvol *hfs_getvol(const char *name) +{ + hfsvol *vol; + + if (name == 0) + return curvol; + + for (vol = hfs_mounts; vol; vol = vol->next) + { + if (d_relstring(name, vol->mdb.drVN) == 0) + return vol; + } + + return 0; +} + +/* + * NAME: hfs->setvol() + * DESCRIPTION: change the current volume + */ +void hfs_setvol(hfsvol *vol) +{ + curvol = vol; +} + +/* + * NAME: hfs->vstat() + * DESCRIPTION: return volume statistics + */ +int hfs_vstat(hfsvol *vol, hfsvolent *ent) +{ + if (getvol(&vol) == -1) + goto fail; + + strcpy(ent->name, vol->mdb.drVN); + + ent->flags = (vol->flags & HFS_VOL_READONLY) ? HFS_ISLOCKED : 0; + + ent->totbytes = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz; + ent->freebytes = vol->mdb.drFreeBks * vol->mdb.drAlBlkSiz; + + ent->alblocksz = vol->mdb.drAlBlkSiz; + ent->clumpsz = vol->mdb.drClpSiz; + + ent->numfiles = vol->mdb.drFilCnt; + ent->numdirs = vol->mdb.drDirCnt; + + ent->crdate = d_ltime(vol->mdb.drCrDate); + ent->mddate = d_ltime(vol->mdb.drLsMod); + ent->bkdate = d_ltime(vol->mdb.drVolBkUp); + + ent->blessed = vol->mdb.drFndrInfo[0]; + + return 0; + +fail: + return -1; +} + + +/* High-Level Directory Routines =========================================== */ + +/* + * NAME: hfs->chdir() + * DESCRIPTION: change current HFS directory + */ +int hfs_chdir(hfsvol *vol, const char *path) +{ + CatDataRec data; + + if (getvol(&vol) == -1 || + v_resolve(&vol, path, &data, 0, 0, 0) <= 0) + goto fail; + + if (data.cdrType != cdrDirRec) + ERROR(ENOTDIR, 0); + + vol->cwd = data.u.dir.dirDirID; + + return 0; + +fail: + return -1; +} + +/* + * NAME: hfs->getcwd() + * DESCRIPTION: return the current working directory ID + */ +unsigned long hfs_getcwd(hfsvol *vol) +{ + if (getvol(&vol) == -1) + return 0; + + return vol->cwd; +} + +/* + * NAME: hfs->setcwd() + * DESCRIPTION: set the current working directory ID + */ +int hfs_setcwd(hfsvol *vol, unsigned long id) +{ + if (getvol(&vol) == -1) + goto fail; + + if (id == vol->cwd) + goto done; + + /* make sure the directory exists */ + + if (v_getdthread(vol, id, 0, 0) <= 0) + goto fail; + + vol->cwd = id; + +done: + return 0; + +fail: + return -1; +} + +/* + * NAME: hfs->dirinfo() + * DESCRIPTION: given a directory ID, return its (name and) parent ID + */ +int hfs_dirinfo(hfsvol *vol, unsigned long *id, char *name) +{ + CatDataRec thread; + + if (getvol(&vol) == -1 || + v_getdthread(vol, *id, &thread, 0) <= 0) + goto fail; + + *id = thread.u.dthd.thdParID; + + if (name) + strcpy(name, thread.u.dthd.thdCName); + + return 0; + +fail: + return -1; +} + +/* + * NAME: hfs->opendir() + * DESCRIPTION: prepare to read the contents of a directory + */ +hfsdir *hfs_opendir(hfsvol *vol, const char *path) +{ + hfsdir *dir = 0; + CatKeyRec key; + CatDataRec data; + byte pkey[HFS_CATKEYLEN]; + + if (getvol(&vol) == -1) + goto fail; + + dir = ALLOC(hfsdir, 1); + if (dir == 0) + ERROR(ENOMEM, 0); + + dir->vol = vol; + + if (*path == 0) + { + /* meta-directory containing root dirs from all mounted volumes */ + + dir->dirid = 0; + dir->vptr = hfs_mounts; + } + else + { + if (v_resolve(&vol, path, &data, 0, 0, 0) <= 0) + goto fail; + + if (data.cdrType != cdrDirRec) + ERROR(ENOTDIR, 0); + + dir->dirid = data.u.dir.dirDirID; + dir->vptr = 0; + + r_makecatkey(&key, dir->dirid, ""); + r_packcatkey(&key, pkey, 0); + + if (bt_search(&vol->cat, pkey, &dir->n) <= 0) + goto fail; + } + + dir->prev = 0; + dir->next = vol->dirs; + + if (vol->dirs) + vol->dirs->prev = dir; + + vol->dirs = dir; + + return dir; + +fail: + FREE(dir); + return 0; +} + +/* + * NAME: hfs->readdir() + * DESCRIPTION: return the next entry in the directory + */ +int hfs_readdir(hfsdir *dir, hfsdirent *ent) +{ + CatKeyRec key; + CatDataRec data; + const byte *ptr; + + if (dir->dirid == 0) + { + hfsvol *vol; + char cname[HFS_MAX_FLEN + 1]; + + for (vol = hfs_mounts; vol; vol = vol->next) + { + if (vol == dir->vptr) + break; + } + + if (vol == 0) + ERROR(ENOENT, "no more entries"); + + if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, 0) <= 0 || + v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName, + &data, cname, 0) <= 0) + goto fail; + + r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent); + + dir->vptr = vol->next; + + goto done; + } + + if (dir->n.rnum == -1) + ERROR(ENOENT, "no more entries"); + + while (1) + { + ++dir->n.rnum; + + while (dir->n.rnum >= dir->n.nd.ndNRecs) + { + if (dir->n.nd.ndFLink == 0) + { + dir->n.rnum = -1; + ERROR(ENOENT, "no more entries"); + } + + if (bt_getnode(&dir->n, dir->n.bt, dir->n.nd.ndFLink) == -1) + { + dir->n.rnum = -1; + goto fail; + } + + dir->n.rnum = 0; + } + + ptr = HFS_NODEREC(dir->n, dir->n.rnum); + + r_unpackcatkey(ptr, &key); + + if (key.ckrParID != dir->dirid) + { + dir->n.rnum = -1; + ERROR(ENOENT, "no more entries"); + } + + r_unpackcatdata(HFS_RECDATA(ptr), &data); + + switch (data.cdrType) + { + case cdrDirRec: + case cdrFilRec: + r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent); + goto done; + + case cdrThdRec: + case cdrFThdRec: + break; + + default: + dir->n.rnum = -1; + ERROR(EIO, "unexpected directory entry found"); + } + } + +done: + return 0; + +fail: + return -1; +} + +/* + * NAME: hfs->closedir() + * DESCRIPTION: stop reading a directory + */ +int hfs_closedir(hfsdir *dir) +{ + hfsvol *vol = dir->vol; + + if (dir->prev) + dir->prev->next = dir->next; + if (dir->next) + dir->next->prev = dir->prev; + if (dir == vol->dirs) + vol->dirs = dir->next; + + FREE(dir); + + return 0; +} + +/* High-Level File Routines ================================================ */ + +/* + * NAME: hfs->open() + * DESCRIPTION: prepare a file for I/O + */ +hfsfile *hfs_open(hfsvol *vol, const char *path) +{ + hfsfile *file = 0; + + if (getvol(&vol) == -1) + goto fail; + + file = ALLOC(hfsfile, 1); + if (file == 0) + ERROR(ENOMEM, 0); + + if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, 0) <= 0) + goto fail; + + if (file->cat.cdrType != cdrFilRec) + ERROR(EISDIR, 0); + + /* package file handle for user */ + + file->vol = vol; + file->flags = 0; + + f_selectfork(file, fkData); + + file->prev = 0; + file->next = vol->files; + + if (vol->files) + vol->files->prev = file; + + vol->files = file; + + return file; + +fail: + FREE(file); + return 0; +} + +/* + * NAME: hfs->setfork() + * DESCRIPTION: select file fork for I/O operations + */ +int hfs_setfork(hfsfile *file, int fork) +{ + int result = 0; + + f_selectfork(file, fork ? fkRsrc : fkData); + + return result; +} + +/* + * NAME: hfs->getfork() + * DESCRIPTION: return the current fork for I/O operations + */ +int hfs_getfork(hfsfile *file) +{ + return file->fork != fkData; +} + +/* + * NAME: hfs->read() + * DESCRIPTION: read from an open file + */ +unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len) +{ + unsigned long *lglen, count; + byte *ptr = buf; + + f_getptrs(file, 0, &lglen, 0); + + if (file->pos + len > *lglen) + len = *lglen - file->pos; + + count = len; + while (count) + { + unsigned long bnum, offs, chunk; + + bnum = file->pos >> HFS_BLOCKSZ_BITS; + offs = file->pos & (HFS_BLOCKSZ - 1); + + chunk = HFS_BLOCKSZ - offs; + if (chunk > count) + chunk = count; + + if (offs == 0 && chunk == HFS_BLOCKSZ) + { + if (f_getblock(file, bnum, (block *) ptr) == -1) + goto fail; + } + else + { + block b; + + if (f_getblock(file, bnum, &b) == -1) + goto fail; + + memcpy(ptr, b + offs, chunk); + } + + ptr += chunk; + + file->pos += chunk; + count -= chunk; + } + + return len; + +fail: + return -1; +} + +/* + * NAME: hfs->seek() + * DESCRIPTION: change file seek pointer + */ +unsigned long hfs_seek(hfsfile *file, long offset, int from) +{ + unsigned long *lglen, newpos; + + f_getptrs(file, 0, &lglen, 0); + + switch (from) + { + case HFS_SEEK_SET: + newpos = (offset < 0) ? 0 : offset; + break; + + case HFS_SEEK_CUR: + if (offset < 0 && (unsigned long) -offset > file->pos) + newpos = 0; + else + newpos = file->pos + offset; + break; + + case HFS_SEEK_END: + if (offset < 0 && (unsigned long) -offset > *lglen) + newpos = 0; + else + newpos = *lglen + offset; + break; + + default: + ERROR(EINVAL, 0); + } + + if (newpos > *lglen) + newpos = *lglen; + + file->pos = newpos; + + return newpos; + +fail: + return -1; +} + +/* + * NAME: hfs->close() + * DESCRIPTION: close a file + */ +int hfs_close(hfsfile *file) +{ + hfsvol *vol = file->vol; + int result = 0; + + if (file->prev) + file->prev->next = file->next; + if (file->next) + file->next->prev = file->prev; + if (file == vol->files) + vol->files = file->next; + + FREE(file); + + return result; +} + +/* High-Level Catalog Routines ============================================= */ + +/* + * NAME: hfs->stat() + * DESCRIPTION: return catalog information for an arbitrary path + */ +int hfs_stat(hfsvol *vol, const char *path, hfsdirent *ent) +{ + CatDataRec data; + unsigned long parid; + char name[HFS_MAX_FLEN + 1]; + + if (getvol(&vol) == -1 || + v_resolve(&vol, path, &data, &parid, name, 0) <= 0) + goto fail; + + r_unpackdirent(parid, name, &data, ent); + + return 0; + +fail: + return -1; +} + +/* + * NAME: hfs->fstat() + * DESCRIPTION: return catalog information for an open file + */ +int hfs_fstat(hfsfile *file, hfsdirent *ent) +{ + r_unpackdirent(file->parid, file->name, &file->cat, ent); + + return 0; +} diff --git a/fs/hfs/hfs_fs.c b/fs/hfs/hfs_fs.c new file mode 100644 index 0000000..c169886 --- /dev/null +++ b/fs/hfs/hfs_fs.c @@ -0,0 +1,324 @@ +/* + * Creation Date: <2001/05/06 22:47:23 samuel> + * Time-stamp: <2004/01/12 10:24:35 samuel> + * + * + * + * HFS world interface + * + * Copyright (C) 2001-2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/fs.h" +#include "libhfs.h" + +#define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */ +#define MAC_OS_ROM_TYPE 0x74627869 /* 'tbxi' */ +#define MAC_OS_ROM_NAME "Mac OS ROM" + +#define FINDER_TYPE 0x464E4452 /* 'FNDR' */ +#define FINDER_CREATOR 0x4D414353 /* 'MACS' */ +#define SYSTEM_TYPE 0x7A737973 /* 'zsys' */ +#define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */ + + + +/************************************************************************/ +/* Search Functions */ +/************************************************************************/ + +static int +_find_file( hfsvol *vol, const char *path, ulong type, ulong creator ) +{ + hfsdirent ent; + hfsdir *dir; + int ret=1; + + if( !(dir=hfs_opendir(vol, path)) ) + return 1; + + while( ret && !hfs_readdir(dir, &ent) ) { + if( ent.flags & HFS_ISDIR ) + continue; + ret = !(*(ulong*)ent.u.file.type == type && *(ulong*)ent.u.file.creator == creator ); + } + + hfs_closedir( dir ); + return ret; +} + + +/* ret: 0=success, 1=not_found, 2=not_a_dir */ +static int +_search( hfsvol *vol, const char *path, const char *sname, file_desc_t **ret_fd ) +{ + hfsdir *dir; + hfsdirent ent; + int topdir=0, status = 1; + char *p, buf[256]; + + strncpy( buf, path, sizeof(buf) ); + if( buf[strlen(buf)-1] != ':' ) + strncat( buf, ":", sizeof(buf) ); + buf[sizeof(buf)-1] = 0; + p = buf + strlen( buf ); + + if( !(dir=hfs_opendir(vol, path)) ) + return 2; + + /* printk("DIRECTORY: %s\n", path ); */ + + while( status && !hfs_readdir(dir, &ent) ) { + ulong type, creator; + + *p = 0; + topdir = 0; + + strncat( buf, ent.name, sizeof(buf) ); + if( (status=_search(vol, buf, sname, ret_fd)) != 2 ) + continue; + topdir = 1; + + /* name search? */ + if( sname ) { + status = strcasecmp( ent.name, sname ); + continue; + } + + type = *(ulong*)ent.u.file.type; + creator = *(ulong*)ent.u.file.creator; + + /* look for Mac OS ROM, System and Finder in the same directory */ + if( type == MAC_OS_ROM_TYPE && creator == MAC_OS_ROM_CREATOR ) { + if( strcasecmp(ent.name, MAC_OS_ROM_NAME) ) + continue; + + status = _find_file( vol, path, FINDER_TYPE, FINDER_CREATOR ) + || _find_file( vol, path, SYSTEM_TYPE, SYSTEM_CREATOR ); + } + } + if( !status && topdir && ret_fd && !(*ret_fd=(file_desc_t*)hfs_open(vol, buf)) ) { + printk("Unexpected error: failed to open matched ROM\n"); + status = 1; + } + + hfs_closedir( dir ); + return status; +} + +static file_desc_t * +_do_search( fs_ops_t *fs, const char *sname ) +{ + hfsvol *vol = hfs_getvol( NULL ); + file_desc_t *ret_fd = NULL; + + (void)_search( vol, ":", sname, &ret_fd ); + return ret_fd; +} + +static file_desc_t * +search_rom( fs_ops_t *fs ) +{ + return _do_search( fs, NULL ); +} + +static file_desc_t * +search_file( fs_ops_t *fs, const char *sname ) +{ + return _do_search( fs, sname ); +} + + +/************************************************************************/ +/* file/fs ops */ +/************************************************************************/ + +static void +file_close( file_desc_t *fd ) +{ + hfsfile *file = (hfsfile*)fd; + hfs_close( file ); +} + +static int +file_lseek( file_desc_t *fd, off_t offs, int whence ) +{ + hfsfile *file = (hfsfile*)fd; + + switch( whence ) { + case SEEK_CUR: + whence = HFS_SEEK_CUR; + break; + case SEEK_END: + whence = HFS_SEEK_END; + break; + default: + case SEEK_SET: + whence = HFS_SEEK_SET; + break; + } + + return hfs_seek( file, offs, whence ); +} + +static int +file_read( file_desc_t *fd, void *buf, size_t count ) +{ + hfsfile *file = (hfsfile*)fd; + return hfs_read( file, buf, count ); +} + +static char * +get_path( file_desc_t *fd, char *retbuf, int len ) +{ + char buf[256], buf2[256]; + hfsvol *vol = hfs_getvol( NULL ); + hfsfile *file = (hfsfile*)fd; + hfsdirent ent; + int start, ns; + ulong id; + + hfs_fstat( file, &ent ); + start = sizeof(buf) - strlen(ent.name) - 1; + if( start <= 0 ) + return NULL; + strcpy( buf+start, ent.name ); + buf[--start] = '\\'; + + ns = start; + for( id=ent.parid ; !hfs_dirinfo(vol, &id, buf2) ; ) { + start = ns; + ns -= strlen(buf2); + if( ns <= 0 ) + return NULL; + strcpy( buf+ns, buf2 ); + buf[--ns] = buf[start] = '\\'; + } + if( strlen(buf + start) >= len ) + return NULL; + + strcpy( retbuf, buf+start ); + return retbuf; +} + +static char * +vol_name( fs_ops_t *fs, char *buf, int size ) +{ + return get_hfs_vol_name( fs->fd, buf, size ); +} + + +static file_desc_t * +open_path( fs_ops_t *fs, const char *path ) +{ + hfsvol *vol = (hfsvol*)fs->fs_data; + const char *s; + char buf[256]; + + if( !strncmp(path, "\\\\", 2) ) { + hfsvolent ent; + + /* \\ is an alias for the (blessed) system folder */ + if( hfs_vstat(vol, &ent) < 0 || hfs_setcwd(vol, ent.blessed) ) + return NULL; + path += 2; + } else { + hfs_chdir( vol, ":" ); + } + + for( path-- ;; ) { + int n; + + s = ++path; + if( !(path=strchr(s, '\\')) ) + break; + n = MIN( sizeof(buf)-1, (path-s) ); + if( !n ) + continue; + + strncpy( buf, s, n ); + buf[n] = 0; + if( hfs_chdir(vol, buf) ) + return NULL; + } + + /* support the ':filetype' syntax */ + if( *s == ':' ) { + unsigned long id, oldid = hfs_getcwd(vol); + file_desc_t *ret = NULL; + hfsdirent ent; + hfsdir *dir; + + s++; + id = oldid; + hfs_dirinfo( vol, &id, buf ); + hfs_setcwd( vol, id ); + + if( !(dir=hfs_opendir(vol, buf)) ) + return NULL; + hfs_setcwd( vol, oldid ); + + while( !hfs_readdir(dir, &ent) ) { + if( ent.flags & HFS_ISDIR ) + continue; + if( !strncmp(s, ent.u.file.type, 4) ) { + ret = (file_desc_t*)hfs_open( vol, ent.name ); + break; + } + } + hfs_closedir( dir ); + return ret; + } + + return (file_desc_t*)hfs_open( vol, s ); +} + +static void +close_fs( fs_ops_t *fs ) +{ + hfsvol *vol = (hfsvol*)fs->fs_data; + + hfs_umount( vol ); + /* callers responsibility to call free(fs) */ +} + +static char * +get_fstype( fs_ops_t *fs ) +{ + return ("HFS"); +} + +static fs_ops_t hfs_ops = { + .close_fs = close_fs, + .open_path = open_path, + .search_rom = search_rom, + .search_file = search_file, + .vol_name = vol_name, + + .get_path = get_path, + .close = file_close, + .read = file_read, + .lseek = file_lseek, + + .get_fstype = get_fstype, +}; + +int +fs_hfs_open( int os_fd, fs_ops_t *fs ) +{ + hfsvol *vol = hfs_mount( os_fd, 0 ); + + if( !vol ) + return -1; + + *fs = hfs_ops; + fs->fs_data = vol; + + return 0; +} diff --git a/fs/hfs/include/apple.h b/fs/hfs/include/apple.h new file mode 100644 index 0000000..eef34d6 --- /dev/null +++ b/fs/hfs/include/apple.h @@ -0,0 +1,272 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: apple.h,v 1.1 1998/04/11 08:27:11 rob Exp $ + */ + +typedef signed char Char; +typedef unsigned char UChar; +typedef signed char SignedByte; +typedef signed short Integer; +typedef unsigned short UInteger; +typedef signed long LongInt; +typedef unsigned long ULongInt; +typedef char Str15[16]; +typedef char Str31[32]; +typedef long OSType; + +typedef struct { + Integer sbSig; /* device signature (should be 0x4552) */ + Integer sbBlkSize; /* block size of the device (in bytes) */ + LongInt sbBlkCount; /* number of blocks on the device */ + Integer sbDevType; /* reserved */ + Integer sbDevId; /* reserved */ + LongInt sbData; /* reserved */ + Integer sbDrvrCount; /* number of driver descriptor entries */ + LongInt ddBlock; /* first driver's starting block */ + Integer ddSize; /* size of the driver, in 512-byte blocks */ + Integer ddType; /* driver operating system type (MacOS = 1) */ + Integer ddPad[243]; /* additional drivers, if any */ +} Block0; + +typedef struct { + Integer pmSig; /* partition signature (0x504d or 0x5453) */ + Integer pmSigPad; /* reserved */ + LongInt pmMapBlkCnt; /* number of blocks in partition map */ + LongInt pmPyPartStart; /* first physical block of partition */ + LongInt pmPartBlkCnt; /* number of blocks in partition */ + Char pmPartName[33]; /* partition name */ + Char pmParType[33]; /* partition type */ + LongInt pmLgDataStart; /* first logical block of data area */ + LongInt pmDataCnt; /* number of blocks in data area */ + LongInt pmPartStatus; /* partition status information */ + LongInt pmLgBootStart; /* first logical block of boot code */ + LongInt pmBootSize; /* size of boot code, in bytes */ + LongInt pmBootAddr; /* boot code load address */ + LongInt pmBootAddr2; /* reserved */ + LongInt pmBootEntry; /* boot code entry point */ + LongInt pmBootEntry2; /* reserved */ + LongInt pmBootCksum; /* boot code checksum */ + Char pmProcessor[17];/* processor type */ + Integer pmPad[188]; /* reserved */ +} Partition; + +typedef struct { + Integer bbID; /* boot blocks signature */ + LongInt bbEntry; /* entry point to boot code */ + Integer bbVersion; /* boot blocks version number */ + Integer bbPageFlags; /* used internally */ + Str15 bbSysName; /* System filename */ + Str15 bbShellName; /* Finder filename */ + Str15 bbDbg1Name; /* debugger filename */ + Str15 bbDbg2Name; /* debugger filename */ + Str15 bbScreenName; /* name of startup screen */ + Str15 bbHelloName; /* name of startup program */ + Str15 bbScrapName; /* name of system scrap file */ + Integer bbCntFCBs; /* number of FCBs to allocate */ + Integer bbCntEvts; /* number of event queue elements */ + LongInt bb128KSHeap; /* system heap size on 128K Mac */ + LongInt bb256KSHeap; /* used internally */ + LongInt bbSysHeapSize; /* system heap size on all machines */ + Integer filler; /* reserved */ + LongInt bbSysHeapExtra; /* additional system heap space */ + LongInt bbSysHeapFract; /* fraction of RAM for system heap */ +} BootBlkHdr; + +typedef struct { + UInteger xdrStABN; /* first allocation block */ + UInteger xdrNumABlks; /* number of allocation blocks */ +} ExtDescriptor; + +typedef ExtDescriptor ExtDataRec[3]; + +typedef struct { + SignedByte xkrKeyLen; /* key length */ + SignedByte xkrFkType; /* fork type (0x00/0xff == data/resource */ + ULongInt xkrFNum; /* file number */ + UInteger xkrFABN; /* starting file allocation block */ +} ExtKeyRec; + +typedef struct { + SignedByte ckrKeyLen; /* key length */ + SignedByte ckrResrv1; /* reserved */ + ULongInt ckrParID; /* parent directory ID */ + Str31 ckrCName; /* catalog node name */ +} CatKeyRec; + +typedef struct { + Integer v; /* vertical coordinate */ + Integer h; /* horizontal coordinate */ +} Point; + +typedef struct { + Integer top; /* top edge of rectangle */ + Integer left; /* left edge */ + Integer bottom; /* bottom edge */ + Integer right; /* right edge */ +} Rect; + +typedef struct { + Rect frRect; /* folder's rectangle */ + Integer frFlags; /* flags */ + Point frLocation; /* folder's location */ + Integer frView; /* folder's view */ +} DInfo; + +typedef struct { + Point frScroll; /* scroll position */ + LongInt frOpenChain; /* directory ID chain of open folders */ + Integer frUnused; /* reserved */ + Integer frComment; /* comment ID */ + LongInt frPutAway; /* directory ID */ +} DXInfo; + +typedef struct { + OSType fdType; /* file type */ + OSType fdCreator; /* file's creator */ + Integer fdFlags; /* flags */ + Point fdLocation; /* file's location */ + Integer fdFldr; /* file's window */ +} FInfo; + +typedef struct { + Integer fdIconID; /* icon ID */ + Integer fdUnused[4]; /* reserved */ + Integer fdComment; /* comment ID */ + LongInt fdPutAway; /* home directory ID */ +} FXInfo; + +typedef struct { + Integer drSigWord; /* volume signature (0x4244 for HFS) */ + LongInt drCrDate; /* date and time of volume creation */ + LongInt drLsMod; /* date and time of last modification */ + Integer drAtrb; /* volume attributes */ + UInteger drNmFls; /* number of files in root directory */ + UInteger drVBMSt; /* first block of volume bit map (always 3) */ + UInteger drAllocPtr; /* start of next allocation search */ + UInteger drNmAlBlks; /* number of allocation blocks in volume */ + ULongInt drAlBlkSiz; /* size (in bytes) of allocation blocks */ + ULongInt drClpSiz; /* default clump size */ + UInteger drAlBlSt; /* first allocation block in volume */ + LongInt drNxtCNID; /* next unused catalog node ID (dir/file ID) */ + UInteger drFreeBks; /* number of unused allocation blocks */ + char drVN[28]; /* volume name (1-27 chars) */ + LongInt drVolBkUp; /* date and time of last backup */ + Integer drVSeqNum; /* volume backup sequence number */ + ULongInt drWrCnt; /* volume write count */ + ULongInt drXTClpSiz; /* clump size for extents overflow file */ + ULongInt drCTClpSiz; /* clump size for catalog file */ + UInteger drNmRtDirs; /* number of directories in root directory */ + ULongInt drFilCnt; /* number of files in volume */ + ULongInt drDirCnt; /* number of directories in volume */ + LongInt drFndrInfo[8]; /* information used by the Finder */ + UInteger drEmbedSigWord; /* type of embedded volume */ + ExtDescriptor drEmbedExtent; /* location of embedded volume */ + ULongInt drXTFlSize; /* size (in bytes) of extents overflow file */ + ExtDataRec drXTExtRec; /* first extent record for extents file */ + ULongInt drCTFlSize; /* size (in bytes) of catalog file */ + ExtDataRec drCTExtRec; /* first extent record for catalog file */ +} MDB; + +typedef enum { + cdrDirRec = 1, + cdrFilRec = 2, + cdrThdRec = 3, + cdrFThdRec = 4 +} CatDataType; + +typedef struct { + SignedByte cdrType; /* record type */ + SignedByte cdrResrv2; /* reserved */ + union { + struct { /* cdrDirRec */ + Integer dirFlags; /* directory flags */ + UInteger dirVal; /* directory valence */ + ULongInt dirDirID; /* directory ID */ + LongInt dirCrDat; /* date and time of creation */ + LongInt dirMdDat; /* date and time of last modification */ + LongInt dirBkDat; /* date and time of last backup */ + DInfo dirUsrInfo; /* Finder information */ + DXInfo dirFndrInfo; /* additional Finder information */ + LongInt dirResrv[4]; /* reserved */ + } dir; + struct { /* cdrFilRec */ + SignedByte + filFlags; /* file flags */ + SignedByte + filTyp; /* file type */ + FInfo filUsrWds; /* Finder information */ + ULongInt filFlNum; /* file ID */ + UInteger filStBlk; /* first alloc block of data fork */ + ULongInt filLgLen; /* logical EOF of data fork */ + ULongInt filPyLen; /* physical EOF of data fork */ + UInteger filRStBlk; /* first alloc block of resource fork */ + ULongInt filRLgLen; /* logical EOF of resource fork */ + ULongInt filRPyLen; /* physical EOF of resource fork */ + LongInt filCrDat; /* date and time of creation */ + LongInt filMdDat; /* date and time of last modification */ + LongInt filBkDat; /* date and time of last backup */ + FXInfo filFndrInfo; /* additional Finder information */ + UInteger filClpSize; /* file clump size */ + ExtDataRec + filExtRec; /* first data fork extent record */ + ExtDataRec + filRExtRec; /* first resource fork extent record */ + LongInt filResrv; /* reserved */ + } fil; + struct { /* cdrThdRec */ + LongInt thdResrv[2]; /* reserved */ + ULongInt thdParID; /* parent ID for this directory */ + Str31 thdCName; /* name of this directory */ + } dthd; + struct { /* cdrFThdRec */ + LongInt fthdResrv[2]; /* reserved */ + ULongInt fthdParID; /* parent ID for this file */ + Str31 fthdCName; /* name of this file */ + } fthd; + } u; +} CatDataRec; + +typedef struct { + ULongInt ndFLink; /* forward link */ + ULongInt ndBLink; /* backward link */ + SignedByte ndType; /* node type */ + SignedByte ndNHeight; /* node level */ + UInteger ndNRecs; /* number of records in node */ + Integer ndResv2; /* reserved */ +} NodeDescriptor; + +enum { + ndIndxNode = (SignedByte) 0x00, + ndHdrNode = (SignedByte) 0x01, + ndMapNode = (SignedByte) 0x02, + ndLeafNode = (SignedByte) 0xff +}; + +typedef struct { + UInteger bthDepth; /* current depth of tree */ + ULongInt bthRoot; /* number of root node */ + ULongInt bthNRecs; /* number of leaf records in tree */ + ULongInt bthFNode; /* number of first leaf node */ + ULongInt bthLNode; /* number of last leaf node */ + UInteger bthNodeSize; /* size of a node */ + UInteger bthKeyLen; /* maximum length of a key */ + ULongInt bthNNodes; /* total number of nodes in tree */ + ULongInt bthFree; /* number of free nodes */ + SignedByte bthResv[76]; /* reserved */ +} BTHdrRec; diff --git a/fs/hfs/include/block.h b/fs/hfs/include/block.h new file mode 100644 index 0000000..fdbc099 --- /dev/null +++ b/fs/hfs/include/block.h @@ -0,0 +1,40 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: block.h,v 1.10 1998/11/02 22:08:53 rob Exp $ + */ + +int b_init(hfsvol *); +int b_flush(hfsvol *); +int b_finish(hfsvol *); + +int b_readpb(hfsvol *, unsigned long, block *, unsigned int); +int b_writepb(hfsvol *, unsigned long, const block *, unsigned int); + +int b_readlb(hfsvol *, unsigned long, block *); +int b_writelb(hfsvol *, unsigned long, const block *); + +int b_readab(hfsvol *, unsigned int, unsigned int, block *); +int b_writeab(hfsvol *, unsigned int, unsigned int, const block *); + +unsigned long b_size(hfsvol *); + +# ifdef DEBUG +void b_showstats(const bcache *); +void b_dumpcache(const bcache *); +# endif diff --git a/fs/hfs/include/btree.h b/fs/hfs/include/btree.h new file mode 100644 index 0000000..b3775a1 --- /dev/null +++ b/fs/hfs/include/btree.h @@ -0,0 +1,33 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: btree.h,v 1.8 1998/11/02 22:08:55 rob Exp $ + */ + +int bt_getnode(node *, btree *, unsigned long); +int bt_putnode(node *); + +int bt_readhdr(btree *); +int bt_writehdr(btree *); + +int bt_space(btree *, unsigned int); + +int bt_insert(btree *, const byte *, unsigned int); +int bt_delete(btree *, const byte *); + +int bt_search(btree *, const byte *, node *); diff --git a/fs/hfs/include/data.h b/fs/hfs/include/data.h new file mode 100644 index 0000000..fd38e75 --- /dev/null +++ b/fs/hfs/include/data.h @@ -0,0 +1,58 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: data.h,v 1.7 1998/11/02 22:08:58 rob Exp $ + */ + +extern const unsigned char hfs_charorder[]; + + signed char d_getsb(register const unsigned char *); +unsigned char d_getub(register const unsigned char *); + signed short d_getsw(register const unsigned char *); +unsigned short d_getuw(register const unsigned char *); + signed long d_getsl(register const unsigned char *); +unsigned long d_getul(register const unsigned char *); + +void d_putsb(register unsigned char *, register signed char); +void d_putub(register unsigned char *, register unsigned char); +void d_putsw(register unsigned char *, register signed short); +void d_putuw(register unsigned char *, register unsigned short); +void d_putsl(register unsigned char *, register signed long); +void d_putul(register unsigned char *, register unsigned long); + +void d_fetchsb(register const unsigned char **, register signed char *); +void d_fetchub(register const unsigned char **, register unsigned char *); +void d_fetchsw(register const unsigned char **, register signed short *); +void d_fetchuw(register const unsigned char **, register unsigned short *); +void d_fetchsl(register const unsigned char **, register signed long *); +void d_fetchul(register const unsigned char **, register unsigned long *); + +void d_storesb(register unsigned char **, register signed char); +void d_storeub(register unsigned char **, register unsigned char); +void d_storesw(register unsigned char **, register signed short); +void d_storeuw(register unsigned char **, register unsigned short); +void d_storesl(register unsigned char **, register signed long); +void d_storeul(register unsigned char **, register unsigned long); + +void d_fetchstr(const unsigned char **, char *, unsigned); +void d_storestr(unsigned char **, const char *, unsigned); + +int d_relstring(const char *, const char *); + +time_t d_ltime(unsigned long); +unsigned long d_mtime(time_t); diff --git a/fs/hfs/include/file.h b/fs/hfs/include/file.h new file mode 100644 index 0000000..8bd66bb --- /dev/null +++ b/fs/hfs/include/file.h @@ -0,0 +1,45 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: file.h,v 1.6 1998/04/11 08:27:12 rob Exp $ + */ + +enum { + fkData = 0x00, + fkRsrc = 0xff +}; + +void f_init(hfsfile *, hfsvol *, long, const char *); +void f_selectfork(hfsfile *, int); +void f_getptrs(hfsfile *, ExtDataRec **, unsigned long **, unsigned long **); + +int f_doblock(hfsfile *, unsigned long, block *, + int (*)(hfsvol *, unsigned int, unsigned int, block *)); + +# define f_getblock(file, num, bp) \ + f_doblock((file), (num), (bp), b_readab) +# define f_putblock(file, num, bp) \ + f_doblock((file), (num), (bp), \ + (int (*)(hfsvol *, unsigned int, unsigned int, block *)) \ + b_writeab) + +int f_addextent(hfsfile *, ExtDescriptor *); +long f_alloc(hfsfile *); + +int f_trunc(hfsfile *); +int f_flush(hfsfile *); diff --git a/fs/hfs/include/hfs.h b/fs/hfs/include/hfs.h new file mode 100644 index 0000000..77d55ae --- /dev/null +++ b/fs/hfs/include/hfs.h @@ -0,0 +1,178 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: hfs.h,v 1.11 1998/11/02 22:09:01 rob Exp $ + */ + +# define HFS_BLOCKSZ 512 +# define HFS_BLOCKSZ_BITS 9 + +# define HFS_MAX_FLEN 31 +# define HFS_MAX_VLEN 27 + +typedef struct _hfsvol_ hfsvol; +typedef struct _hfsfile_ hfsfile; +typedef struct _hfsdir_ hfsdir; + +typedef struct { + char name[HFS_MAX_VLEN + 1]; /* name of volume (MacOS Standard Roman) */ + int flags; /* volume flags */ + + unsigned long totbytes; /* total bytes on volume */ + unsigned long freebytes; /* free bytes on volume */ + + unsigned long alblocksz; /* volume allocation block size */ + unsigned long clumpsz; /* default file clump size */ + + unsigned long numfiles; /* number of files in volume */ + unsigned long numdirs; /* number of directories in volume */ + + time_t crdate; /* volume creation date */ + time_t mddate; /* last volume modification date */ + time_t bkdate; /* last volume backup date */ + + unsigned long blessed; /* CNID of MacOS System Folder */ +} hfsvolent; + +typedef struct { + char name[HFS_MAX_FLEN + 1]; /* catalog name (MacOS Standard Roman) */ + int flags; /* bit flags */ + unsigned long cnid; /* catalog node id (CNID) */ + unsigned long parid; /* CNID of parent directory */ + + time_t crdate; /* date of creation */ + time_t mddate; /* date of last modification */ + time_t bkdate; /* date of last backup */ + + short fdflags; /* Macintosh Finder flags */ + + struct { + signed short v; /* Finder icon vertical coordinate */ + signed short h; /* horizontal coordinate */ + } fdlocation; + + union { + struct { + unsigned long dsize; /* size of data fork */ + unsigned long rsize; /* size of resource fork */ + + char type[5]; /* file type code (plus null) */ + char creator[5]; /* file creator code (plus null) */ + } file; + + struct { + unsigned short valence; /* number of items in directory */ + + struct { + signed short top; /* top edge of folder's rectangle */ + signed short left; /* left edge */ + signed short bottom; /* bottom edge */ + signed short right; /* right edge */ + } rect; + } dir; + } u; +} hfsdirent; + +# define HFS_ISDIR 0x0001 +# define HFS_ISLOCKED 0x0002 + +# define HFS_CNID_ROOTPAR 1 +# define HFS_CNID_ROOTDIR 2 +# define HFS_CNID_EXT 3 +# define HFS_CNID_CAT 4 +# define HFS_CNID_BADALLOC 5 + +# define HFS_FNDR_ISONDESK (1 << 0) +# define HFS_FNDR_COLOR 0x0e +# define HFS_FNDR_COLORRESERVED (1 << 4) +# define HFS_FNDR_REQUIRESSWITCHLAUNCH (1 << 5) +# define HFS_FNDR_ISSHARED (1 << 6) +# define HFS_FNDR_HASNOINITS (1 << 7) +# define HFS_FNDR_HASBEENINITED (1 << 8) +# define HFS_FNDR_RESERVED (1 << 9) +# define HFS_FNDR_HASCUSTOMICON (1 << 10) +# define HFS_FNDR_ISSTATIONERY (1 << 11) +# define HFS_FNDR_NAMELOCKED (1 << 12) +# define HFS_FNDR_HASBUNDLE (1 << 13) +# define HFS_FNDR_ISINVISIBLE (1 << 14) +# define HFS_FNDR_ISALIAS (1 << 15) + +extern const char *hfs_error; +extern const unsigned char hfs_charorder[]; + +# define HFS_MODE_RDONLY 0 +# define HFS_MODE_RDWR 1 +# define HFS_MODE_ANY 2 + +# define HFS_MODE_MASK 0x0003 + +# define HFS_OPT_NOCACHE 0x0100 +# define HFS_OPT_2048 0x0200 +# define HFS_OPT_ZERO 0x0400 + +# define HFS_SEEK_SET 0 +# define HFS_SEEK_CUR 1 +# define HFS_SEEK_END 2 + +hfsvol *hfs_mount( int os_fd, int); +int hfs_flush(hfsvol *); +void hfs_flushall(void); +int hfs_umount(hfsvol *); +void hfs_umountall(void); +hfsvol *hfs_getvol(const char *); +void hfs_setvol(hfsvol *); + +int hfs_vstat(hfsvol *, hfsvolent *); +int hfs_vsetattr(hfsvol *, hfsvolent *); + +int hfs_chdir(hfsvol *, const char *); +unsigned long hfs_getcwd(hfsvol *); +int hfs_setcwd(hfsvol *, unsigned long); +int hfs_dirinfo(hfsvol *, unsigned long *, char *); + +hfsdir *hfs_opendir(hfsvol *, const char *); +int hfs_readdir(hfsdir *, hfsdirent *); +int hfs_closedir(hfsdir *); + +hfsfile *hfs_create(hfsvol *, const char *, const char *, const char *); +hfsfile *hfs_open(hfsvol *, const char *); +int hfs_setfork(hfsfile *, int); +int hfs_getfork(hfsfile *); +unsigned long hfs_read(hfsfile *, void *, unsigned long); +unsigned long hfs_write(hfsfile *, const void *, unsigned long); +int hfs_truncate(hfsfile *, unsigned long); +unsigned long hfs_seek(hfsfile *, long, int); +int hfs_close(hfsfile *); + +int hfs_stat(hfsvol *, const char *, hfsdirent *); +int hfs_fstat(hfsfile *, hfsdirent *); +int hfs_setattr(hfsvol *, const char *, const hfsdirent *); +int hfs_fsetattr(hfsfile *, const hfsdirent *); + +int hfs_mkdir(hfsvol *, const char *); +int hfs_rmdir(hfsvol *, const char *); + +int hfs_delete(hfsvol *, const char *); +int hfs_rename(hfsvol *, const char *, const char *); + +int hfs_zero(const char *, unsigned int, unsigned long *); +int hfs_mkpart(const char *, unsigned long); +int hfs_nparts(const char *); + +int hfs_format(const char *, int, int, + const char *, unsigned int, const unsigned long []); diff --git a/fs/hfs/include/libhfs.h b/fs/hfs/include/libhfs.h new file mode 100644 index 0000000..5fdc471 --- /dev/null +++ b/fs/hfs/include/libhfs.h @@ -0,0 +1,226 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: libhfs.h,v 1.7 1998/11/02 22:09:02 rob Exp $ + */ + +# include "hfs.h" +# include "apple.h" + +extern int errno; + +# define ERROR(code, str) \ + do { hfs_error = (str), errno = (code); goto fail; } while (0) + +# ifdef DEBUG +# define ASSERT(cond) do { if (! (cond)) abort(); } while (0) +# else +# define ASSERT(cond) /* nothing */ +# endif + +# define SIZE(type, n) ((size_t) (sizeof(type) * (n))) +# define ALLOC(type, n) ((type *) malloc(SIZE(type, n))) +# define ALLOCX(type, n) ((n) ? ALLOC(type, n) : (type *) 0) +# define FREE(ptr) ((ptr) ? (void) free((void *) ptr) : (void) 0) + +# define REALLOC(ptr, type, n) \ + ((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n)))) +# define REALLOCX(ptr, type, n) \ + ((n) ? REALLOC(ptr, type, n) : (FREE(ptr), (type *) 0)) + +# define BMTST(bm, num) \ + (((const byte *) (bm))[(num) >> 3] & (0x80 >> ((num) & 0x07))) +# define BMSET(bm, num) \ + (((byte *) (bm))[(num) >> 3] |= (0x80 >> ((num) & 0x07))) +# define BMCLR(bm, num) \ + (((byte *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07))) + +# define STRINGIZE(x) #x +# define STR(x) STRINGIZE(x) + +typedef unsigned char byte; +typedef byte block[HFS_BLOCKSZ]; + +typedef struct _bucket_ { + int flags; /* bit flags */ + unsigned int count; /* number of times this block is requested */ + + unsigned long bnum; /* logical block number */ + block *data; /* pointer to block contents */ + + struct _bucket_ *cnext; /* next bucket in cache chain */ + struct _bucket_ *cprev; /* previous bucket in cache chain */ + + struct _bucket_ *hnext; /* next bucket in hash chain */ + struct _bucket_ **hprev; /* previous bucket's pointer to this bucket */ +} bucket; + +# define HFS_BUCKET_INUSE 0x01 +# define HFS_BUCKET_DIRTY 0x02 + +# define HFS_CACHESZ 128 +# define HFS_HASHSZ 32 +# define HFS_BLOCKBUFSZ 16 + +typedef struct { + struct _hfsvol_ *vol; /* volume to which cache belongs */ + bucket *tail; /* end of bucket chain */ + + unsigned int hits; /* number of cache hits */ + unsigned int misses; /* number of cache misses */ + + bucket chain[HFS_CACHESZ]; /* cache bucket chain */ + bucket *hash[HFS_HASHSZ]; /* hash table for bucket chain */ + + block pool[HFS_CACHESZ]; /* physical blocks in cache */ +} bcache; + +# define HFS_MAP1SZ 256 +# define HFS_MAPXSZ 492 + +# define HFS_NODEREC(nd, rnum) ((nd).data + (nd).roff[rnum]) +# define HFS_RECLEN(nd, rnum) ((nd).roff[(rnum) + 1] - (nd).roff[rnum]) + +# define HFS_RECKEYLEN(ptr) (*(const byte *) (ptr)) +# define HFS_RECKEYSKIP(ptr) ((size_t) ((1 + HFS_RECKEYLEN(ptr) + 1) & ~1)) +# define HFS_RECDATA(ptr) ((ptr) + HFS_RECKEYSKIP(ptr)) + +# define HFS_SETKEYLEN(ptr, x) (*(byte *) (ptr) = (x)) + +# define HFS_CATDATALEN sizeof(CatDataRec) +# define HFS_EXTDATALEN sizeof(ExtDataRec) +# define HFS_MAX_DATALEN (HFS_CATDATALEN > HFS_EXTDATALEN ? \ + HFS_CATDATALEN : HFS_EXTDATALEN) + +# define HFS_CATKEYLEN sizeof(CatKeyRec) +# define HFS_EXTKEYLEN sizeof(ExtKeyRec) +# define HFS_MAX_KEYLEN (HFS_CATKEYLEN > HFS_EXTKEYLEN ? \ + HFS_CATKEYLEN : HFS_EXTKEYLEN) + +# define HFS_MAX_CATRECLEN (HFS_CATKEYLEN + HFS_CATDATALEN) +# define HFS_MAX_EXTRECLEN (HFS_EXTKEYLEN + HFS_EXTDATALEN) +# define HFS_MAX_RECLEN (HFS_MAX_KEYLEN + HFS_MAX_DATALEN) + +# define HFS_SIGWORD 0x4244 +# define HFS_SIGWORD_MFS ((Integer) 0xd2d7) + +# define HFS_ATRB_BUSY (1 << 6) +# define HFS_ATRB_HLOCKED (1 << 7) +# define HFS_ATRB_UMOUNTED (1 << 8) +# define HFS_ATRB_BBSPARED (1 << 9) +# define HFS_ATRB_BVINCONSIS (1 << 11) +# define HFS_ATRB_COPYPROT (1 << 14) +# define HFS_ATRB_SLOCKED (1 << 15) + +struct _hfsfile_ { + struct _hfsvol_ *vol; /* pointer to volume descriptor */ + unsigned long parid; /* parent directory ID of this file */ + char name[HFS_MAX_FLEN + 1]; /* catalog name of this file */ + CatDataRec cat; /* catalog information */ + ExtDataRec ext; /* current extent record */ + unsigned int fabn; /* starting file allocation block number */ + int fork; /* current selected fork for I/O */ + unsigned long pos; /* current file seek pointer */ + int flags; /* bit flags */ + + struct _hfsfile_ *prev; + struct _hfsfile_ *next; +}; + +# define HFS_FILE_UPDATE_CATREC 0x01 + +# define HFS_MAX_NRECS 35 /* maximum based on minimum record size */ + +typedef struct _node_ { + struct _btree_ *bt; /* btree to which this node belongs */ + unsigned long nnum; /* node index */ + NodeDescriptor nd; /* node descriptor */ + int rnum; /* current record index */ + UInteger roff[HFS_MAX_NRECS + 1]; + /* record offsets */ + block data; /* raw contents of node */ +} node; + +struct _hfsdir_ { + struct _hfsvol_ *vol; /* associated volume */ + unsigned long dirid; /* directory ID of interest (or 0) */ + + node n; /* current B*-tree node */ + struct _hfsvol_ *vptr; /* current volume pointer */ + + struct _hfsdir_ *prev; + struct _hfsdir_ *next; +}; + +typedef void (*keyunpackfunc)(const byte *, void *); +typedef int (*keycomparefunc)(const void *, const void *); + +typedef struct _btree_ { + hfsfile f; /* subset file information */ + node hdrnd; /* header node */ + BTHdrRec hdr; /* header record */ + byte *map; /* usage bitmap */ + unsigned long mapsz; /* number of bytes in bitmap */ + int flags; /* bit flags */ + + keyunpackfunc keyunpack; /* key unpacking function */ + keycomparefunc keycompare; /* key comparison function */ +} btree; + +# define HFS_BT_UPDATE_HDR 0x01 + +struct _hfsvol_ { + int os_fd; /* OS-dependent private descriptor data */ + int flags; /* bit flags */ + + int pnum; /* ordinal HFS partition number */ + unsigned long vstart; /* logical block offset to start of volume */ + unsigned long vlen; /* number of logical blocks in volume */ + unsigned int lpa; /* number of logical blocks per allocation block */ + + bcache *cache; /* cache of recently used blocks */ + + MDB mdb; /* master directory block */ + block *vbm; /* volume bitmap */ + unsigned short vbmsz; /* number of blocks in bitmap */ + + btree ext; /* B*-tree control block for extents overflow file */ + btree cat; /* B*-tree control block for catalog file */ + + unsigned long cwd; /* directory id of current working directory */ + + int refs; /* number of external references to this volume */ + hfsfile *files; /* list of open files */ + hfsdir *dirs; /* list of open directories */ + + struct _hfsvol_ *prev; + struct _hfsvol_ *next; +}; + +# define HFS_VOL_OPEN 0x0001 +# define HFS_VOL_MOUNTED 0x0002 +# define HFS_VOL_READONLY 0x0004 +# define HFS_VOL_USINGCACHE 0x0008 + +# define HFS_VOL_UPDATE_MDB 0x0010 +# define HFS_VOL_UPDATE_ALTMDB 0x0020 +# define HFS_VOL_UPDATE_VBM 0x0040 + +# define HFS_VOL_OPT_MASK 0xff00 + +extern hfsvol *hfs_mounts; diff --git a/fs/hfs/include/low.h b/fs/hfs/include/low.h new file mode 100644 index 0000000..03db9bb --- /dev/null +++ b/fs/hfs/include/low.h @@ -0,0 +1,44 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: low.h,v 1.6 1998/04/11 08:27:13 rob Exp $ + */ + +# define HFS_DDR_SIGWORD 0x4552 + +# define HFS_PM_SIGWORD 0x504d +# define HFS_PM_SIGWORD_OLD 0x5453 + +# define HFS_BB_SIGWORD 0x4c4b + +# define HFS_BOOTCODE1LEN (HFS_BLOCKSZ - 148) +# define HFS_BOOTCODE2LEN HFS_BLOCKSZ + +# define HFS_BOOTCODELEN (HFS_BOOTCODE1LEN + HFS_BOOTCODE2LEN) + +int l_getddr(hfsvol *, Block0 *); +int l_putddr(hfsvol *, const Block0 *); + +int l_getpmentry(hfsvol *, Partition *, unsigned long); +int l_putpmentry(hfsvol *, const Partition *, unsigned long); + +int l_getbb(hfsvol *, BootBlkHdr *, byte *); +int l_putbb(hfsvol *, const BootBlkHdr *, const byte *); + +int l_getmdb(hfsvol *, MDB *, int); +int l_putmdb(hfsvol *, const MDB *, int); diff --git a/fs/hfs/include/medium.h b/fs/hfs/include/medium.h new file mode 100644 index 0000000..5580a9e --- /dev/null +++ b/fs/hfs/include/medium.h @@ -0,0 +1,42 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: medium.h,v 1.3 1998/04/11 08:27:13 rob Exp $ + */ + +/* + * Partition Types: + * + * "Apple_partition_map" partition map + * "Apple_Driver" device driver + * "Apple_Driver43" SCSI Manager 4.3 device driver + * "Apple_MFS" Macintosh 64K ROM filesystem + * "Apple_HFS" Macintosh hierarchical filesystem + * "Apple_Unix_SVR2" Unix filesystem + * "Apple_PRODOS" ProDOS filesystem + * "Apple_Free" unused + * "Apple_Scratch" empty + */ + +int m_zeroddr(hfsvol *); + +int m_zeropm(hfsvol *, unsigned int); +int m_findpmentry(hfsvol *, const char *, Partition *, unsigned long *); +int m_mkpart(hfsvol *, const char *, const char *, unsigned long); + +int m_zerobb(hfsvol *); diff --git a/fs/hfs/include/node.h b/fs/hfs/include/node.h new file mode 100644 index 0000000..91287fd --- /dev/null +++ b/fs/hfs/include/node.h @@ -0,0 +1,34 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: node.h,v 1.7 1998/11/02 22:09:06 rob Exp $ + */ + +void n_init(node *, btree *, int, int); + +int n_new(node *); +int n_free(node *); + +int n_search(node *, const byte *); + +void n_index(const node *, byte *, unsigned int *); + +void n_insertx(node *, const byte *, unsigned int); +int n_insert(node *, byte *, unsigned int *); + +int n_delete(node *, byte *, int *); diff --git a/fs/hfs/include/record.h b/fs/hfs/include/record.h new file mode 100644 index 0000000..4959dc8 --- /dev/null +++ b/fs/hfs/include/record.h @@ -0,0 +1,47 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: record.h,v 1.7 1998/11/02 22:09:08 rob Exp $ + */ + +void r_packcatkey(const CatKeyRec *, byte *, unsigned int *); +void r_unpackcatkey(const byte *, CatKeyRec *); + +void r_packextkey(const ExtKeyRec *, byte *, unsigned int *); +void r_unpackextkey(const byte *, ExtKeyRec *); + +int r_comparecatkeys(const CatKeyRec *, const CatKeyRec *); +int r_compareextkeys(const ExtKeyRec *, const ExtKeyRec *); + +void r_packcatdata(const CatDataRec *, byte *, unsigned int *); +void r_unpackcatdata(const byte *, CatDataRec *); + +void r_packextdata(const ExtDataRec *, byte *, unsigned int *); +void r_unpackextdata(const byte *, ExtDataRec *); + +void r_makecatkey(CatKeyRec *, unsigned long, const char *); +void r_makeextkey(ExtKeyRec *, int, unsigned long, unsigned int); + +void r_packcatrec(const CatKeyRec *, const CatDataRec *, + byte *, unsigned int *); +void r_packextrec(const ExtKeyRec *, const ExtDataRec *, + byte *, unsigned int *); + +void r_packdirent(CatDataRec *, const hfsdirent *); +void r_unpackdirent(unsigned long, const char *, + const CatDataRec *, hfsdirent *); diff --git a/fs/hfs/include/volume.h b/fs/hfs/include/volume.h new file mode 100644 index 0000000..2ac41d1 --- /dev/null +++ b/fs/hfs/include/volume.h @@ -0,0 +1,68 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: volume.h,v 1.7 1998/11/02 22:09:12 rob Exp $ + */ + +#ifndef _H_VOLUME +#define _H_VOLUME + +void v_init(hfsvol *, int); + +int v_open(hfsvol *, int os_fd); +int v_flush(hfsvol *); +int v_close(hfsvol *); + +int v_same(hfsvol *, int os_fd); +int v_geometry(hfsvol *, int); + +int v_readmdb(hfsvol *); +int v_writemdb(hfsvol *); + +int v_readvbm(hfsvol *); +int v_writevbm(hfsvol *); + +int v_mount(hfsvol *); +int v_dirty(hfsvol *); + +int v_catsearch(hfsvol *, unsigned long, const char *, + CatDataRec *, char *, node *); +int v_extsearch(hfsfile *, unsigned int, ExtDataRec *, node *); + +int v_getthread(hfsvol *, unsigned long, CatDataRec *, node *, int); + +# define v_getdthread(vol, id, thread, np) \ + v_getthread(vol, id, thread, np, cdrThdRec) +# define v_getfthread(vol, id, thread, np) \ + v_getthread(vol, id, thread, np, cdrFThdRec) + +int v_putcatrec(const CatDataRec *, node *); +int v_putextrec(const ExtDataRec *, node *); + +int v_allocblocks(hfsvol *, ExtDescriptor *); +int v_freeblocks(hfsvol *, const ExtDescriptor *); + +int v_resolve(hfsvol **, const char *, CatDataRec *, long *, char *, node *); + +int v_adjvalence(hfsvol *, unsigned long, int, int); +int v_mkdir(hfsvol *, unsigned long, const char *); + +int v_scavenge(hfsvol *); + + +#endif /* _H_VOLUME */ diff --git a/fs/hfs/low.c b/fs/hfs/low.c new file mode 100644 index 0000000..7bfc55b --- /dev/null +++ b/fs/hfs/low.c @@ -0,0 +1,157 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998, 2001 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: low.c,v 1.8 1998/11/02 22:09:03 rob Exp $ + */ + +#include "openbios/config.h" +#include "libhfs.h" +#include "low.h" +#include "data.h" +#include "block.h" +#include "file.h" + +/* + * NAME: low->getpmentry() + * DESCRIPTION: read a partition map entry + */ +int l_getpmentry(hfsvol *vol, Partition *map, unsigned long bnum) +{ + block b; + const byte *ptr = b; + int i; + + if (b_readpb(vol, bnum, &b, 1) == -1) + goto fail; + + d_fetchsw(&ptr, &map->pmSig); + d_fetchsw(&ptr, &map->pmSigPad); + d_fetchsl(&ptr, &map->pmMapBlkCnt); + d_fetchsl(&ptr, &map->pmPyPartStart); + d_fetchsl(&ptr, &map->pmPartBlkCnt); + + strncpy((char *) map->pmPartName, (const char *) ptr, 32); + map->pmPartName[32] = 0; + ptr += 32; + + strncpy((char *) map->pmParType, (const char *) ptr, 32); + map->pmParType[32] = 0; + ptr += 32; + + d_fetchsl(&ptr, &map->pmLgDataStart); + d_fetchsl(&ptr, &map->pmDataCnt); + d_fetchsl(&ptr, &map->pmPartStatus); + d_fetchsl(&ptr, &map->pmLgBootStart); + d_fetchsl(&ptr, &map->pmBootSize); + d_fetchsl(&ptr, &map->pmBootAddr); + d_fetchsl(&ptr, &map->pmBootAddr2); + d_fetchsl(&ptr, &map->pmBootEntry); + d_fetchsl(&ptr, &map->pmBootEntry2); + d_fetchsl(&ptr, &map->pmBootCksum); + + strncpy((char *) map->pmProcessor, (const char *) ptr, 16); + map->pmProcessor[16] = 0; + ptr += 16; + + for (i = 0; i < 188; ++i) + d_fetchsw(&ptr, &map->pmPad[i]); + + ASSERT(ptr - b == HFS_BLOCKSZ); + + return 0; + +fail: + return -1; +} + + +/* + * NAME: low->getmdb() + * DESCRIPTION: read a master directory block + */ +int l_getmdb(hfsvol *vol, MDB *mdb, int backup) +{ + block b; + const byte *ptr = b; + int i; + + if (b_readlb(vol, backup ? vol->vlen - 2 : 2, &b) == -1) + goto fail; + + d_fetchsw(&ptr, &mdb->drSigWord); + d_fetchsl(&ptr, &mdb->drCrDate); + d_fetchsl(&ptr, &mdb->drLsMod); + d_fetchsw(&ptr, &mdb->drAtrb); + d_fetchuw(&ptr, &mdb->drNmFls); + d_fetchuw(&ptr, &mdb->drVBMSt); + d_fetchuw(&ptr, &mdb->drAllocPtr); + d_fetchuw(&ptr, &mdb->drNmAlBlks); + d_fetchul(&ptr, &mdb->drAlBlkSiz); + d_fetchul(&ptr, &mdb->drClpSiz); + d_fetchuw(&ptr, &mdb->drAlBlSt); + d_fetchsl(&ptr, &mdb->drNxtCNID); + d_fetchuw(&ptr, &mdb->drFreeBks); + + d_fetchstr(&ptr, mdb->drVN, sizeof(mdb->drVN)); + + ASSERT(ptr - b == 64); + + d_fetchsl(&ptr, &mdb->drVolBkUp); + d_fetchsw(&ptr, &mdb->drVSeqNum); + d_fetchul(&ptr, &mdb->drWrCnt); + d_fetchul(&ptr, &mdb->drXTClpSiz); + d_fetchul(&ptr, &mdb->drCTClpSiz); + d_fetchuw(&ptr, &mdb->drNmRtDirs); + d_fetchul(&ptr, &mdb->drFilCnt); + d_fetchul(&ptr, &mdb->drDirCnt); + + for (i = 0; i < 8; ++i) + d_fetchsl(&ptr, &mdb->drFndrInfo[i]); + + ASSERT(ptr - b == 124); + + d_fetchuw(&ptr, &mdb->drEmbedSigWord); + d_fetchuw(&ptr, &mdb->drEmbedExtent.xdrStABN); + d_fetchuw(&ptr, &mdb->drEmbedExtent.xdrNumABlks); + + d_fetchul(&ptr, &mdb->drXTFlSize); + + for (i = 0; i < 3; ++i) + { + d_fetchuw(&ptr, &mdb->drXTExtRec[i].xdrStABN); + d_fetchuw(&ptr, &mdb->drXTExtRec[i].xdrNumABlks); + } + + ASSERT(ptr - b == 146); + + d_fetchul(&ptr, &mdb->drCTFlSize); + + for (i = 0; i < 3; ++i) + { + d_fetchuw(&ptr, &mdb->drCTExtRec[i].xdrStABN); + d_fetchuw(&ptr, &mdb->drCTExtRec[i].xdrNumABlks); + } + + ASSERT(ptr - b == 162); + + return 0; + +fail: + return -1; +} + diff --git a/fs/hfs/medium.c b/fs/hfs/medium.c new file mode 100644 index 0000000..0e74aab --- /dev/null +++ b/fs/hfs/medium.c @@ -0,0 +1,84 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: medium.c,v 1.4 1998/11/02 22:09:04 rob Exp $ + */ + +#include "openbios/config.h" +#include "libhfs.h" +#include "block.h" +#include "low.h" +#include "medium.h" + + +/* + * NAME: medium->findpmentry() + * DESCRIPTION: locate a partition map entry + */ +int m_findpmentry(hfsvol *vol, const char *type, + Partition *map, unsigned long *start) +{ + unsigned long bnum; + int found = 0; + + if (start && *start > 0) + { + bnum = *start; + + if (bnum++ >= (unsigned long) map->pmMapBlkCnt) + ERROR(EINVAL, "partition not found"); + } + else + bnum = 1; + + while (1) + { + if (l_getpmentry(vol, map, bnum) == -1) + { + found = -1; + goto fail; + } + + if (map->pmSig != HFS_PM_SIGWORD) + { + found = -1; + + if (map->pmSig == HFS_PM_SIGWORD_OLD) + ERROR(EINVAL, "old partition map format not supported"); + else + ERROR(EINVAL, "invalid partition map"); + } + + if (strcmp((char *) map->pmParType, type) == 0) + { + found = 1; + goto done; + } + + if (bnum++ >= (unsigned long) map->pmMapBlkCnt) + ERROR(EINVAL, "partition not found"); + } + +done: + if (start) + *start = bnum; + +fail: + return found; +} + diff --git a/fs/hfs/node.c b/fs/hfs/node.c new file mode 100644 index 0000000..5f90cf7 --- /dev/null +++ b/fs/hfs/node.c @@ -0,0 +1,59 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: node.c,v 1.9 1998/11/02 22:09:05 rob Exp $ + */ + +#include "openbios/config.h" +#include "libhfs.h" +#include "node.h" +#include "data.h" +#include "btree.h" + +/* + * NAME: node->search() + * DESCRIPTION: locate a record in a node, or the record it should follow + */ +int n_search(node *np, const byte *pkey) +{ + const btree *bt = np->bt; + byte key1[HFS_MAX_KEYLEN], key2[HFS_MAX_KEYLEN]; + int i, comp = -1; + + bt->keyunpack(pkey, key2); + + for (i = np->nd.ndNRecs; i--; ) + { + const byte *rec; + + rec = HFS_NODEREC(*np, i); + + if (HFS_RECKEYLEN(rec) == 0) + continue; /* deleted record */ + + bt->keyunpack(rec, key1); + comp = bt->keycompare(key1, key2); + + if (comp <= 0) + break; + } + + np->rnum = i; + + return comp == 0; +} diff --git a/fs/hfs/record.c b/fs/hfs/record.c new file mode 100644 index 0000000..aeb6602 --- /dev/null +++ b/fs/hfs/record.c @@ -0,0 +1,552 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: record.c,v 1.9 1998/11/02 22:09:07 rob Exp $ + */ + +#include "openbios/config.h" +#include "libhfs.h" +#include "record.h" +#include "data.h" + +/* + * NAME: record->packcatkey() + * DESCRIPTION: pack a catalog record key + */ +void r_packcatkey(const CatKeyRec *key, byte *pkey, unsigned int *len) +{ + const byte *start = pkey; + + d_storesb(&pkey, key->ckrKeyLen); + d_storesb(&pkey, key->ckrResrv1); + d_storeul(&pkey, key->ckrParID); + + d_storestr(&pkey, key->ckrCName, sizeof(key->ckrCName)); + + if (len) + *len = HFS_RECKEYSKIP(start); +} + +/* + * NAME: record->unpackcatkey() + * DESCRIPTION: unpack a catalog record key + */ +void r_unpackcatkey(const byte *pkey, CatKeyRec *key) +{ + d_fetchsb(&pkey, &key->ckrKeyLen); + d_fetchsb(&pkey, &key->ckrResrv1); + d_fetchul(&pkey, &key->ckrParID); + + d_fetchstr(&pkey, key->ckrCName, sizeof(key->ckrCName)); +} + +/* + * NAME: record->packextkey() + * DESCRIPTION: pack an extents record key + */ +void r_packextkey(const ExtKeyRec *key, byte *pkey, unsigned int *len) +{ + const byte *start = pkey; + + d_storesb(&pkey, key->xkrKeyLen); + d_storesb(&pkey, key->xkrFkType); + d_storeul(&pkey, key->xkrFNum); + d_storeuw(&pkey, key->xkrFABN); + + if (len) + *len = HFS_RECKEYSKIP(start); +} + +/* + * NAME: record->unpackextkey() + * DESCRIPTION: unpack an extents record key + */ +void r_unpackextkey(const byte *pkey, ExtKeyRec *key) +{ + d_fetchsb(&pkey, &key->xkrKeyLen); + d_fetchsb(&pkey, &key->xkrFkType); + d_fetchul(&pkey, &key->xkrFNum); + d_fetchuw(&pkey, &key->xkrFABN); +} + +/* + * NAME: record->comparecatkeys() + * DESCRIPTION: compare two (packed) catalog record keys + */ +int r_comparecatkeys(const CatKeyRec *key1, const CatKeyRec *key2) +{ + int diff; + + diff = key1->ckrParID - key2->ckrParID; + if (diff) + return diff; + + return d_relstring(key1->ckrCName, key2->ckrCName); +} + +/* + * NAME: record->compareextkeys() + * DESCRIPTION: compare two (packed) extents record keys + */ +int r_compareextkeys(const ExtKeyRec *key1, const ExtKeyRec *key2) +{ + int diff; + + diff = key1->xkrFNum - key2->xkrFNum; + if (diff) + return diff; + + diff = (unsigned char) key1->xkrFkType - + (unsigned char) key2->xkrFkType; + if (diff) + return diff; + + return key1->xkrFABN - key2->xkrFABN; +} + +/* + * NAME: record->packcatdata() + * DESCRIPTION: pack catalog record data + */ +void r_packcatdata(const CatDataRec *data, byte *pdata, unsigned int *len) +{ + const byte *start = pdata; + int i; + + d_storesb(&pdata, data->cdrType); + d_storesb(&pdata, data->cdrResrv2); + + switch (data->cdrType) + { + case cdrDirRec: + d_storesw(&pdata, data->u.dir.dirFlags); + d_storeuw(&pdata, data->u.dir.dirVal); + d_storeul(&pdata, data->u.dir.dirDirID); + d_storesl(&pdata, data->u.dir.dirCrDat); + d_storesl(&pdata, data->u.dir.dirMdDat); + d_storesl(&pdata, data->u.dir.dirBkDat); + + d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.top); + d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.left); + d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.bottom); + d_storesw(&pdata, data->u.dir.dirUsrInfo.frRect.right); + d_storesw(&pdata, data->u.dir.dirUsrInfo.frFlags); + d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.v); + d_storesw(&pdata, data->u.dir.dirUsrInfo.frLocation.h); + d_storesw(&pdata, data->u.dir.dirUsrInfo.frView); + + d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.v); + d_storesw(&pdata, data->u.dir.dirFndrInfo.frScroll.h); + d_storesl(&pdata, data->u.dir.dirFndrInfo.frOpenChain); + d_storesw(&pdata, data->u.dir.dirFndrInfo.frUnused); + d_storesw(&pdata, data->u.dir.dirFndrInfo.frComment); + d_storesl(&pdata, data->u.dir.dirFndrInfo.frPutAway); + + for (i = 0; i < 4; ++i) + d_storesl(&pdata, data->u.dir.dirResrv[i]); + + break; + + case cdrFilRec: + d_storesb(&pdata, data->u.fil.filFlags); + d_storesb(&pdata, data->u.fil.filTyp); + + d_storesl(&pdata, data->u.fil.filUsrWds.fdType); + d_storesl(&pdata, data->u.fil.filUsrWds.fdCreator); + d_storesw(&pdata, data->u.fil.filUsrWds.fdFlags); + d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.v); + d_storesw(&pdata, data->u.fil.filUsrWds.fdLocation.h); + d_storesw(&pdata, data->u.fil.filUsrWds.fdFldr); + + d_storeul(&pdata, data->u.fil.filFlNum); + + d_storeuw(&pdata, data->u.fil.filStBlk); + d_storeul(&pdata, data->u.fil.filLgLen); + d_storeul(&pdata, data->u.fil.filPyLen); + + d_storeuw(&pdata, data->u.fil.filRStBlk); + d_storeul(&pdata, data->u.fil.filRLgLen); + d_storeul(&pdata, data->u.fil.filRPyLen); + + d_storesl(&pdata, data->u.fil.filCrDat); + d_storesl(&pdata, data->u.fil.filMdDat); + d_storesl(&pdata, data->u.fil.filBkDat); + + d_storesw(&pdata, data->u.fil.filFndrInfo.fdIconID); + for (i = 0; i < 4; ++i) + d_storesw(&pdata, data->u.fil.filFndrInfo.fdUnused[i]); + d_storesw(&pdata, data->u.fil.filFndrInfo.fdComment); + d_storesl(&pdata, data->u.fil.filFndrInfo.fdPutAway); + + d_storeuw(&pdata, data->u.fil.filClpSize); + + for (i = 0; i < 3; ++i) + { + d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrStABN); + d_storeuw(&pdata, data->u.fil.filExtRec[i].xdrNumABlks); + } + + for (i = 0; i < 3; ++i) + { + d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrStABN); + d_storeuw(&pdata, data->u.fil.filRExtRec[i].xdrNumABlks); + } + + d_storesl(&pdata, data->u.fil.filResrv); + + break; + + case cdrThdRec: + for (i = 0; i < 2; ++i) + d_storesl(&pdata, data->u.dthd.thdResrv[i]); + + d_storeul(&pdata, data->u.dthd.thdParID); + + d_storestr(&pdata, data->u.dthd.thdCName, + sizeof(data->u.dthd.thdCName)); + + break; + + case cdrFThdRec: + for (i = 0; i < 2; ++i) + d_storesl(&pdata, data->u.fthd.fthdResrv[i]); + + d_storeul(&pdata, data->u.fthd.fthdParID); + + d_storestr(&pdata, data->u.fthd.fthdCName, + sizeof(data->u.fthd.fthdCName)); + + break; + + default: + ASSERT(0); + } + + if (len) + *len += pdata - start; +} + +/* + * NAME: record->unpackcatdata() + * DESCRIPTION: unpack catalog record data + */ +void r_unpackcatdata(const byte *pdata, CatDataRec *data) +{ + int i; + + d_fetchsb(&pdata, &data->cdrType); + d_fetchsb(&pdata, &data->cdrResrv2); + + switch (data->cdrType) + { + case cdrDirRec: + d_fetchsw(&pdata, &data->u.dir.dirFlags); + d_fetchuw(&pdata, &data->u.dir.dirVal); + d_fetchul(&pdata, &data->u.dir.dirDirID); + d_fetchsl(&pdata, &data->u.dir.dirCrDat); + d_fetchsl(&pdata, &data->u.dir.dirMdDat); + d_fetchsl(&pdata, &data->u.dir.dirBkDat); + + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.top); + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.left); + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.bottom); + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frRect.right); + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frFlags); + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.v); + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frLocation.h); + d_fetchsw(&pdata, &data->u.dir.dirUsrInfo.frView); + + d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.v); + d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frScroll.h); + d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frOpenChain); + d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frUnused); + d_fetchsw(&pdata, &data->u.dir.dirFndrInfo.frComment); + d_fetchsl(&pdata, &data->u.dir.dirFndrInfo.frPutAway); + + for (i = 0; i < 4; ++i) + d_fetchsl(&pdata, &data->u.dir.dirResrv[i]); + + break; + + case cdrFilRec: + d_fetchsb(&pdata, &data->u.fil.filFlags); + d_fetchsb(&pdata, &data->u.fil.filTyp); + + d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdType); + d_fetchsl(&pdata, &data->u.fil.filUsrWds.fdCreator); + d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFlags); + d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.v); + d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdLocation.h); + d_fetchsw(&pdata, &data->u.fil.filUsrWds.fdFldr); + + d_fetchul(&pdata, &data->u.fil.filFlNum); + + d_fetchuw(&pdata, &data->u.fil.filStBlk); + d_fetchul(&pdata, &data->u.fil.filLgLen); + d_fetchul(&pdata, &data->u.fil.filPyLen); + + d_fetchuw(&pdata, &data->u.fil.filRStBlk); + d_fetchul(&pdata, &data->u.fil.filRLgLen); + d_fetchul(&pdata, &data->u.fil.filRPyLen); + + d_fetchsl(&pdata, &data->u.fil.filCrDat); + d_fetchsl(&pdata, &data->u.fil.filMdDat); + d_fetchsl(&pdata, &data->u.fil.filBkDat); + + d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdIconID); + for (i = 0; i < 4; ++i) + d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdUnused[i]); + d_fetchsw(&pdata, &data->u.fil.filFndrInfo.fdComment); + d_fetchsl(&pdata, &data->u.fil.filFndrInfo.fdPutAway); + + d_fetchuw(&pdata, &data->u.fil.filClpSize); + + for (i = 0; i < 3; ++i) + { + d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrStABN); + d_fetchuw(&pdata, &data->u.fil.filExtRec[i].xdrNumABlks); + } + + for (i = 0; i < 3; ++i) + { + d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrStABN); + d_fetchuw(&pdata, &data->u.fil.filRExtRec[i].xdrNumABlks); + } + + d_fetchsl(&pdata, &data->u.fil.filResrv); + + break; + + case cdrThdRec: + for (i = 0; i < 2; ++i) + d_fetchsl(&pdata, &data->u.dthd.thdResrv[i]); + + d_fetchul(&pdata, &data->u.dthd.thdParID); + + d_fetchstr(&pdata, data->u.dthd.thdCName, + sizeof(data->u.dthd.thdCName)); + + break; + + case cdrFThdRec: + for (i = 0; i < 2; ++i) + d_fetchsl(&pdata, &data->u.fthd.fthdResrv[i]); + + d_fetchul(&pdata, &data->u.fthd.fthdParID); + + d_fetchstr(&pdata, data->u.fthd.fthdCName, + sizeof(data->u.fthd.fthdCName)); + + break; + + default: + ASSERT(0); + } +} + +/* + * NAME: record->packextdata() + * DESCRIPTION: pack extent record data + */ +void r_packextdata(const ExtDataRec *data, byte *pdata, unsigned int *len) +{ + const byte *start = pdata; + int i; + + for (i = 0; i < 3; ++i) + { + d_storeuw(&pdata, (*data)[i].xdrStABN); + d_storeuw(&pdata, (*data)[i].xdrNumABlks); + } + + if (len) + *len += pdata - start; +} + +/* + * NAME: record->unpackextdata() + * DESCRIPTION: unpack extent record data + */ +void r_unpackextdata(const byte *pdata, ExtDataRec *data) +{ + int i; + + for (i = 0; i < 3; ++i) + { + d_fetchuw(&pdata, &(*data)[i].xdrStABN); + d_fetchuw(&pdata, &(*data)[i].xdrNumABlks); + } +} + +/* + * NAME: record->makecatkey() + * DESCRIPTION: construct a catalog record key + */ +void r_makecatkey(CatKeyRec *key, unsigned long parid, const char *name) +{ + int len; + + len = strlen(name) + 1; + + key->ckrKeyLen = 0x05 + len + (len & 1); + key->ckrResrv1 = 0; + key->ckrParID = parid; + + strcpy(key->ckrCName, name); +} + +/* + * NAME: record->makeextkey() + * DESCRIPTION: construct an extents record key + */ +void r_makeextkey(ExtKeyRec *key, + int fork, unsigned long fnum, unsigned int fabn) +{ + key->xkrKeyLen = 0x07; + key->xkrFkType = fork; + key->xkrFNum = fnum; + key->xkrFABN = fabn; +} + +/* + * NAME: record->packcatrec() + * DESCRIPTION: create a packed catalog record + */ +void r_packcatrec(const CatKeyRec *key, const CatDataRec *data, + byte *precord, unsigned int *len) +{ + r_packcatkey(key, precord, len); + r_packcatdata(data, HFS_RECDATA(precord), len); +} + +/* + * NAME: record->packextrec() + * DESCRIPTION: create a packed extents record + */ +void r_packextrec(const ExtKeyRec *key, const ExtDataRec *data, + byte *precord, unsigned int *len) +{ + r_packextkey(key, precord, len); + r_packextdata(data, HFS_RECDATA(precord), len); +} + +/* + * NAME: record->packdirent() + * DESCRIPTION: make changes to a catalog record + */ +void r_packdirent(CatDataRec *data, const hfsdirent *ent) +{ + switch (data->cdrType) + { + case cdrDirRec: + data->u.dir.dirCrDat = d_mtime(ent->crdate); + data->u.dir.dirMdDat = d_mtime(ent->mddate); + data->u.dir.dirBkDat = d_mtime(ent->bkdate); + + data->u.dir.dirUsrInfo.frFlags = ent->fdflags; + data->u.dir.dirUsrInfo.frLocation.v = ent->fdlocation.v; + data->u.dir.dirUsrInfo.frLocation.h = ent->fdlocation.h; + + data->u.dir.dirUsrInfo.frRect.top = ent->u.dir.rect.top; + data->u.dir.dirUsrInfo.frRect.left = ent->u.dir.rect.left; + data->u.dir.dirUsrInfo.frRect.bottom = ent->u.dir.rect.bottom; + data->u.dir.dirUsrInfo.frRect.right = ent->u.dir.rect.right; + + break; + + case cdrFilRec: + if (ent->flags & HFS_ISLOCKED) + data->u.fil.filFlags |= (1 << 0); + else + data->u.fil.filFlags &= ~(1 << 0); + + data->u.fil.filCrDat = d_mtime(ent->crdate); + data->u.fil.filMdDat = d_mtime(ent->mddate); + data->u.fil.filBkDat = d_mtime(ent->bkdate); + + data->u.fil.filUsrWds.fdFlags = ent->fdflags; + data->u.fil.filUsrWds.fdLocation.v = ent->fdlocation.v; + data->u.fil.filUsrWds.fdLocation.h = ent->fdlocation.h; + + data->u.fil.filUsrWds.fdType = + d_getsl((const unsigned char *) ent->u.file.type); + data->u.fil.filUsrWds.fdCreator = + d_getsl((const unsigned char *) ent->u.file.creator); + + break; + } +} + +/* + * NAME: record->unpackdirent() + * DESCRIPTION: unpack catalog information into hfsdirent structure + */ +void r_unpackdirent(unsigned long parid, const char *name, + const CatDataRec *data, hfsdirent *ent) +{ + strcpy(ent->name, name); + ent->parid = parid; + + switch (data->cdrType) + { + case cdrDirRec: + ent->flags = HFS_ISDIR; + ent->cnid = data->u.dir.dirDirID; + + ent->crdate = d_ltime(data->u.dir.dirCrDat); + ent->mddate = d_ltime(data->u.dir.dirMdDat); + ent->bkdate = d_ltime(data->u.dir.dirBkDat); + + ent->fdflags = data->u.dir.dirUsrInfo.frFlags; + ent->fdlocation.v = data->u.dir.dirUsrInfo.frLocation.v; + ent->fdlocation.h = data->u.dir.dirUsrInfo.frLocation.h; + + ent->u.dir.valence = data->u.dir.dirVal; + + ent->u.dir.rect.top = data->u.dir.dirUsrInfo.frRect.top; + ent->u.dir.rect.left = data->u.dir.dirUsrInfo.frRect.left; + ent->u.dir.rect.bottom = data->u.dir.dirUsrInfo.frRect.bottom; + ent->u.dir.rect.right = data->u.dir.dirUsrInfo.frRect.right; + + break; + + case cdrFilRec: + ent->flags = (data->u.fil.filFlags & (1 << 0)) ? HFS_ISLOCKED : 0; + ent->cnid = data->u.fil.filFlNum; + + ent->crdate = d_ltime(data->u.fil.filCrDat); + ent->mddate = d_ltime(data->u.fil.filMdDat); + ent->bkdate = d_ltime(data->u.fil.filBkDat); + + ent->fdflags = data->u.fil.filUsrWds.fdFlags; + ent->fdlocation.v = data->u.fil.filUsrWds.fdLocation.v; + ent->fdlocation.h = data->u.fil.filUsrWds.fdLocation.h; + + ent->u.file.dsize = data->u.fil.filLgLen; + ent->u.file.rsize = data->u.fil.filRLgLen; + + d_putsl((unsigned char *) ent->u.file.type, + data->u.fil.filUsrWds.fdType); + d_putsl((unsigned char *) ent->u.file.creator, + data->u.fil.filUsrWds.fdCreator); + + ent->u.file.type[4] = ent->u.file.creator[4] = 0; + + break; + } +} diff --git a/fs/hfs/volume.c b/fs/hfs/volume.c new file mode 100644 index 0000000..052397c --- /dev/null +++ b/fs/hfs/volume.c @@ -0,0 +1,592 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: volume.c,v 1.12 1998/11/02 22:09:10 rob Exp $ + */ + +#include "openbios/config.h" +#include "libhfs.h" +#include "volume.h" +#include "data.h" +#include "block.h" +#include "low.h" +#include "medium.h" +#include "file.h" +#include "btree.h" +#include "record.h" +#include "os.h" + +/* + * NAME: vol->init() + * DESCRIPTION: initialize volume structure + */ +void v_init(hfsvol *vol, int flags) +{ + btree *ext = &vol->ext; + btree *cat = &vol->cat; + + vol->os_fd = 0; + vol->flags = flags & HFS_VOL_OPT_MASK; + + vol->pnum = -1; + vol->vstart = 0; + vol->vlen = 0; + vol->lpa = 0; + + vol->cache = 0; + + vol->vbm = 0; + vol->vbmsz = 0; + + f_init(&ext->f, vol, HFS_CNID_EXT, "extents overflow"); + + ext->map = 0; + ext->mapsz = 0; + ext->flags = 0; + + ext->keyunpack = (keyunpackfunc) r_unpackextkey; + ext->keycompare = (keycomparefunc) r_compareextkeys; + + f_init(&cat->f, vol, HFS_CNID_CAT, "catalog"); + + cat->map = 0; + cat->mapsz = 0; + cat->flags = 0; + + cat->keyunpack = (keyunpackfunc) r_unpackcatkey; + cat->keycompare = (keycomparefunc) r_comparecatkeys; + + vol->cwd = HFS_CNID_ROOTDIR; + + vol->refs = 0; + vol->files = 0; + vol->dirs = 0; + + vol->prev = 0; + vol->next = 0; +} + +/* + * NAME: vol->open() + * DESCRIPTION: open volume source and lock against concurrent updates + */ +int v_open(hfsvol *vol, int os_fd ) +{ + if (vol->flags & HFS_VOL_OPEN) + ERROR(EINVAL, "volume already open"); + + vol->flags |= HFS_VOL_OPEN; + vol->os_fd = os_fd; + + /* initialize volume block cache (OK to fail) */ + + if (! (vol->flags & HFS_OPT_NOCACHE) && + b_init(vol) != -1) + vol->flags |= HFS_VOL_USINGCACHE; + + return 0; + +fail: + return -1; +} + +/* + * NAME: vol->close() + * DESCRIPTION: close access path to volume source + */ +int v_close(hfsvol *vol) +{ + int result = 0; + + if (! (vol->flags & HFS_VOL_OPEN)) + goto done; + + if ((vol->flags & HFS_VOL_USINGCACHE) && + b_finish(vol) == -1) + result = -1; + + vol->flags &= ~(HFS_VOL_OPEN | HFS_VOL_MOUNTED | HFS_VOL_USINGCACHE); + + /* free dynamically allocated structures */ + + FREE(vol->vbm); + + vol->vbm = 0; + vol->vbmsz = 0; + + FREE(vol->ext.map); + FREE(vol->cat.map); + + vol->ext.map = 0; + vol->cat.map = 0; + +done: + return result; +} + +/* + * NAME: vol->same() + * DESCRIPTION: return 1 iff path is same as open volume + */ +int v_same(hfsvol *vol, int os_fd ) +{ + return vol->os_fd == os_fd; +} + +/* + * NAME: vol->geometry() + * DESCRIPTION: determine volume location and size (possibly in a partition) + */ +int v_geometry(hfsvol *vol, int pnum) +{ + Partition map; + unsigned long bnum = 0; + int found; + + vol->pnum = pnum; + + if (pnum == 0) + { + vol->vstart = 0; + vol->vlen = b_size(vol); + + if (vol->vlen == 0) + goto fail; + } + else + { + while (pnum--) + { + found = m_findpmentry(vol, "Apple_HFS", &map, &bnum); + if (found == -1 || ! found) + goto fail; + } + + vol->vstart = map.pmPyPartStart; + vol->vlen = map.pmPartBlkCnt; + + if (map.pmDataCnt) + { + if ((unsigned long) map.pmLgDataStart + + (unsigned long) map.pmDataCnt > vol->vlen) + ERROR(EINVAL, "partition data overflows partition"); + + vol->vstart += (unsigned long) map.pmLgDataStart; + vol->vlen = map.pmDataCnt; + } + + if (vol->vlen == 0) + ERROR(EINVAL, "volume partition is empty"); + } + + if (vol->vlen < 800 * (1024 >> HFS_BLOCKSZ_BITS)) + ERROR(EINVAL, "volume is smaller than 800K"); + + return 0; + +fail: + return -1; +} + +/* + * NAME: vol->readmdb() + * DESCRIPTION: load Master Directory Block into memory + */ +int v_readmdb(hfsvol *vol) +{ + if (l_getmdb(vol, &vol->mdb, 0) == -1) + goto fail; + + if (vol->mdb.drSigWord != HFS_SIGWORD) + { + if (vol->mdb.drSigWord == HFS_SIGWORD_MFS) + ERROR(EINVAL, "MFS volume format not supported"); + else + ERROR(EINVAL, "not a Macintosh HFS volume"); + } + + if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0) + ERROR(EINVAL, "bad volume allocation block size"); + + vol->lpa = vol->mdb.drAlBlkSiz >> HFS_BLOCKSZ_BITS; + + /* extents pseudo-file structs */ + + vol->ext.f.cat.u.fil.filStBlk = vol->mdb.drXTExtRec[0].xdrStABN; + vol->ext.f.cat.u.fil.filLgLen = vol->mdb.drXTFlSize; + vol->ext.f.cat.u.fil.filPyLen = vol->mdb.drXTFlSize; + + vol->ext.f.cat.u.fil.filCrDat = vol->mdb.drCrDate; + vol->ext.f.cat.u.fil.filMdDat = vol->mdb.drLsMod; + + memcpy(&vol->ext.f.cat.u.fil.filExtRec, + &vol->mdb.drXTExtRec, sizeof(ExtDataRec)); + + f_selectfork(&vol->ext.f, fkData); + + /* catalog pseudo-file structs */ + + vol->cat.f.cat.u.fil.filStBlk = vol->mdb.drCTExtRec[0].xdrStABN; + vol->cat.f.cat.u.fil.filLgLen = vol->mdb.drCTFlSize; + vol->cat.f.cat.u.fil.filPyLen = vol->mdb.drCTFlSize; + + vol->cat.f.cat.u.fil.filCrDat = vol->mdb.drCrDate; + vol->cat.f.cat.u.fil.filMdDat = vol->mdb.drLsMod; + + memcpy(&vol->cat.f.cat.u.fil.filExtRec, + &vol->mdb.drCTExtRec, sizeof(ExtDataRec)); + + f_selectfork(&vol->cat.f, fkData); + + return 0; + +fail: + return -1; +} + +/* + * NAME: vol->readvbm() + * DESCRIPTION: read volume bitmap into memory + */ +int v_readvbm(hfsvol *vol) +{ + unsigned int vbmst = vol->mdb.drVBMSt; + unsigned int vbmsz = (vol->mdb.drNmAlBlks + 0x0fff) >> 12; + block *bp; + + ASSERT(vol->vbm == 0); + + if (vol->mdb.drAlBlSt - vbmst < vbmsz) + ERROR(EIO, "volume bitmap collides with volume data"); + + vol->vbm = ALLOC(block, vbmsz); + if (vol->vbm == 0) + ERROR(ENOMEM, 0); + + vol->vbmsz = vbmsz; + + for (bp = vol->vbm; vbmsz--; ++bp) + { + if (b_readlb(vol, vbmst++, bp) == -1) + goto fail; + } + + return 0; + +fail: + FREE(vol->vbm); + + vol->vbm = 0; + vol->vbmsz = 0; + + return -1; +} + +/* + * NAME: vol->mount() + * DESCRIPTION: load volume information into memory + */ +int v_mount(hfsvol *vol) +{ + /* read the MDB, volume bitmap, and extents/catalog B*-tree headers */ + + if (v_readmdb(vol) == -1 || + v_readvbm(vol) == -1 || + bt_readhdr(&vol->ext) == -1 || + bt_readhdr(&vol->cat) == -1) + goto fail; + + if (vol->mdb.drAtrb & HFS_ATRB_SLOCKED) + vol->flags |= HFS_VOL_READONLY; + else if (vol->flags & HFS_VOL_READONLY) + vol->mdb.drAtrb |= HFS_ATRB_HLOCKED; + else + vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED; + + vol->flags |= HFS_VOL_MOUNTED; + + return 0; + +fail: + return -1; +} + +/* + * NAME: vol->catsearch() + * DESCRIPTION: search catalog tree + */ +int v_catsearch(hfsvol *vol, unsigned long parid, const char *name, + CatDataRec *data, char *cname, node *np) +{ + CatKeyRec key; + byte pkey[HFS_CATKEYLEN]; + const byte *ptr; + node n; + int found; + + if (np == 0) + np = &n; + + r_makecatkey(&key, parid, name); + r_packcatkey(&key, pkey, 0); + + found = bt_search(&vol->cat, pkey, np); + if (found <= 0) + return found; + + ptr = HFS_NODEREC(*np, np->rnum); + + if (cname) + { + r_unpackcatkey(ptr, &key); + strcpy(cname, key.ckrCName); + } + + if (data) + r_unpackcatdata(HFS_RECDATA(ptr), data); + + return 1; +} + +/* + * NAME: vol->extsearch() + * DESCRIPTION: search extents tree + */ +int v_extsearch(hfsfile *file, unsigned int fabn, + ExtDataRec *data, node *np) +{ + ExtKeyRec key; + ExtDataRec extsave; + unsigned int fabnsave; + byte pkey[HFS_EXTKEYLEN]; + const byte *ptr; + node n; + int found; + + if (np == 0) + np = &n; + + r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn); + r_packextkey(&key, pkey, 0); + + /* in case bt_search() clobbers these */ + + memcpy(&extsave, &file->ext, sizeof(ExtDataRec)); + fabnsave = file->fabn; + + found = bt_search(&file->vol->ext, pkey, np); + + memcpy(&file->ext, &extsave, sizeof(ExtDataRec)); + file->fabn = fabnsave; + + if (found <= 0) + return found; + + if (data) + { + ptr = HFS_NODEREC(*np, np->rnum); + r_unpackextdata(HFS_RECDATA(ptr), data); + } + + return 1; +} + +/* + * NAME: vol->getthread() + * DESCRIPTION: retrieve catalog thread information for a file or directory + */ +int v_getthread(hfsvol *vol, unsigned long id, + CatDataRec *thread, node *np, int type) +{ + CatDataRec rec; + int found; + + if (thread == 0) + thread = &rec; + + found = v_catsearch(vol, id, "", thread, 0, np); + if (found == 1 && thread->cdrType != type) + ERROR(EIO, "bad thread record"); + + return found; + +fail: + return -1; +} + + +/* + * NAME: vol->resolve() + * DESCRIPTION: translate a pathname; return catalog information + */ +int v_resolve(hfsvol **vol, const char *path, + CatDataRec *data, long *parid, char *fname, node *np) +{ + unsigned long dirid; + char name[HFS_MAX_FLEN + 1], *nptr; + int found = 0; + + if (*path == 0) + ERROR(ENOENT, "empty path"); + + if (parid) + *parid = 0; + + nptr = strchr(path, ':'); + + if (*path == ':' || nptr == 0) + { + dirid = (*vol)->cwd; /* relative path */ + + if (*path == ':') + ++path; + + if (*path == 0) + { + found = v_getdthread(*vol, dirid, data, 0); + if (found == -1) + goto fail; + + if (found) + { + if (parid) + *parid = data->u.dthd.thdParID; + + found = v_catsearch(*vol, data->u.dthd.thdParID, + data->u.dthd.thdCName, data, fname, np); + if (found == -1) + goto fail; + } + + goto done; + } + } + else + { + hfsvol *check; + + dirid = HFS_CNID_ROOTPAR; /* absolute path */ + + if (nptr - path > HFS_MAX_VLEN) + ERROR(ENAMETOOLONG, 0); + + strncpy(name, path, nptr - path); + name[nptr - path] = 0; + + for (check = hfs_mounts; check; check = check->next) + { + if (d_relstring(check->mdb.drVN, name) == 0) + { + *vol = check; + break; + } + } + } + + while (1) + { + while (*path == ':') + { + ++path; + + found = v_getdthread(*vol, dirid, data, 0); + if (found == -1) + goto fail; + else if (! found) + goto done; + + dirid = data->u.dthd.thdParID; + } + + if (*path == 0) + { + found = v_getdthread(*vol, dirid, data, 0); + if (found == -1) + goto fail; + + if (found) + { + if (parid) + *parid = data->u.dthd.thdParID; + + found = v_catsearch(*vol, data->u.dthd.thdParID, + data->u.dthd.thdCName, data, fname, np); + if (found == -1) + goto fail; + } + + goto done; + } + + nptr = name; + while (nptr < name + sizeof(name) - 1 && *path && *path != ':') + *nptr++ = *path++; + + if (*path && *path != ':') + ERROR(ENAMETOOLONG, 0); + + *nptr = 0; + if (*path == ':') + ++path; + + if (parid) + *parid = dirid; + + found = v_catsearch(*vol, dirid, name, data, fname, np); + if (found == -1) + goto fail; + + if (! found) + { + if (*path && parid) + *parid = 0; + + if (*path == 0 && fname) + strcpy(fname, name); + + goto done; + } + + switch (data->cdrType) + { + case cdrDirRec: + if (*path == 0) + goto done; + + dirid = data->u.dir.dirDirID; + break; + + case cdrFilRec: + if (*path == 0) + goto done; + + ERROR(ENOTDIR, "invalid pathname"); + + default: + ERROR(EIO, "unexpected catalog record"); + } + } + +done: + return found; + +fail: + return -1; +} + + diff --git a/fs/hfs_mdb.h b/fs/hfs_mdb.h new file mode 100644 index 0000000..3fcff14 --- /dev/null +++ b/fs/hfs_mdb.h @@ -0,0 +1,110 @@ +/* + * Creation Date: <2000/09/03 23:04:27 samuel> + * Time-stamp: <2000/09/04 01:23:55 samuel> + * + * + * + * HFS Master Directory Block (MDB) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_HFS_MDB +#define _H_HFS_MDB + +typedef unsigned char hfs_char_t; +typedef unsigned char hfs_ushort_t[2]; +typedef unsigned char hfs_uint_t[4]; + +#define hfs_get_ushort(addr) (*((unsigned short*)(addr))) +#define hfs_get_uint(addr) (*((unsigned int*)(addr))) + +/* + * The HFS Master Directory Block (MDB). + * + * Also known as the Volume Information Block (VIB), this structure is + * the HFS equivalent of a superblock. + * + * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62 + * + * modified for HFS Extended + */ + +typedef struct hfs_mdb { + hfs_ushort_t drSigWord; /* Signature word indicating fs type */ + hfs_uint_t drCrDate; /* fs creation date/time */ + hfs_uint_t drLsMod; /* fs modification date/time */ + hfs_ushort_t drAtrb; /* fs attributes */ + hfs_ushort_t drNmFls; /* number of files in root directory */ + hfs_ushort_t drVBMSt; /* location (in 512-byte blocks) + of the volume bitmap */ + hfs_ushort_t drAllocPtr; /* location (in allocation blocks) + to begin next allocation search */ + hfs_ushort_t drNmAlBlks; /* number of allocation blocks */ + hfs_uint_t drAlBlkSiz; /* bytes in an allocation block */ + hfs_uint_t drClpSiz; /* clumpsize, the number of bytes to + allocate when extending a file */ + hfs_ushort_t drAlBlSt; /* location (in 512-byte blocks) + of the first allocation block */ + hfs_uint_t drNxtCNID; /* CNID to assign to the next + file or directory created */ + hfs_ushort_t drFreeBks; /* number of free allocation blocks */ + hfs_char_t drVN[28]; /* the volume label */ + hfs_uint_t drVolBkUp; /* fs backup date/time */ + hfs_ushort_t drVSeqNum; /* backup sequence number */ + hfs_uint_t drWrCnt; /* fs write count */ + hfs_uint_t drXTClpSiz; /* clumpsize for the extents B-tree */ + hfs_uint_t drCTClpSiz; /* clumpsize for the catalog B-tree */ + hfs_ushort_t drNmRtDirs; /* number of directories in + the root directory */ + hfs_uint_t drFilCnt; /* number of files in the fs */ + hfs_uint_t drDirCnt; /* number of directories in the fs */ + hfs_char_t drFndrInfo[32]; /* data used by the Finder */ + hfs_ushort_t drEmbedSigWord; /* embedded volume signature */ + hfs_uint_t drEmbedExtent; /* starting block number (xdrStABN) + and number of allocation blocks + (xdrNumABlks) occupied by embedded + volume */ + hfs_uint_t drXTFlSize; /* bytes in the extents B-tree */ + hfs_char_t drXTExtRec[12]; /* extents B-tree's first 3 extents */ + hfs_uint_t drCTFlSize; /* bytes in the catalog B-tree */ + hfs_char_t drCTExtRec[12]; /* catalog B-tree's first 3 extents */ +} hfs_mdb_t; + +#define HFS_PLUS_SIGNATURE 0x482b /* 'H+' */ +#define HFS_SIGNATURE 0x4244 /* HFS / embedded HFS+ */ + + +typedef struct hfs_plus_mdb +{ + ushort signature; + ushort version; + uint attributes; + uint lastMountedVersion; + uint reserved; + + uint createDate; + uint modifyDate; + uint backupDate; + uint checkedDate; + + uint fileCount; + uint folderCount; + + uint blockSize; + uint totalBlocks; + uint freeBlocks; + + uint nextAllocation; + uint rsrcClumpSize; + uint dataClumpSize; + + /* ... there are more fields here ... */ +} hfs_plus_mdb_t; + + +#endif /* _H_HFS_MDB */ + diff --git a/fs/hfsplus/blockiter.c b/fs/hfsplus/blockiter.c new file mode 100644 index 0000000..83836df --- /dev/null +++ b/fs/hfsplus/blockiter.c @@ -0,0 +1,141 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * The iterator shown here iterates over the blocks of a fork. + * + * Copyright (C) 2000 Klaus Halfmann + * Original work by 1996-1998 Robert Leslie + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: blockiter.c,v 1.2 2000/10/17 05:58:46 hasi Exp $ + */ + +#include "openbios/config.h" +#include "libhfsp.h" +#include "blockiter.h" +#include "volume.h" +#include "record.h" +#include "btree.h" +#include "os.h" +#include "swab.h" +#include "hfstime.h" + +/* Initialize iterator for a given fork */ +void +blockiter_init(blockiter* b, volume* vol, hfsp_fork_raw* f, + UInt8 forktype, UInt32 fileId) +{ + b->vol = vol; + b->curr_block = 0; + b->block = 0; + b->max_block = f->total_blocks; + b->fileId = fileId; + b->index = 0; + b->file = f->extents; + b->e = f->extents; + b->forktype = forktype; + b->in_extent = 0; +} + +/* get next extent record when needed */ +static int +blockiter_next_extent(blockiter *b) +{ + btree* extents_tree = volume_get_extents_tree(b->vol); + int err; + + b->index = 0; + if (b->in_extent) // already using extents record ? + { + err = record_next_extent(&b->er); + // Hope there is no need to check this ... + // if (b->er.key.start_block != b->curr_block) + // HFSP_ERROR(ENOENT, + // "Extents record inconistent"); + } + else + { + err = record_init_file(&b->er, extents_tree, b->forktype, + b->fileId, b->curr_block); + b->in_extent = -1; // true + } + b->e = b->er.extent; + return err; +} + +/* find next block of the fork iterating over */ +int +blockiter_next(blockiter *b) +{ + b->curr_block ++; + b->block ++; + if (b->curr_block >= b->max_block) + return -1; // end of Blocks, but no error + // in current part of extent ? + if (b->block >= b->e->block_count) + { + b->index++; + b->block = 0; // reset relative position + b->e++; + if (b -> index >= 8) // need to fetch another extent + { + if (blockiter_next_extent(b)) + HFSP_ERROR(ENOENT, "Extends record not found."); + } + } + return 0; + + fail: + return -1; +} + +/* skip the indicated number of blocks */ +int +blockiter_skip(blockiter *b, UInt32 skip) +{ + while (skip > 0) + { + // Skip to skip or end of current extent + UInt32 diff = b->e->block_count - b->block; + if (skip < diff) + { + diff = skip; + skip = 0; + } + else + skip -= diff; + b->curr_block += diff; + b->block += diff; + if (b->curr_block >= b->max_block) + return -1; // end of Blocks, but no error + if (b->block >= b->e->block_count) + { + b->index++; + b->block = 0; // reset relative position + b->e++; + if (b -> index >= 8) // need to fetch another extent + { + if (blockiter_next_extent(b)) + HFSP_ERROR(ENOENT, "Extends record not found."); + } + } + } // we are here when skip was null, thats ok + return 0; + fail: + return -1; +} + diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c new file mode 100644 index 0000000..096f9f8 --- /dev/null +++ b/fs/hfsplus/btree.c @@ -0,0 +1,376 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * Copyright (C) 2000 Klaus Halfmann + * Original 1996-1998 Robert Leslie + * Additional work by Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: btree.c,v 1.14 2000/10/25 05:43:04 hasi Exp $ + */ + +#include "openbios/config.h" +#include "libhfsp.h" +#include "volume.h" +#include "btree.h" +#include "record.h" +#include "swab.h" + +/* Read the node from the given buffer and swap the bytes. + * + * return pointer after reading the structure + */ +static void* btree_readnode(btree* bt, btree_node_desc* node, void *p) +{ + node->next = bswabU32_inc(p); + node->prev = bswabU32_inc(p); + node->kind = bswabU8_inc(p); + node->height = bswabU8_inc(p); + node->num_rec = bswabU16_inc(p); + node->reserved = bswabU16_inc(p); + return p; +} + +/* read a btree header from the given buffer and swap the bytes. + * + * return pointer after reading the structure + */ +static void* btree_readhead(btree* bt, btree_head* head, void *p) +{ + head->depth = bswabU16_inc(p); + head->root = bswabU32_inc(p); + head->leaf_count = bswabU32_inc(p); + head->leaf_head = bswabU32_inc(p); + head->leaf_tail = bswabU32_inc(p); + head->node_size = bswabU16_inc(p); + head->max_key_len = bswabU16_inc(p); + head->node_count = bswabU32_inc(p); + head->free_nodes = bswabU32_inc(p); + head->reserved1 = bswabU16_inc(p); + head->clump_size = bswabU32_inc(p); + head->btree_type = bswabU8_inc(p); + head->reserved2 = bswabU8_inc(p); + head->attributes = bswabU32_inc(p); + // skip reserved bytes + ((UInt32*) p) += 16; + return p; +} + +/* Priority of the depth of the node compared to LRU value. + * Should be the average number of keys per node but these vary. */ +#define DEPTH_FACTOR 1000 + +/* Cache size is height of tree + this value + * Really big numbers wont help in case of ls -R + */ +#define EXTRA_CACHESIZE 3 + +/* Not in use by now ... */ +#define CACHE_DIRTY 0x0001 + +/* Intialize cache with default cache Size, + * must call node_cache_close to deallocate memory */ +static int node_cache_init(node_cache* cache, btree* tree, int size) +{ + int nodebufsize; + char * buf; + + cache->size = size; + cache->currindex = 0; + nodebufsize = tree->head.node_size + sizeof(node_buf); + buf = malloc(size *(sizeof(node_entry) + nodebufsize)); + if (!buf) + return -1; + cache -> nodebufsize = nodebufsize; + cache -> entries = (node_entry*) buf; + cache -> buffers = (char*) &cache->entries[size]; + bzero(cache->entries, size*sizeof(node_entry)); + return 0; +} + +/* Like cache->buffers[i], since size of node_buf is variable */ +static inline node_buf* node_buf_get(node_cache* cache, int i) +{ + return (node_buf*) (cache->buffers + (i * cache->nodebufsize)); +} + +/* flush the cache NYI */ +static void node_cache_flush(node_cache* cache) +{ + // NYI +} + +/* flush the node at index */ +static void node_cache_flush_node(node_cache* cache, int index) +{ + // NYI + cache -> entries[index].index = 0; // invalidate entry +} + +static void node_cache_close(node_cache* cache) +{ + if (!cache->entries) // not (fully) intialized ? + return; + node_cache_flush(cache); + free(cache->entries); +} + +/* Load the cach node indentified by index with + * the node identified by node_index */ + +static node_buf* node_cache_load_buf + (btree* bt, node_cache* cache, int index, UInt16 node_index) +{ + node_buf *result = node_buf_get(cache ,index); + UInt32 blkpernode = bt->blkpernode; + UInt32 block = node_index * blkpernode; + void* p = volume_readfromfork(bt->vol, result->node, bt->fork, + block, blkpernode, HFSP_EXTENT_DATA, bt->cnid); + node_entry *e = &cache->entries[index]; + + if (!p) + return NULL; // evil ... + + result->index = node_index; + btree_readnode(bt, &result->desc, p); + + e -> priority = result->desc.height * DEPTH_FACTOR; + e -> index = node_index; + return result; +} + +/* Read node at given index, using cache. + */ +node_buf* btree_node_by_index(btree* bt, UInt16 index) +{ + node_cache* cache = &bt->cache; + int oldindex, lruindex; + int currindex = cache->currindex; + UInt32 prio; + node_entry *e; + + // Shortcut acces to current node, will not change priorities + if (cache->entries[currindex].index == index) + return node_buf_get(cache ,currindex); + oldindex = currindex; + if (currindex == 0) + currindex = cache->size; + currindex--; + lruindex = oldindex; // entry to be flushed when needed + prio = 0; // current priority + while (currindex != oldindex) // round robin + { + e = &cache->entries[currindex]; + if (e->index == index) // got it + { + if (e->priority != 0) // already top, uuh + e->priority--; + cache->currindex = currindex; + return node_buf_get(cache ,currindex); + } + else + { + if (!e->index) + { + lruindex = currindex; + break; // empty entry, load it + } + if (e->priority != UINT_MAX) // already least, uuh + e->priority++; + } + if (prio < e->priority) + { + lruindex = currindex; + prio = e->priority; + } + if (currindex == 0) + currindex = cache->size; + currindex--; + } + e = &cache->entries[lruindex]; + cache->currindex = lruindex; + if (e->flags & CACHE_DIRTY) + node_cache_flush_node( cache, lruindex); + return node_cache_load_buf (bt, cache, lruindex, index); +} + +/** intialize the btree with the first entry in the fork */ +static int btree_init(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ + void *p; + char buf[vol->blksize]; + UInt16 node_size; + btree_node_desc node; + + bt->vol = vol; + bt->fork = fork; + p = volume_readfromfork(vol, buf, fork, 0, 1, + HFSP_EXTENT_DATA, bt->cnid); + if (!p) + return -1; + p = btree_readnode(bt, &node, p); + if (node.kind != HFSP_NODE_HEAD) + return -1; // should not happen ? + p = btree_readhead(bt, &bt->head, p); + + node_size = bt->head.node_size; + bt->blkpernode = node_size / vol->blksize; + + if (bt->blkpernode == 0 || vol->blksize * + bt->blkpernode != node_size) + return -1; // should never happen ... + + node_cache_init(&bt->cache, bt, bt->head.depth + EXTRA_CACHESIZE); + + // Allocate buffer + // bt->buf = malloc(node_size); + // if (!bt->buf) + // return ENOMEM; + + return 0; +} + +/** Intialize catalog btree, so that btree_close can safely be called. */ +void btree_reset(btree* bt) +{ + bt->cache.entries = NULL; +} + +/** Intialize catalog btree */ +int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ + int result = btree_init(bt,vol,fork); // super (...) + bt->cnid = HFSP_CAT_CNID; + bt->kcomp = record_key_compare; + bt->kread = record_readkey; + return result; +} + +/** Intialize catalog btree */ +int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ + int result = btree_init(bt,vol,fork); // super (...) + bt->cnid = HFSP_EXT_CNID; + bt->kcomp = record_extent_key_compare; + bt->kread = record_extent_readkey; + return result; +} + +/** close the btree and free any resources */ +void btree_close(btree* bt) +{ + node_cache_close(&bt->cache); + // free(bt->buf); +} + +/* returns pointer to key given by index in current node. + * + * Assumes that current node is not NODE_HEAD ... + */ +void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index) +{ + UInt16 node_size = bt->head.node_size; + // The offsets are found at the end of the node ... + UInt16 off_pos = node_size - (index +1) * sizeof(btree_record_offset); + // position of offset at end of node + btree_record_offset* offset = + (btree_record_offset*) (buf->node + off_pos); + + // now we have the offset and can read the key ... +#ifdef CONFIG_LITTLE_ENDIAN + return buf->node + bswap_16(*offset); +#else + return buf->node + *offset; +#endif +} + + +#ifdef DEBUG + +/* print btree header node information */ +void btree_printhead(btree_head* head) +{ + UInt32 attr; + printf(" depth : %#X\n", head->depth); + printf(" root : %#lX\n", head->root); + printf(" leaf_count : %#lX\n", head->leaf_count); + printf(" leaf_head : %#lX\n", head->leaf_head); + printf(" leaf_tail : %#lX\n", head->leaf_tail); + printf(" node_size : %#X\n", head->node_size); + printf(" max_key_len : %#X\n", head->max_key_len); + printf(" node_count : %#lX\n", head->node_count); + printf(" free_nodes : %#lX\n", head->free_nodes); + printf(" reserved1 : %#X\n", head->reserved1); + printf(" clump_size : %#lX\n", head->clump_size); + printf(" btree_type : %#X\n", head->btree_type); + attr = head->attributes; + printf(" reserved2 : %#X\n", head->reserved2); + if (attr & HFSPLUS_BAD_CLOSE) + printf(" HFSPLUS_BAD_CLOSE *** "); + else + printf(" !HFSPLUS_BAD_CLOSE"); + if (attr & HFSPLUS_TREE_BIGKEYS) + printf(" HFSPLUS_TREE_BIGKEYS "); + else + printf(" !HFSPLUS_TREE_BIGKEYS"); + if (attr & HFSPLUS_TREE_VAR_NDXKEY_SIZE) + printf(" HFSPLUS_TREE_VAR_NDXKEY_SIZE"); + else + printf(" !HFSPLUS_TREE_VAR_NDXKEY_SIZE"); + if (attr & HFSPLUS_TREE_UNUSED) + printf(" HFSPLUS_TREE_UNUSED ***\n"); + printf("\n"); +} + +/* Dump all the node information to stdout */ +void btree_print(btree* bt) +{ + btree_node_desc* node; + + btree_printhead(&bt->head); + + node = &bt->node; + printf("next : %#lX\n", node->next); + printf("prev : %#lX\n", node->prev); + printf("height : %#X\n", node->height); + printf("num_rec : %#X\n", node->num_rec); + printf("reserved : %#X\n", node->reserved); + printf("height : %#X\n", node->height); switch(node->kind) + { + case HFSP_NODE_NDX : + printf("HFSP_NODE_NDX\n"); + break; + case HFSP_NODE_HEAD : + printf("HFSP_NODE_HEAD\n"); + break; + case HFSP_NODE_MAP : + printf("HFSP_NODE_MAP\n"); + break; + case HFSP_NODE_LEAF : + printf("HFSP_NODE_LEAF\n"); + break; + default: + printf("*** Unknown Node type ***\n"); + } +} + +#endif + diff --git a/fs/hfsplus/build.xml b/fs/hfsplus/build.xml new file mode 100644 index 0000000..4f2604d --- /dev/null +++ b/fs/hfsplus/build.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/fs/hfsplus/hfsp_fs.c b/fs/hfsplus/hfsp_fs.c new file mode 100644 index 0000000..0f510ab --- /dev/null +++ b/fs/hfsplus/hfsp_fs.c @@ -0,0 +1,397 @@ +/* + * Creation Date: <2001/05/05 23:33:49 samuel> + * Time-stamp: <2004/01/12 10:25:39 samuel> + * + * + * + * HFS+ file system interface (and ROM lookup support) + * + * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/fs.h" +#include "libhfsp.h" +#include "volume.h" +#include "record.h" +#include "unicode.h" +#include "blockiter.h" + + +#define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */ +#define MAC_OS_ROM_TYPE 0x74627869 /* 'tbxi' */ +#define MAC_OS_ROM_NAME "Mac OS ROM" + +#define FINDER_TYPE 0x464E4452 /* 'FNDR' */ +#define FINDER_CREATOR 0x4D414353 /* 'MACS' */ +#define SYSTEM_TYPE 0x7A737973 /* 'zsys' */ +#define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */ + + +typedef struct { + record rec; + char *path; + + off_t pos; +} hfsp_file_t; + + +/************************************************************************/ +/* Search implementation */ +/************************************************************************/ + +typedef int (*match_proc_t)( record *r, record *parent, const void *match_data, hfsp_file_t *pt ); + +static int +search_files( record *par, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt ) +{ + hfsp_file_t t; + record r; + int ret = 1; + + t.path = NULL; + + record_init_parent( &r, par ); + do{ + if( r.record.type == HFSP_FOLDER || r.record.type == HFSP_FILE ) + ret = (*proc)( &r, par, match_data, &t ); + + if( ret && r.record.type == HFSP_FOLDER && recursive ) + ret = search_files( &r, 1, proc, match_data, &t ); + + } while( ret && !record_next(&r) ); + + if( !ret && pt ) { + char name[256], *s2 = t.path ? t.path : ""; + unicode_uni2asc( name, &r.key.name, sizeof(name)); + + pt->rec = t.rec; + pt->path = malloc( strlen(name) + strlen(s2) + 2 ); + strcpy( pt->path, name ); + if( strlen(s2) ) { + strcat( pt->path, "\\" ); + strcat( pt->path, s2 ); + } + } + + if( t.path ) + free( t.path ); + + return ret; +} + +static int +root_search_files( fs_ops_t *fs, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt ) +{ + volume *vol = (volume*)fs->fs_data; + record r; + + record_init_root( &r, &vol->catalog ); + return search_files( &r, recursive, proc, match_data, pt ); +} + +static int +match_file( record *r, record *parent, const void *match_data, hfsp_file_t *pt ) +{ + unsigned char *p = (char*)match_data; + char name[256]; + int ret=1; + + if( r->record.type != HFSP_FILE ) + return 1; + + (void) unicode_uni2asc(name, &r->key.name, sizeof(name)); + if( !(ret=strcasecmp(p, name)) && pt ) + pt->rec = *r; + + return ret; +} + +static int +match_rom( record *r, record *par, const void *match_data, hfsp_file_t *pt ) +{ + hfsp_cat_file *file = &r->record.u.file; + FInfo *fi = &file->user_info; + int ret = 1; + char buf[256]; + + if( r->record.type == HFSP_FILE && fi->fdCreator == MAC_OS_ROM_CREATOR && fi->fdType == MAC_OS_ROM_TYPE ) { + ret = search_files( par, 0, match_file, "System", NULL ) + || search_files( par, 0, match_file, "Finder", NULL ); + + (void) unicode_uni2asc(buf, &r->key.name, sizeof(buf)); + if( !strcasecmp("BootX", buf) ) + return 1; + + if( !ret && pt ) + pt->rec = *r; + } + return ret; +} + +static int +match_path( record *r, record *par, const void *match_data, hfsp_file_t *pt ) +{ + char name[256], *s, *next, *org; + int ret=1; + + next = org = strdup( (char*)match_data ); + while( (s=strsep( &next, "\\/" )) && !strlen(s) ) + ; + if( !s ) { + free( org ); + return 1; + } + + if( *s == ':' && strlen(s) == 5 ) { + if( r->record.type == HFSP_FILE && !next ) { + /* match type */ + hfsp_cat_file *file = &r->record.u.file; + FInfo *fi = &file->user_info; + int i, type=0; + for( i=1; s[i] && i<=4; i++ ) + type = (type << 8) | s[i]; + /* printk("fi->fdType: %s / %s\n", s+1, b ); */ + if( fi->fdType == type ) { + if( pt ) + pt->rec = *r; + ret = 0; + } + } + } else { + (void) unicode_uni2asc(name, &r->key.name, sizeof(name)); + + if( !strcasecmp(s, name) ) { + if( r->record.type == HFSP_FILE && !next ) { + if( pt ) + pt->rec = *r; + ret = 0; + } else /* must be a directory */ + ret = search_files( r, 0, match_path, next, pt ); + } + } + free( org ); + return ret; +} + + +/************************************************************************/ +/* File System Operations */ +/************************************************************************/ + +static void +close_fs( fs_ops_t *fs ) +{ + volume *vol = (volume*)fs->fs_data; + volume_close( vol ); + free( vol ); +} + +static file_desc_t * +_create_fops( hfsp_file_t *t ) +{ + hfsp_file_t *r = malloc( sizeof(hfsp_file_t) ); + + *r = *t; + r->pos = 0; + return (file_desc_t*)r; +} + +static file_desc_t * +open_path( fs_ops_t *fs, const char *path ) +{ + hfsp_file_t t; + volume *vol = (volume*)fs->fs_data; + record r; + + /* Leading \\ means system folder. The finder info block has + * the following meaning. + * + * [0] Prefered boot directory ID + * [3] MacOS 9 boot directory ID + * [5] MacOS X boot directory ID + */ + if( !strncmp(path, "\\\\", 2) ) { + int *p = (int*)&vol->vol.finder_info[0]; + int cnid = p[0]; + /* printk(" p[0] = %x, p[3] = %x, p[5] = %x\n", p[0], p[3], p[5] ); */ + if( p[0] == p[5] && p[3] ) + cnid = p[3]; + if( record_init_cnid(&r, &vol->catalog, cnid) ) + return NULL; + path += 2; + } else { + record_init_root( &r, &vol->catalog ); + } + + if( !search_files(&r, 0, match_path, path, &t) ) + return _create_fops( &t ); + return NULL; +} + +static file_desc_t * +search_rom( fs_ops_t *fs ) +{ + hfsp_file_t t; + + if( !root_search_files(fs, 1, match_rom, NULL, &t) ) + return _create_fops( &t ); + return NULL; +} + +static file_desc_t * +search_file( fs_ops_t *fs, const char *name ) +{ + hfsp_file_t t; + + if( !root_search_files(fs, 1, match_file, name, &t) ) + return _create_fops( &t ); + return NULL; +} + + +/************************************************************************/ +/* File Operations */ +/************************************************************************/ + +static char * +get_path( file_desc_t *fd, char *buf, int len ) +{ + hfsp_file_t *t = (hfsp_file_t*)fd; + if( !t->path ) + return NULL; + + strncpy( buf, t->path, len ); + buf[len-1] = 0; + return buf; +} + +static void +file_close( file_desc_t *fd ) +{ + hfsp_file_t *t = (hfsp_file_t*)fd; + if( t->path ) + free( t->path ); + free( t ); +} + +static int +file_lseek( file_desc_t *fd, off_t offs, int whence ) +{ + hfsp_file_t *t = (hfsp_file_t*)fd; + hfsp_cat_file *file = &t->rec.record.u.file; + int total = file->data_fork.total_size; + + switch( whence ){ + case SEEK_CUR: + t->pos += offs; + break; + case SEEK_END: + t->pos = total + offs; + break; + default: + case SEEK_SET: + t->pos = offs; + break; + } + + if( t->pos < 0 ) + t->pos = 0; + + if( t->pos > total ) + t->pos = total; + + return t->pos; +} + +static int +file_read( file_desc_t *fd, void *buf, size_t count ) +{ + hfsp_file_t *t = (hfsp_file_t*)fd; + volume *vol = t->rec.tree->vol; + UInt32 blksize = vol->blksize; + hfsp_cat_file *file = &t->rec.record.u.file; + blockiter iter; + char buf2[blksize]; + int act_count, curpos=0; + + blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id ); + while( curpos + blksize < t->pos ) { + if( blockiter_next( &iter ) ) + return -1; + curpos += blksize; + } + act_count = 0; + + while( act_count < count ){ + UInt32 block = blockiter_curr(&iter); + int max = blksize, add = 0, size; + + if( volume_readinbuf( vol, buf2, block ) ) + break; + + if( curpos < t->pos ){ + add += t->pos - curpos; + max -= t->pos - curpos; + } + size = (count-act_count > max)? max : count-act_count; + memcpy( buf + act_count, &buf2[add], size ); + + curpos += blksize; + act_count += size; + + if( blockiter_next( &iter ) ) + break; + } + + t->pos += act_count; + return (act_count > 0)? act_count : -1; +} + +static char * +vol_name( fs_ops_t *fs, char *buf, int size ) +{ + return get_hfs_vol_name( fs->fd, buf, size ); +} + +static char * +get_fstype( fs_ops_t *fs ) +{ + return ("HFS+"); +} + + +static fs_ops_t fs_ops = { + .close_fs = close_fs, + .open_path = open_path, + .search_rom = search_rom, + .search_file = search_file, + .vol_name = vol_name, + + .get_path = get_path, + .close = file_close, + .read = file_read, + .lseek = file_lseek, + + .get_fstype = get_fstype +}; + +int +fs_hfsp_open( int os_fd, fs_ops_t *fs ) +{ + volume *vol = malloc( sizeof(volume) ); + + if( volume_open(vol, os_fd) ) { + free( vol ); + return -1; + } + *fs = fs_ops; + fs->fs_data = vol; + + return 0; +} diff --git a/fs/hfsplus/include/apple.h b/fs/hfsplus/include/apple.h new file mode 100644 index 0000000..76f3271 --- /dev/null +++ b/fs/hfsplus/include/apple.h @@ -0,0 +1,111 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes + * + * This file contains defintions that are special for Apple. + * The names match the defintions found in Apple Header files. + * + * Copyright (C) 2000 Klaus Halfmann + * Original code 1996-1998 by Robert Leslie + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: apple.h,v 1.2 2000/09/08 14:55:08 hasi Exp $ + */ + +typedef signed char Char; +typedef unsigned char UChar; +typedef signed char SInt8; +typedef unsigned char UInt8; +typedef signed short SInt16; +typedef unsigned short UInt16; +typedef signed long SInt32; +typedef unsigned long UInt32; +typedef unsigned long OSType; +typedef unsigned long long UInt64; + +/* A point, normally used by Quickdraw, + * but found in Finderinformation, too + */ +typedef struct { + SInt16 v; /* vertical coordinate */ + SInt16 h; /* horizontal coordinate */ +} Point; + +/* A rectancle, normally used by Quickdraw, + * but found in Finderinformation, too. + */ +typedef struct { + SInt16 top; /* top edge of rectangle */ + SInt16 left; /* left edge */ + SInt16 bottom; /* bottom edge */ + SInt16 right; /* right edge */ +} Rect; + +/* Information about the location and size of a folder + * used by the Finder. + */ +typedef struct { + Rect frRect; /* folder's rectangle */ + SInt16 frFlags; /* flags */ + Point frLocation; /* folder's location */ + SInt16 frView; /* folder's view */ +} DInfo; + +/* Extended folder information used by the Finder ... + */ +typedef struct { + Point frScroll; /* scroll position */ + SInt32 frOpenChain; /* directory ID chain of open folders */ + SInt16 frUnused; /* reserved */ + SInt16 frComment; /* comment ID */ + SInt32 frPutAway; /* directory ID */ +} DXInfo; + +/* Finder information for a File + */ +typedef struct { + OSType fdType; /* file type */ + OSType fdCreator; /* file's creator */ + SInt16 fdFlags; /* flags */ + Point fdLocation; /* file's location */ + SInt16 fdFldr; /* file's window */ +} FInfo; + +/* Extendend Finder Information for a file + */ +typedef struct { + SInt16 fdIconID; /* icon ID */ + SInt16 fdUnused[4]; /* reserved */ + SInt16 fdComment; /* comment ID */ + SInt32 fdPutAway; /* home directory ID */ +} FXInfo; + +/* Flagvalues for FInfo and DInfo */ +# define HFS_FNDR_ISONDESK (1 << 0) +# define HFS_FNDR_COLOR 0x0e +# define HFS_FNDR_COLORRESERVED (1 << 4) +# define HFS_FNDR_REQUIRESSWITCHLAUNCH (1 << 5) +# define HFS_FNDR_ISSHARED (1 << 6) +# define HFS_FNDR_HASNOINITS (1 << 7) +# define HFS_FNDR_HASBEENINITED (1 << 8) +# define HFS_FNDR_RESERVED (1 << 9) +# define HFS_FNDR_HASCUSTOMICON (1 << 10) +# define HFS_FNDR_ISSTATIONERY (1 << 11) +# define HFS_FNDR_NAMELOCKED (1 << 12) +# define HFS_FNDR_HASBUNDLE (1 << 13) +# define HFS_FNDR_ISINVISIBLE (1 << 14) +# define HFS_FNDR_ISALIAS (1 << 15) + diff --git a/fs/hfsplus/include/blockiter.h b/fs/hfsplus/include/blockiter.h new file mode 100644 index 0000000..e20828b --- /dev/null +++ b/fs/hfsplus/include/blockiter.h @@ -0,0 +1,60 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * The iterator shown here iterates over the blocks of a fork. + * + * Copyright (C) 2000 Klaus Halfmann + * Original work by 1996-1998 Robert Leslie + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: blockiter.h,v 1.1 2000/10/10 11:14:05 hasi Exp $ + */ + +/* Structure of the blockiterator */ +typedef struct +{ + volume* vol; // volume we iterate over + UInt32 curr_block; // current, absolute block + UInt32 block; // relative block in current extent + UInt32 max_block; // Maximum allowed block + UInt32 fileId; // id of file we iterate over + int index; // 0 .. 7 in current extent + hfsp_extent* file; // original extent record from file + hfsp_extent* e; // current extentent under examination + UInt8 forktype; // type of fork we iterate over + UInt8 in_extent; // boolean 0 - in file extent + // 1 - in extents file + extent_record er; // record to iterate in extents file. +} blockiter; + +/* Initialize iterator for a given fork */ +extern void blockiter_init(blockiter* b, volume* vol, hfsp_fork_raw* f, + UInt8 forktype, UInt32 fileId); + +/* find next block of the fork iterating over */ +extern int blockiter_next(blockiter *b); + +/* skip the indicated number of blocks */ +extern int blockiter_skip(blockiter *b, UInt32 skip); + +/* return current block */ +static inline UInt32 blockiter_curr(blockiter *b) +{ + return b->e->start_block + b->block; +} + + diff --git a/fs/hfsplus/include/btree.h b/fs/hfsplus/include/btree.h new file mode 100644 index 0000000..b413c46 --- /dev/null +++ b/fs/hfsplus/include/btree.h @@ -0,0 +1,50 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes. + * + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * Copyright (C) 2000 Klaus Halfmann + * Original 1996-1998 Robert Leslie + * Additional work by Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: btree.h,v 1.10 2000/10/25 05:43:04 hasi Exp $ + */ + +/** Intialize catalog btree, so that btree_close can safely be called. */ +extern void btree_reset(btree* bt); + +/** Intialize catalog btree */ +extern int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork); + +/** Intialize extents btree */ +extern int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork); + +/** close the btree and free any resources */ +extern void btree_close(btree* bt); + +/* Read node at given index */ +extern node_buf* btree_node_by_index(btree* bt, UInt16 index); + +/* returns pointer to key given by index in current node */ +extern void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index); + +#ifdef DEBUG + /* Dump all the btree information to stdout */ + extern void btree_print(btree* bt); +#endif + diff --git a/fs/hfsplus/include/hfs.h b/fs/hfsplus/include/hfs.h new file mode 100644 index 0000000..582e8a9 --- /dev/null +++ b/fs/hfsplus/include/hfs.h @@ -0,0 +1,32 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes + * + * This file includes definitions for access to old HFS structures. + * + * Copyright (C) 2000 Klaus Halfmann + * Original code 1996-1998 by Robert Leslie + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: hfs.h,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $ + */ + + +#define HFS_BLOCKSZ 512 + /* A sector for Apple is always 512 bytes */ +#define HFS_BLOCKSZ_BITS 9 /* 1<<9 == 512 */ +#define HFS_VOLHEAD_SIG 0x4244 /* 'BD' */ + diff --git a/fs/hfsplus/include/hfsp.h b/fs/hfsplus/include/hfsp.h new file mode 100644 index 0000000..63ae345 --- /dev/null +++ b/fs/hfsplus/include/hfsp.h @@ -0,0 +1,305 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes + * + * This file includes definitions for the structures found on + * HFS+ Volumes. The structures are further wrapped by struct + * found in libhfsp.h. fucntions on those enhanced structures + * are found in files mentioned in comments below. + * + * Copyright (C) 2000 Klaus Halfmann + * Original code 1996-1998 by Robert Leslie + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: hfsp.h,v 1.17 2000/10/20 06:16:52 hasi Exp $ + */ + +#define HFSP_BLOCKSZ 512 /* A sector for Apple is always 512 bytes */ +#define HFSP_BLOCKSZ_BITS 9 /* 1<<9 == 512 */ +#define HFSP_VOLHEAD_SIG 0x482B /* 'H+' */ + +/* HFS+ includes POSIX permissions , although marked as reserved they will be + * used as such. Is ignored by MacOS 8-9 but probably not by MacOS X. + */ +typedef struct { + UInt32 owner; + UInt32 group; + UInt32 mode; + UInt32 dev; +} hfsp_perm; + +/* A single contiguous area (fragment) of a file */ +typedef struct { + UInt32 start_block; + UInt32 block_count; +} hfsp_extent; + +/* A file may contain up to 8 normale extents, all other + are found in some extra extent area */ +typedef hfsp_extent hfsp_extent_rec[8]; + +/* Information for a "Fork" in a file + * Forks are the "usual" DATA and RSRC forks or special files + * (e.g. the Volume Bitmap) + */ +typedef struct { + UInt64 total_size; // logical size + UInt32 clump_size; // number of bytes to preallocate + UInt32 total_blocks; + hfsp_extent_rec extents; // initial (8) extents +} hfsp_fork_raw; + +/* HFS+ Volume Header + * Always found at block 2 of the disk, a copy is stored + * at the second to last block of the disk. + */ +typedef struct hfsp_vh { + UInt16 signature; // must be HFSPLUS_VOLHEAD_SIG 'H+' + UInt16 version; // currently 4, ignored + UInt32 attributes; // See bit constants below + UInt32 last_mount_vers; + // Use a registered creator code here (what do we use ?) + // Mac OS uses '8.10' well + UInt32 reserved; + + UInt32 create_date; // local time ! + UInt32 modify_date; // GMT (?) + UInt32 backup_date; // GMT (?) + UInt32 checked_date; // GMT (?) fsck ? + + UInt32 file_count; + // not including special files but including DATA and RSRC forks + UInt32 folder_count; // excluding the root folder + + UInt32 blocksize; + // must be multiple of HFSPLUS_SECTOR_SIZE, + // should be a multiple of 4k for harddisk + UInt32 total_blocks; + UInt32 free_blocks; + // The total number of unused allocation blocks on the disk. + + UInt32 next_alloc; + // hint wher to search for next allocation blocks + UInt32 rsrc_clump_sz; + // default clump size for rsrc forks + UInt32 data_clump_sz; + // default clump size for data forks + UInt32 next_cnid; + // next unused catalog id + UInt32 write_count; + // increment on every mount (and write ?) + UInt64 encodings_bmp; + // for every encoding used on the disk a bit is set + // ignored but eventually must be cared for + Char finder_info[32]; + hfsp_fork_raw alloc_file; + // stores bitmap of use/free blocks + hfsp_fork_raw ext_file; + // stores oferflow extents + hfsp_fork_raw cat_file; + // This contains the root directory + hfsp_fork_raw attr_file; + hfsp_fork_raw start_file; + // a special startup file may be described here (used by ?) +} hfsp_vh; + +/* HFS+ volume attributes */ +/* 0-6 reserved, may be used in memory only */ +#define HFSPLUS_VOL_RESERVED1 0x000000FF +#define HFSPLUS_VOL_HARDLOCK 0x00000080 // Used in Memory by finder only +#define HFSPLUS_VOL_UNMNT 0x00000100 + // clear this bit when mounting, set as last step of unmounting + // This is checked by (slower) ROM code +#define HFSPLUS_VOL_SPARE_BLK 0x00000200 +#define HFSPLUS_VOL_NOCACHE 0x00000400 + // in case of RAM or ROM disk (try a HFS+ Ramdisk :) +#define HFSPLUS_VOL_INCNSTNT 0x00000800 + // Reverse meaning as of HFSPLUS_VOL_UNMNT + // This is checked by (faster) Mac OS code +/* 12-14 reserved */ +#define HFSPLUS_VOL_RESERVED2 0x00007000 +#define HFSPLUS_VOL_SOFTLOCK 0x00008000 +#define HFSPLUS_VOL_RESERVED3 0xFFFF0000 + +/* HFS+ Btree node descriptor */ +typedef struct { + UInt32 next; /* pointer to next node of this kind, or 0 */ + UInt32 prev; /* pointer to previous node of this kind, or 0 */ + UInt8 kind; /* see below */ + UInt8 height; /* root node starts with 0 */ + UInt16 num_rec; /* number of records in this node */ + UInt16 reserved; /* fill up to 4 byte alignment */ +} btree_node_desc; + +/* HFS+ Btree Node types */ +#define HFSP_NODE_NDX 0x00 +#define HFSP_NODE_HEAD 0x01 +#define HFSP_NODE_MAP 0x02 +#define HFSP_NODE_LEAF 0xFF + +#define HFSP_CATALOG_MIN_NODE_SIZE 0x1000 +#define HFSP_ATTRMIN_DOE_SIZE 0x1000 + +/* The record offsets are found at the end of the fork + * containing the Btree */ + +typedef UInt16 btree_record_offset; + +typedef struct { + UInt16 depth; + // equal to height of btree_node_desc + UInt32 root; + // root node of the hierarchy + UInt32 leaf_count; + UInt32 leaf_head; + UInt32 leaf_tail; + UInt16 node_size; + // node size of _all_ nodes in this fork + UInt16 max_key_len; + UInt32 node_count; + // count of all (free and used) nodes in tree + UInt32 free_nodes; + UInt16 reserved1; + UInt32 clump_size; + // ignored my MacOS used by ? + UInt8 btree_type; + // always 0 for HFS+ + UInt8 reserved2; + UInt32 attributes; + // see below + UInt32 reserved3[16]; +} btree_head; + +/* BTree attributes */ +#define HFSPLUS_BAD_CLOSE 0x01 + // Btree was not properly closed and should be checked + // not used for HFS+ but reserved +#define HFSPLUS_TREE_BIGKEYS 0x02 + // always set for HFS+ +#define HFSPLUS_TREE_VAR_NDXKEY_SIZE 0x04 + // use variable length index nodes, always set for catalog btree, + // always cleared for extents btree. + +#define HFSPLUS_TREE_UNUSED 0xFFFFFFF8 + +/* Some special File ID numbers */ +#define HFSP_POR_CNID 1 /* Parent Of the Root */ +#define HFSP_ROOT_CNID 2 /* ROOT directory */ +#define HFSP_EXT_CNID 3 /* EXTents B-tree */ +#define HFSP_CAT_CNID 4 /* CATalog B-tree */ +#define HFSP_BAD_CNID 5 /* BAD blocks file */ +#define HFSP_ALLOC_CNID 6 /* ALLOCation file */ +#define HFSP_START_CNID 7 /* STARTup file */ +#define HFSP_ATTR_CNID 8 /* ATTRibutes file */ +#define HFSP_EXCH_CNID 15 /* ExchangeFiles temp id */ +#define HFPS_MIN_CNID 15 /* Minimum expected value */ + +/* Unicode String */ +typedef struct { + UInt16 strlen; + UInt16 name[255]; // unicode charcters +} hfsp_unistr255; + +/* HFS+ catalog entry key */ +typedef struct { + UInt16 key_length; /* excluding length */ + UInt32 parent_cnid; + hfsp_unistr255 name; +} hfsp_cat_key; + +/* HFS+ exnteds entry key */ +typedef struct { + UInt16 key_length; /* excluding length */ + UInt8 fork_type; /* Seee below */ + UInt8 filler; + UInt32 file_id; + UInt32 start_block; +} hfsp_extent_key; + +#define HFSP_EXTENT_DATA 0x00 +#define HFSP_EXTENT_RSRC 0xFF + +/* The key is followed by a record, an index or some other data */ + +/* The types of these records are defined as follows */ + +#define HFSP_FOLDER 0x0001 // entry fo a Folder +#define HFSP_FILE 0x0002 // entry for a File +#define HFSP_FOLDER_THREAD 0x0003 + // Like '.' in unix, identifies the folder by its id, only +#define HFSP_FILE_THREAD 0x0004 + // Im unsure if this is used by HFS+, too + +/* HFS+ folder data (part of an hfsp_cat_entry) */ +typedef struct { + UInt16 flags; /* no flags defined yet */ + UInt32 valence; /* Numer of files and folders contained in folder */ + UInt32 id; + UInt32 create_date; // GMT + UInt32 content_mod_date; // GMT + UInt32 attribute_mod_date; // GMT + UInt32 access_date; // GMT + UInt32 backup_date; // GMT + hfsp_perm permissions; + DInfo user_info; + DXInfo finder_info; + UInt32 text_encoding; + // hint fo the finder what encoding to use, unused here + UInt32 reserved; +} hfsp_cat_folder; + +/* HFS+ file data (part of a cat_entry) */ +typedef struct { + UInt16 flags; /* See below */ + UInt32 reserved1; + UInt32 id; + UInt32 create_date; + UInt32 content_mod_date; + UInt32 attribute_mod_date; + UInt32 access_date; + UInt32 backup_date; + hfsp_perm permissions; + FInfo user_info; + FXInfo finder_info; + UInt32 text_encoding; + UInt32 reserved2; + + hfsp_fork_raw data_fork; + hfsp_fork_raw res_fork; +} hfsp_cat_file; + +/* File attribute bits */ +#define HFSP_FILE_LOCKED 0x0001 +#define HFSP_THREAD_EXISTS 0x0002 /* Always set in HFS+ */ + +/* HFS+ catalog thread (part of a cat_entry) */ +typedef struct { + UInt16 reserved; + UInt32 parentID; + hfsp_unistr255 nodeName; +} hfsp_cat_thread; + + +/* A data record in the catalog tree */ +typedef struct { + UInt16 type; + union { + hfsp_cat_folder folder; + hfsp_cat_file file; + hfsp_cat_thread thread; + } u; +} hfsp_cat_entry; + diff --git a/fs/hfsplus/include/hfstime.h b/fs/hfsplus/include/hfstime.h new file mode 100644 index 0000000..cf34af7 --- /dev/null +++ b/fs/hfsplus/include/hfstime.h @@ -0,0 +1,34 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 2000 Klaus Halfmann ^ + * Original 1996-1998 Robert Leslie + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * The HFS+ dates are stored as UInt32 containing the number of seconds since + * midnight, January 1, 1904, GMT. This is slightly different from HFS, + * where the value represents local time. A notable exception is the + * creationdate !. Linux uses times in GMT starting at January 1, 1970 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: hfstime.h,v 1.2 2000/10/19 13:33:38 hasi Exp $ + */ + + /* The number of seconds between 1.1.1904 and 1.1.1970 */ +#define HFSPTIMEDIFF 2082844800U + + /* return the given apple time as UNIX time */ +extern char* get_atime(UInt32 atime); + diff --git a/fs/hfsplus/include/libhfsp.h b/fs/hfsplus/include/libhfsp.h new file mode 100644 index 0000000..99d258b --- /dev/null +++ b/fs/hfsplus/include/libhfsp.h @@ -0,0 +1,204 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 2000 Klaus Halfmann (khalfmann@libra.de) + * Original work by 1996-1998 Robert Leslie (rob@mars.org) + * + * This file defines constants,structs etc needed for this library. + * Everything found here is usually not related to Apple defintions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: libhfsp.h,v 1.17 2000/10/20 06:16:52 hasi Exp $ + */ + +# include "apple.h" +# include "hfs.h" +# include "hfsp.h" + +extern int errno; +/* Last error is eventually found here */ +extern const char *hfsp_error; + +# define HFSP_ERROR(code, str) \ + do { hfsp_error = (str), errno = (code); goto fail; } while (0) + +# ifdef DEBUG +# define ASSERT(cond) do { if (! (cond)) abort(); } while (0) +# else +# define ASSERT(cond) /* nothing */ +# endif + +# define SIZE(type, n) ((size_t) (sizeof(type) * (n))) +# define ALLOC(type, n) ((type *) malloc(SIZE(type, n))) +# define ALLOCX(type, n) ((n) ? ALLOC(type, n) : (type *) 0) +# define FREE(ptr) ((ptr) ? (void) free((void *) ptr) : (void) 0) + +# define REALLOC(ptr, type, n) \ + ((type *) ((ptr) ? realloc(ptr, SIZE(type, n)) : malloc(SIZE(type, n)))) +# define REALLOCX(ptr, type, n) \ + ((n) ? REALLOC(ptr, type, n) : (FREE(ptr), (type *) 0)) + +# define BMTST(bm, num) \ + (((const byte *) (bm))[(num) >> 3] & (0x80 >> ((num) & 0x07))) +# define BMSET(bm, num) \ + (((byte *) (bm))[(num) >> 3] |= (0x80 >> ((num) & 0x07))) +# define BMCLR(bm, num) \ + (((byte *) (bm))[(num) >> 3] &= ~(0x80 >> ((num) & 0x07))) + +# define STRINGIZE(x) #x +# define STR(x) STRINGIZE(x) + +/* used by internal routines to specify the open modes */ +# define HFSP_MODE_RDONLY 0 +# define HFSP_MODE_RDWR 1 +# define HFSP_MODE_ANY 2 + +/* Signatures registered with Apple to identify this driver */ + /* Identifies the userland implementation */ +# define HPLS_SIGNATURE 0x482B4C58 // 'H+LX' + /* Identifies the kernel module by Brad Boyer (flar@pants.nu) */ +# define HPLS_SIGRES1 0x482B4C78 // 'H+Lx' + /* not jet in use ... */ +# define HPLS_SIGRES2 0x482B6C78 // 'H+lx' + /* Signature used by Apple */ +# define HPAPPLE_SIGNATURE 0x382e3130 // '8.10' + +/* Version used for this implementation of HFS+. This is not related + * to the VERSION file found at the top-level of this package, + * but designates the version of the low level code */ +#define HPLS_VERSION 1 /* must fit in a short */ + + +/* Othe Signatures may follow for informational purpos */ + +/* prototype for key comparing functions. */ +typedef int (*hfsp_key_compare) (void* key1, void* key2); + +/* prototype for key reading (necessary for byte swapping) */ +typedef void* (*hfsp_key_read) (void* p, void* key); + +struct volume; /* foreward declaration for btree needed */ + +/* Structures for a node cache. The cache is an array + * with linear search. (So making it to big may make + * things slower). It is searched in a round robin + * fashion. + */ + +typedef struct +{ + UInt32 priority; + // as lower this number as higher the priority. + // decremetned on any sucessfull usage + // incremented else, intial value height*DEPTHFACTOR + UInt16 index; // of node in fork + // 0 means empty, since first node is node header + // contents of node in original byte order + UInt16 flags; // like DIRTY etc. +} node_entry; + +typedef struct +{ + UInt32 index; // duplicate of above + btree_node_desc desc; // header of node + char node[0]; // actual node_size + // contents of node in original byte order +} node_buf; + +typedef struct +{ + int size; // number of nodes in the cache + int currindex; // round robin index + int nodebufsize; // size of complete node_buf, including node + node_entry *entries; + char *buffers; // actually *node_buf +} node_cache; + +typedef struct +{ + struct volume* vol; /* pointer to volume this tree is part of */ + hfsp_fork_raw* fork; /* pointer to fork this tree is part of */ + UInt32 cnid; /* (pseudo) file id for the fork */ + hfsp_key_compare kcomp; + /* function used for key compare in _this_ btree */ + hfsp_key_read kread; + /* fucntion used to read a key int _this_ btree */ + btree_head head; + + UInt16 blkpernode; + /* Number of volume blocks per node (usually 1-4) */ + node_cache cache; + /* Warning all functions of btrees and records may modify + the following values ! */ + // UInt16 node_index; /* index of node in fork */ + // btree_node_desc node; /* current node under examination */ + // char* buf; /* buf with size of a node */ +} btree; + +/* Function on btrees are defined in btree.h */ + +/* A Wrapper around the raw hfs+ volume header for additional information + * needed by this library. + */ + +typedef struct volume +{ + int os_fd; /* OS dependend reference to device */ + UInt16 blksize_bits; /* blocksize of device = 1 << blksize_bits */ + UInt16 filler; + UInt32 blksize; /* always 1 << blksize_bits */ + UInt32 startblock; + /* Offset from physical to logical blocks, + eventually intodruced by HFS wrapper */ + UInt32 maxblocks; /* maximum number of blocks in device */ + // UInt32 currblock; /* value of current block, to cache blocks */ + hfsp_vh vol; /* raw volume data */ + // void* blockbuf; /* (single) buffer for fetching one block */ + /* Buffer has double size of blksize to allow cross block reading */ + + btree* extents; /* is NULL by default and intialized when needed */ + btree catalog; /* This is always neeeded */ +} volume; + +/* Functions on volumes are defined in volume.h */ + +typedef struct { // may not be used as found here + btree* tree; // tree where this record is contained in. + UInt16 node_index; /* index of record in btree */ + UInt16 keyind; /* index of current key in btree */ + hfsp_cat_key key; /* current key */ + UInt32 child; /* child node belonging to this key */ +} index_record; + +typedef struct { + btree* tree; // tree where this record is contained in. + UInt16 node_index; /* index of record in btree */ + UInt16 keyind; /* index of current key in btree */ + hfsp_extent_key key; /* current key */ + hfsp_extent_rec extent; /* The payload carried around */ +} extent_record; + +typedef struct { + btree* tree; // tree where this record is contained in. + UInt16 node_index; /* index of record in btree */ + UInt16 keyind; /* index of current key in btree */ + hfsp_cat_key key; /* current key */ + hfsp_cat_entry record; /* current record */ +} record; + +/* Functions on records are defined in record.h */ + + + diff --git a/fs/hfsplus/include/record.h b/fs/hfsplus/include/record.h new file mode 100644 index 0000000..9299c7b --- /dev/null +++ b/fs/hfsplus/include/record.h @@ -0,0 +1,81 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes. + * + * a record contains a key and a folder or file and is part + * of a btree. + * + * Copyright (C) 2000 Klaus Halfmann + * Original 1996-1998 Robert Leslie + * Additional work by Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: record.h,v 1.10 2000/10/01 17:08:05 hasi Exp $ + */ + +/* Compare two cat_keys ... */ +extern int record_key_compare(void* k1, void* k2); + +/* Compare two extent_keys ... */ +extern int record_extent_key_compare(void* k1, void* k2); + +/* read a catalog key into a given buffer */ +extern void* record_readkey(void* p, void* buf); + +/* read an extent key into a given buffer */ +extern void* record_extent_readkey(void* p, void* buf); + +/* intialize the record to the first record of the tree + * which is (per design) the root node. + */ +extern int record_init_root(record* r, btree* tree); + +/* intialize the record to the folder given by cnid. + */ +extern int record_init_cnid(record* r, btree* tree, UInt32 cnid); + +/* intialize the record to the first record of the parent. + */ +extern int record_init_parent(record* r, record* parent); + +/* intialize the record by searching for the given string in the given folder. + * + * parent and r may be the same. + */ +extern int record_init_string_parent(record* r, record* parent, char* key); + +/* move record up in folder hierarchy (if possible) */ +extern int record_up(record* r); + +/* move record foreward to next entry. + * + * In case of an error the value of *r is undefined ! + */ +extern int record_next(record* r); + +/* intialize the extent_record to the extent identified by + * a given file */ +extern int record_init_file(extent_record* r, btree* tree, + UInt8 forktype, UInt32 fileId, UInt32 blockindex); + +/* move foreward to next entent record. */ +extern int record_next_extent(extent_record *r); + +#ifdef DEBUG + /* Dump all the record information to stdout */ + extern void record_print(record* r); +#endif + + diff --git a/fs/hfsplus/include/swab.h b/fs/hfsplus/include/swab.h new file mode 100644 index 0000000..0c41674 --- /dev/null +++ b/fs/hfsplus/include/swab.h @@ -0,0 +1,44 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 2000 Klaus Halfmann + * Original work 1996-1998 Robert Leslie + * + * This file defines some byte swapping function. I did not find this + * in any standard or linux way. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: swab.h,v 1.3 2000/09/14 05:53:44 hasi Exp $ + */ + +#ifndef bswap_16 +#define bswap_16(x) \ + ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) +#endif + +/* Big endian */ + +#define bswabU16_inc(ptr) (*((UInt16*) (ptr))++) +#define bswabU32_inc(ptr) (*((UInt32*) (ptr))++) +#define bswabU64_inc(ptr) (*((UInt64*) (ptr))++) + +#define bstoreU16_inc(ptr, val) (*((UInt16*) (ptr))++) = val +#define bstoreU32_inc(ptr, val) (*((UInt32*) (ptr))++) = val +#define bstoreU64_inc(ptr, val) (*((UInt64*) (ptr))++) = val + + +/* for the sake of compleetness and readability */ +#define bswabU8_inc(ptr) (*((UInt8*) (ptr))++) +#define bstoreU8_inc(ptr,val) (*((UInt8*) (ptr))++) = val diff --git a/fs/hfsplus/include/unicode.h b/fs/hfsplus/include/unicode.h new file mode 100644 index 0000000..db5e762 --- /dev/null +++ b/fs/hfsplus/include/unicode.h @@ -0,0 +1,28 @@ +/* + * linux/fs/hfsplus/unicode.c + * + * Copyright (C) 1999-2000 Brad Boyer (flar@pants.nu) + * This file may be distributed under the terms of the GNU Public License. + * + * The routines found here convert hfs-unicode string into ascii Strings + * and vice versa. And the correct comparison between Strings. + */ + +/* convert the asci string astr into a unicode string given by ustr. + * + * returns actual length of convertet string. + */ + +int unicode_asc2uni(hfsp_unistr255 *ustr, const char *astr); + +/* Convert an unicode string ustr to a ascii string astr of given maximum len + * + * returns actual length of convertet string. + */ + +int unicode_uni2asc(char *astr, const hfsp_unistr255 *ustr, int maxlen); + +/* similar to strcmp for unicode, pascal strings */ + +SInt32 fast_unicode_compare (const hfsp_unistr255 *ustr1, + const hfsp_unistr255 *ustr2); diff --git a/fs/hfsplus/include/volume.h b/fs/hfsplus/include/volume.h new file mode 100644 index 0000000..868a4ef --- /dev/null +++ b/fs/hfsplus/include/volume.h @@ -0,0 +1,84 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 2000 Klaus Halfmann ^ + * Original 1996-1998 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: volume.h,v 1.11 2000/10/17 05:58:46 hasi Exp $ + */ + +#ifndef _H_VOLUME +#define _H_VOLUME + +/* Open the device, read and verify the volume header + (and its backup) */ +extern int volume_open(volume* vol, int os_fd); + +/* Write back all data eventually cached and close the device. */ +extern int volume_close(volume* vol); + +/* read multiple blocks into given memory. + * + * returns given pointer or NULL on failure. + */ +extern void* volume_readfromfork(volume* vol, void* buf, + hfsp_fork_raw* f, UInt32 block, + UInt32 count, UInt8 forktype, UInt32 fileId); + +/* Fill a given buffer with the given block in volume. + */ +int volume_readinbuf(volume * vol,void* buf, long block); + +/* invalidat cache hold in volume, will be removed when + * caching strategy is clear to me. */ +/* +extern inline void volume_invalidate_cache(volume* vol) +{ + vol -> currblock = (UInt32) -1; +} +*/ + +/* Check in Allocation file if given block is allocated. */ +extern int volume_allocated(volume* v, UInt32 block); + +/* Read a raw hfsp_extent_rec from memory. */ +extern void* volume_readextent(void *p, hfsp_extent_rec er); + +/* Read fork information from raw memory */ +extern void* volume_readfork(void *p, hfsp_fork_raw* f); + +/* internal function used to create the extents btree, + is called by following inline fucntion when needed */ +extern void volume_create_extents_tree(volume* vol); + +/* accessor for entends btree, is created on demand */ +static inline btree* volume_get_extents_tree(volume* vol) { + if (!vol->extents) + volume_create_extents_tree(vol); + return vol->extents; +} + + +#ifdef DEBUG + /* Print raw fork information to stdout */ + void volume_print_fork(hfsp_fork_raw* f); + /* Dump all the volume information to stdout */ + void volume_print(hfsp_vh* vol); +#endif + + + +#endif /* _H_VOLUME */ diff --git a/fs/hfsplus/libhfsp.c b/fs/hfsplus/libhfsp.c new file mode 100644 index 0000000..3c8a1a9 --- /dev/null +++ b/fs/hfsplus/libhfsp.c @@ -0,0 +1,28 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998 Robert Leslie + * + * Thi file contains utitlity fucntions to manage the features of + * the hfs+ library. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: libhfsp.c,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $ + */ + +#include "openbios/config.h" +#include "libhfsp.h" + +const char *hfsp_error = "no error"; /* static error string */ diff --git a/fs/hfsplus/record.c b/fs/hfsplus/record.c new file mode 100644 index 0000000..6c8f7f7 --- /dev/null +++ b/fs/hfsplus/record.c @@ -0,0 +1,756 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes. + * + * a record contains a key and a folder or file and is part + * of a btree. + * + * Copyright (C) 2000 Klaus Halfmann + * Original 1996-1998 Robert Leslie + * Additional work by Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: record.c,v 1.24 2000/10/17 05:58:46 hasi Exp $ + */ + +#include "openbios/config.h" +#include "libhfsp.h" +#include "hfstime.h" +#include "record.h" +#include "volume.h" +#include "btree.h" +#include "unicode.h" +#include "swab.h" + +/* read a hfsp_cat_key from memory */ +void* record_readkey(void* p, void* buf) +{ + hfsp_cat_key* key = (hfsp_cat_key*) buf; + const void* check; + UInt16 key_length, len,i; + UInt16* cp; + + key->key_length = key_length = bswabU16_inc(p); + check = p; + key->parent_cnid = bswabU32_inc(p); + key->name.strlen = len = bswabU16_inc(p); + cp = key->name.name; + for (i=0; i < len; i++, cp++) + *cp = bswabU16_inc(p); + /* check if keylenght was correct */ + if (key_length != ((char*) p) - ((char*) check)) + HFSP_ERROR(EINVAL, "Invalid key length in record_readkey"); + return p; + fail: + return NULL; +} + +/* read a hfsp_extent_key from memory */ +void* record_extent_readkey(void* p, void* buf) +{ + hfsp_extent_key* key = (hfsp_extent_key*) buf; + UInt16 key_length; + + key->key_length = key_length = bswabU16_inc(p); + key->fork_type = bswabU8_inc(p); + key->filler = bswabU8_inc(p); + if (key_length != 10) + HFSP_ERROR(-1, "Invalid key length in record_extent_readkey"); + key->file_id = bswabU32_inc(p); + key->start_block = bswabU32_inc(p); + return p; + fail: + return NULL; +} + + +/* read posix permission from memory */ +static inline void* record_readperm(void *p, hfsp_perm* perm) +{ + perm->owner= bswabU32_inc(p); + perm->group= bswabU32_inc(p); + perm->mode = bswabU32_inc(p); + perm->dev = bswabU32_inc(p); + return p; +} + +/* read directory info */ +static inline void* record_readDInfo(void *p, DInfo* info) +{ + info->frRect.top = bswabU16_inc(p); + info->frRect.left = bswabU16_inc(p); + info->frRect.bottom = bswabU16_inc(p); + info->frRect.right = bswabU16_inc(p); + info->frFlags = bswabU16_inc(p); + info->frLocation.v = bswabU16_inc(p); + info->frLocation.h = bswabU16_inc(p); + info->frView = bswabU16_inc(p); + return p; +} + +/* read extra Directory info */ +static inline void* record_readDXInfo(void *p, DXInfo* xinfo) +{ + xinfo->frScroll.v = bswabU16_inc(p); + xinfo->frScroll.h = bswabU16_inc(p); + xinfo->frOpenChain = bswabU32_inc(p); + xinfo->frUnused = bswabU16_inc(p); + xinfo->frComment = bswabU16_inc(p); + xinfo->frPutAway = bswabU32_inc(p); + return p; +} + +/* read a hfsp_cat_folder from memory */ +static void* record_readfolder(void *p, hfsp_cat_folder* folder) +{ + folder->flags = bswabU16_inc(p); + folder->valence = bswabU32_inc(p); + folder->id = bswabU32_inc(p); + folder->create_date = bswabU32_inc(p); + folder->content_mod_date = bswabU32_inc(p); + folder->attribute_mod_date = bswabU32_inc(p); + folder->access_date = bswabU32_inc(p); + folder->backup_date = bswabU32_inc(p); + p = record_readperm (p, &folder->permissions); + p = record_readDInfo (p, &folder->user_info); + p = record_readDXInfo (p, &folder->finder_info); + folder->text_encoding = bswabU32_inc(p); + folder->reserved = bswabU32_inc(p); + return p; +} + +/* read file info */ +static inline void* record_readFInfo(void *p, FInfo* info) +{ + info->fdType = bswabU32_inc(p); + info->fdCreator = bswabU32_inc(p); + info->fdFlags = bswabU16_inc(p); + info->fdLocation.v = bswabU16_inc(p); + info->fdLocation.h = bswabU16_inc(p); + info->fdFldr = bswabU16_inc(p); + return p; +} + +/* read extra File info */ +static inline void* record_readFXInfo(void *p, FXInfo* xinfo) +{ + xinfo->fdIconID = bswabU16_inc(p); + ((SInt16*) p) += 4; // skip unused + xinfo->fdComment = bswabU16_inc(p); + xinfo->fdPutAway = bswabU32_inc(p); + return p; +} + +/* read a hfsp_cat_file from memory */ +static void* record_readfile(void *p, hfsp_cat_file* file) +{ + file->flags = bswabU16_inc(p); + file->reserved1 = bswabU32_inc(p); + file->id = bswabU32_inc(p); + file->create_date = bswabU32_inc(p); + file->content_mod_date = bswabU32_inc(p); + file->attribute_mod_date = bswabU32_inc(p); + file->access_date = bswabU32_inc(p); + file->backup_date = bswabU32_inc(p); + p = record_readperm (p, &file->permissions); + p = record_readFInfo (p, &file->user_info); + p = record_readFXInfo (p, &file->finder_info); + file->text_encoding = bswabU32_inc(p); + file->reserved2 = bswabU32_inc(p); + p = volume_readfork (p, &file->data_fork); + return volume_readfork (p, &file->res_fork); +} + +/* read a hfsp_cat_thread from memory */ +static void* record_readthread(void *p, hfsp_cat_thread* entry) +{ + int i; + UInt16 len; + UInt16* cp; + + entry-> reserved = bswabU16_inc(p); + entry-> parentID = bswabU32_inc(p); + entry->nodeName.strlen = len= bswabU16_inc(p); + cp = entry->nodeName.name; + if (len > 255) + HFSP_ERROR(-1, "Invalid key length in record thread"); + for (i=0; i < len; i++, cp++) + *cp = bswabU16_inc(p); + return p; + fail: + return NULL; +} + +/* read a hfsp_cat_entry from memory */ +static void* record_readentry(void *p, hfsp_cat_entry* entry) +{ + UInt16 type = bswabU16_inc(p); + entry->type = type; + switch (type) + { + case HFSP_FOLDER: + return record_readfolder(p, &entry->u.folder); + case HFSP_FILE: + return record_readfile (p, &entry->u.file); + case HFSP_FOLDER_THREAD: + case HFSP_FILE_THREAD: + return record_readthread(p, &entry->u.thread); + default: + HFSP_ERROR(-1, "Unexpected record type in record_readentry"); + } ; + fail: + return NULL; +} + + +/* Most of the functions here will not change the node in the btree, + But this must be changed in the future ... */ + + +/* intialize the record with the given index entry in the btree. */ +static int record_init(record* r, btree* bt, node_buf* buf, UInt16 index) +{ + void *p; + r-> tree = bt; + p = btree_key_by_index(bt,buf,index); + if (!p) + return -1; + p = record_readkey (p, &r->key); + if (!p) + return -1; + p = record_readentry(p, &r->record); + if (!p) + return -1; + r->node_index = buf->index; + r-> keyind = index; + + return 0; +} + +/* intialize the record with the given index entry in the btree. */ +static int record_init_extent(extent_record* r, btree* bt, node_buf* buf, UInt16 index) +{ + void *p; + r-> tree = bt; + p = btree_key_by_index(bt, buf,index); + if (!p) + return -1; + p = record_extent_readkey(p, &r->key); + if (!p) + return -1; + p = volume_readextent(p, r->extent); + if (!p) + return -1; + r->node_index = buf->index; + r-> keyind = index; + + return 0; +} + +/* intialize the record to the first record of the tree + * which is (per design) the root node. + */ +int record_init_root(record* r, btree* tree) +{ + // Position to first leaf node ... + UInt32 leaf_head = tree->head.leaf_head; + node_buf* buf = btree_node_by_index(tree, leaf_head); + if (!buf) + return -1; + return record_init(r, tree, buf, 0); +} + +/* Compare two cat_keys ... */ +int record_key_compare(void* k1, void* k2) +{ + hfsp_cat_key* key1 = (hfsp_cat_key*) k1; + hfsp_cat_key* key2 = (hfsp_cat_key*) k2; + int diff = key2->parent_cnid - key1->parent_cnid; + if (!diff) // same parent + diff = fast_unicode_compare(&key1->name, &key2->name); + return diff; +} + +/* Compare two extent_keys ... */ +int record_extent_key_compare(void* k1, void* k2) +{ + hfsp_extent_key* key1 = (hfsp_extent_key*) k1; + hfsp_extent_key* key2 = (hfsp_extent_key*) k2; + int diff = key2->fork_type - key1->fork_type; + if (!diff) // same type + { + diff = key2->file_id - key1->file_id; + if (!diff) // same file + diff = key2->start_block - key1->start_block; + } + return diff; +} + +/* Position node in btree so that key might be inside */ +static node_buf* record_find_node(btree* tree, void *key) +{ + int start, end, mid, comp; // components of a binary search + void *p = NULL; + char curr_key[tree->head.max_key_len]; + // The current key under examination + hfsp_key_read readkey = tree->kread; + hfsp_key_compare key_compare = tree->kcomp; + UInt32 index; + node_buf* node = btree_node_by_index(tree, tree->head.root); + if (!node) + HFSP_ERROR(-1, "record_find_node: Cant position to root node"); + while (node->desc.kind == HFSP_NODE_NDX) + { + mid = start = 0; + end = node->desc.num_rec; + comp = -1; + while (start < end) + { + mid = (start + end) >> 1; + p = btree_key_by_index(tree, node, mid); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + p = readkey (p, curr_key); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + comp = key_compare(curr_key, key); + if (comp > 0) + start = mid + 1; + else if (comp < 0) + end = mid; + else + break; + } + if (!p) // Empty tree, fascinating ... + HFSP_ERROR(-1, "record_find_node: unexpected empty node"); + if (comp < 0) // mmh interesting key is before this key ... + { + if (mid == 0) + return NULL; // nothing before this key .. + p = btree_key_by_index(tree, node, mid-1); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + p = readkey (p, curr_key); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + } + + index = bswabU32_inc(p); + node = btree_node_by_index(tree, index); + } + return node; // go on and use the found node + fail: + return NULL; +} + +/* search for the given key in the btree. + * + * returns pointer to memory just after key or NULL + * In any case *keyind recives the index where the + * key was found (or could be inserted.) + */ +static void * +record_find_key(btree* tree, void* key, int* keyind, UInt16* node_index) +{ + node_buf* buf = record_find_node(tree, key); + if (buf) + { + int comp = -1; + int start = 0; // components of a binary search + int end = buf->desc.num_rec; + int mid = -1; + void *p = NULL; + char curr_key[tree->head.max_key_len]; + hfsp_key_read readkey = tree->kread; + hfsp_key_compare key_compare = tree->kcomp; + while (start < end) + { + mid = (start + end) >> 1; + p = btree_key_by_index(tree, buf, mid); + if (!p) + HFSP_ERROR(-1, "record_init_key: unexpected error"); + p = readkey (p, curr_key); + if (!p) + HFSP_ERROR(-1, "record_init_cat_key: unexpected error"); + comp = key_compare(curr_key, key); + if (comp > 0) + start = mid + 1; + else if (comp < 0) + end = mid; + else + break; + } + if (!p) // Empty tree, fascinating ... + HFSP_ERROR(ENOENT, "record_init_key: unexpected empty node"); + *keyind = mid; + *node_index = buf->index; + if (!comp) // found something ... + return p; + } + HFSP_ERROR(ENOENT, NULL); + fail: + return NULL; +} + +/* intialize the record by searching for the given key in the btree. + * + * r is umodified on error. + */ +static int +record_init_key(record* r, btree* tree, hfsp_cat_key* key) +{ + int keyind; + UInt16 node_index; + void *p = record_find_key(tree, key, &keyind, &node_index); + + if (p) + { + r -> tree = tree; + r -> node_index= node_index; + r -> keyind = keyind; + r -> key = *key; // Better use a record_key_copy ... + p = record_readentry(p, &r->record); + if (!p) + HFSP_ERROR(-1, "record_init_key: unexpected error"); + return 0; + } + fail: + return -1; +} + +/* intialize the extent_record to the extent identified by the + * (first) blockindex. + * + * forktype: either HFSP_EXTEND_DATA or HFSP_EXTEND_RSRC + */ +int record_init_file(extent_record* r, btree* tree, + UInt8 forktype, UInt32 fileId, UInt32 blockindex) +{ + int keyind; + UInt16 node_index; + hfsp_extent_key key = { 10, forktype, 0, fileId, blockindex }; + void *p = record_find_key(tree, &key, &keyind, &node_index); + + if (p) + { + r -> tree = tree; + r -> node_index= node_index; + r -> keyind = keyind; + r -> key = key; // Better use a record_key_copy ... + p = volume_readextent(p, r->extent); + if (!p) + HFSP_ERROR(-1, "record_init_file: unexpected error"); + return 0; + } + fail: + return -1; +} + +/* intialize the record to the folder identified by cnid + */ +int record_init_cnid(record* r, btree* tree, UInt32 cnid) +{ + hfsp_cat_key thread_key; // the thread is the first record + + thread_key.key_length = 6; // null name (like '.' in unix ) + thread_key.parent_cnid = cnid; + thread_key.name.strlen = 0; + + return record_init_key(r, tree, &thread_key); +} + +/* intialize the record to the first record of the parent. + */ +int record_init_parent(record* r, record* parent) +{ + if (parent->record.type == HFSP_FOLDER) + return record_init_cnid(r, parent->tree, parent->record.u.folder.id); + else if(parent->record.type == HFSP_FOLDER_THREAD) + { + if (r != parent) + *r = *parent; // The folder thread is in fact the first entry, like '.' + return 0; + } + HFSP_ERROR(EINVAL, + "record_init_parent: parent is neither folder nor folder thread."); + + fail: + return EINVAL; +} + + +/* find correct node record for given node and *pindex. + * + * index of record in this (or next) node + * */ +static node_buf* prepare_next(btree* tree, UInt16 node_index, UInt16* pindex) +{ + node_buf* buf = btree_node_by_index(tree, node_index); + btree_node_desc* desc = &buf->desc; + UInt32 numrec = desc->num_rec; + if (*pindex >= numrec) // move on to next node + { + UInt16 next = desc->next; + *pindex = 0; + if (!next /* is there a next node ? */ + || !( buf = btree_node_by_index(tree, next))) + return NULL; + } + return buf; +} +/* move record foreward to next entry. + * + * In case of an error the value of *r is undefined ! + */ +int record_next(record* r) +{ + btree* tree = r->tree; + UInt16 index = r->keyind +1; + UInt32 parent; + node_buf* buf = prepare_next(tree, r->node_index, &index); + + if (!buf) + return ENOENT; // No (more) such file or directory + + parent = r->key.parent_cnid; + + if (record_init(r, tree, buf, index)) + return -1; + + if (r->key.parent_cnid != parent || // end of current directory + index != r->keyind) // internal error ? + return ENOENT; // No (more) such file or directory + + return 0; +} + +/* move record foreward to next extent record. + * + * In case of an error the value of *r is undefined ! + */ +int record_next_extent(extent_record* r) +{ + btree* tree = r->tree; + UInt16 index = r->keyind +1; + UInt32 file_id; + UInt8 fork_type; + node_buf* buf = prepare_next(tree, r->node_index, &index); + + if (!buf) + return ENOENT; // No (more) such file or directory + + file_id = r->key.file_id; + fork_type = r->key.fork_type; + + if (record_init_extent(r, tree, buf, index)) + return -1; + + if (r->key.file_id != file_id || // end of current file + r->key.fork_type != fork_type || // end of current fork + index != r->keyind) // internal error ? + return ENOENT; // No (more) such file or directory + + return 0; +} + +/* intialize the record by searching for the given string in the given folder. + * + * parent and r may be the same. + */ +int record_init_string_parent(record* r, record* parent, char* name) +{ + hfsp_cat_key key; + + if (parent->record.type == HFSP_FOLDER) + key.parent_cnid = parent->record.u.folder.id; + else if(parent->record.type == HFSP_FOLDER_THREAD) + key.parent_cnid = parent->key.parent_cnid; + else + HFSP_ERROR(-1, "record_init_string_parent: parent is not a folder."); + + key.key_length = 6 + unicode_asc2uni(&key.name,name); // 6 for minumum size + return record_init_key(r, parent->tree, &key); + + fail: + return -1; +} + +/* move record up in folder hierarchy (if possible) */ +int record_up(record* r) +{ + if (r->record.type == HFSP_FOLDER) + { + // locate folder thread + if (record_init_cnid(r, r->tree, r->record.u.folder.id)) + return -1; + } + else if(r->record.type == HFSP_FOLDER_THREAD) + { + // do nothing were are already where we want to be + } + else + HFSP_ERROR(-1, "record_up: record is neither folder nor folder thread."); + + if(r->record.type != HFSP_FOLDER_THREAD) + HFSP_ERROR(-1, "record_up: unable to locate parent"); + return record_init_cnid(r, r->tree, r->record.u.thread.parentID); + + fail: + return -1; +} + +#ifdef DEBUG + +/* print Quickdraw Point */ +static void record_print_Point(Point* p) +{ + printf("[ v=%d, h=%d ]", p->v, p->h); +} + +/* print Quickdraw Rect */ +static void record_print_Rect(Rect* r) +{ + printf("[ top=%d, left=%d, bottom=%d, right=%d ]", + r->top, r->left, r->bottom, r->right); +} + +/* print the key of a record */ +static void record_print_key(hfsp_cat_key* key) +{ + char buf[255]; // mh this _might_ overflow + unicode_uni2asc(buf, &key->name, 255); + printf("parent cnid : %ld\n", key->parent_cnid); + printf("name : %s\n", buf); +} + +/* print permissions */ +static void record_print_perm(hfsp_perm* perm) +{ + printf("owner :\t%ld\n", perm->owner); + printf("group :\t%ld\n", perm->group); + printf("perm :\t0x%lX\n",perm->mode); + printf("dev :\t%ld\n", perm->dev); +} + +/* print Directory info */ +static void record_print_DInfo(DInfo* dinfo) +{ + printf( "frRect :\t"); record_print_Rect(&dinfo->frRect); + printf("\nfrFlags :\t0X%X\n", dinfo->frFlags); + printf( "frLocation :\t"); record_print_Point(&dinfo->frLocation); + printf("\nfrView :\t0X%X\n", dinfo->frView); +} + +/* print extended Directory info */ +static void record_print_DXInfo(DXInfo* xinfo) +{ + printf( "frScroll :\t"); record_print_Point(&xinfo->frScroll); + printf("\nfrOpenChain :\t%ld\n", xinfo->frOpenChain); + printf( "frUnused :\t%d\n", xinfo->frUnused); + printf( "frComment :\t%d\n", xinfo->frComment); + printf( "frPutAway :\t%ld\n", xinfo->frPutAway); +} + +static void record_print_folder(hfsp_cat_folder* folder) +{ + printf("flags :\t0x%X\n", folder->flags); + printf("valence :\t0x%lX\n", folder->valence); + printf("id :\t%ld\n", folder->id); + record_print_perm (&folder->permissions); + record_print_DInfo (&folder->user_info); + record_print_DXInfo (&folder->finder_info); + printf("text_encoding :\t0x%lX\n", folder->text_encoding); + printf("reserved :\t0x%lX\n", folder->reserved); +} + +/* print File info */ +static void record_print_FInfo(FInfo* finfo) +{ + printf( "fdType :\t%4.4s\n", (char*) &finfo->fdType); + printf( "fdCreator :\t%4.4s\n", (char*) &finfo->fdCreator); + printf( "fdFlags :\t0X%X\n", finfo->fdFlags); + printf( "fdLocation :\t"); record_print_Point(&finfo->fdLocation); + printf("\nfdFldr :\t%d\n", finfo->fdFldr); +} + +/* print extended File info */ +static void record_print_FXInfo(FXInfo* xinfo) +{ + printf( "fdIconID :\t%d\n", xinfo->fdIconID); + // xinfo -> fdUnused; + printf( "fdComment :\t%d\n", xinfo->fdComment); + printf( "fdPutAway :\t%ld\n", xinfo->fdPutAway); +} + +/* print folder entry */ + +/* print file entry */ +static void record_print_file(hfsp_cat_file* file) +{ + printf("flags :\t0x%X\n", file->flags); + printf("reserved1 :\t0x%lX\n", file->reserved1); + printf("id :\t%ld\n", file->id); + record_print_perm (&file->permissions); + record_print_FInfo (&file->user_info); + record_print_FXInfo (&file->finder_info); + printf("text_encoding :\t0x%lX\n", file->text_encoding); + printf("reserved :\t0x%lX\n", file->reserved2); + printf("Datafork:\n"); + volume_print_fork (&file->data_fork); + printf("Rsrcfork:\n"); + volume_print_fork (&file->res_fork); +} + +/* print info for a file or folder thread */ +static void record_print_thread(hfsp_cat_thread* entry) +{ + char buf[255]; // mh this _might_ overflow + unicode_uni2asc(buf, &entry->nodeName, 255); + printf("parent cnid :\t%ld\n", entry->parentID); + printf("name :\t%s\n" , buf); +} + +/* print the information for a record */ +static void record_print_entry(hfsp_cat_entry* entry) +{ + switch (entry->type) + { + case HFSP_FOLDER: + printf("=== Folder ===\n"); + return record_print_folder(&entry->u.folder); + case HFSP_FILE: + printf("=== File ===\n"); + return record_print_file (&entry->u.file); + case HFSP_FOLDER_THREAD: + printf("=== Folder Thread ===\n"); + return record_print_thread(&entry->u.thread); + case HFSP_FILE_THREAD: + printf("=== File Thread ==\n"); + return record_print_thread(&entry->u.thread); + default: + printf("=== Unknown Record Type ===\n"); + } ; +} + + /* Dump all the record information to stdout */ +void record_print(record* r) +{ + printf ("keyind : %u\n", r->keyind); + record_print_key (&r->key); + record_print_entry(&r->record); +} + +#endif + diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c new file mode 100644 index 0000000..e5ce4ad --- /dev/null +++ b/fs/hfsplus/unicode.c @@ -0,0 +1,508 @@ +/* + * linux/fs/hfsplus/unicode.c + * + * Copyright (C) 1999-2000 Brad Boyer (flar@pants.nu) + * This file may be distributed under the terms of the GNU Public License. + * + * The routines found here convert hfs-unicode string into ascii Strings + * and vice versa. And the correct comparison between Strings. + */ + + +#include "openbios/config.h" +#include "libhfsp.h" +#include "unicode.h" + +/* ISO-8859-1 -> unicode */ +static int +asc2uni( unsigned char *ustr, const char *astr, int maxlen ) +{ + int len; + + if( maxlen <= 0 ) + return 0; + + for( len=0; *astr && len < maxlen-1 ; astr++, len++ ) { + *ustr++ = 0; + *ustr++ = *astr; + } + ustr[0] = ustr[1] = 0; + return len; +} + +/* unicode -> ISO-8859-1 */ +static int +uni2asc( char *astr, const unsigned char *ustr, int ustrlen, int maxlen ) +{ + int len; + + if( maxlen <= 0 ) + return 0; + + for( len=0; ustrlen-- > 0 && len < maxlen-1 ; ustr += 2 ) { + /* might be unrepresentable (or too complicated for us) */ + if( ustr[0] || !ustr[1] ) + continue; + *astr++ = ustr[1]; + len++; + } + *astr = 0; + return len; +} + +int +unicode_asc2uni( hfsp_unistr255 *ustr, const char* astr ) +{ + return ustr->strlen = asc2uni( (u8*)ustr->name, astr, 255 ); +} + +int +unicode_uni2asc(char *astr, const hfsp_unistr255 *ustr, int maxlen) +{ + return uni2asc( astr, (u8*)ustr->name, ustr->strlen, maxlen ); +} + +/* The following code is almost as published by Apple, only + small modifications where made to match some linux styles ... + +fastUnicodeCompare - Compare two Unicode strings; produce a relative ordering +*/ + +static UInt16 gLowerCaseTable[]; + +SInt32 fast_unicode_compare ( const hfsp_unistr255 *ustr1, + const hfsp_unistr255 *ustr2) +{ + register UInt16 c1,c2; + register SInt32 diff; + register UInt16 temp; + register UInt16 length1 = ustr1->strlen; + register UInt16 length2 = ustr2->strlen; + register UInt16* lowerCaseTable = gLowerCaseTable; + register UInt16* str1 = ustr1->name; + register UInt16* str2 = ustr2->name; + + while (1) { + // Set default values for c1, c2 in case there are no more valid chars + c1 = c2 = 0; + // Find next non-ignorable char from str1, or zero if no more + while (length1 && c1 == 0) { + c1 = *(str1++); + --length1; + if ((temp = lowerCaseTable[c1>>8]) != 0) // is there a subtable + // for this upper byte? + c1 = lowerCaseTable[temp + (c1 & 0x00FF)]; // yes, so fold the char + } + // Find next non-ignorable char from str2, or zero if no more + while (length2 && c2 == 0) { + c2 = *(str2++); + --length2; + if ((temp = lowerCaseTable[c2>>8]) != 0) // is there a subtable + // for this upper byte? + c2 = lowerCaseTable[temp + (c2 & 0x00FF)]; // yes, so fold the char + } + diff = c2-c1; + if (diff) // found a difference, so stop looping + break; + if (c1 == 0) // did we reach the end of both strings at the same time? + return 0; // yes, so strings are equal + } + return diff; +} + + +/* The lower case table consists of a 256-entry high-byte table followed by + some number of 256-entry subtables. The high-byte table contains either an + offset to the subtable for characters with that high byte or zero, which + means that there are no case mappings or ignored characters in that block. + Ignored characters are mapped to zero. + */ + +static UInt16 gLowerCaseTable[] = { + + // High-byte indices ( == 0 iff no case mapping and no ignorables ) + + + /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00, + + // Table 1 (for high byte 0x00) + + /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF, + /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, + + // Table 2 (for high byte 0x01) + + /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, + 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F, + /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, + 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F, + /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, + 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, + /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, + 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140, + /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, + 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F, + /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, + 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F, + /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, + 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F, + /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, + 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F, + /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, + 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259, + /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, + 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275, + /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, + 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF, + /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, + 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF, + /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, + 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF, + /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, + 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF, + /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, + 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF, + /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, + 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF, + + // Table 3 (for high byte 0x03) + + /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, + /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F, + /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F, + /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F, + /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, + 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F, + /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, + 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F, + /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, + 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F, + /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, + 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F, + /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, + 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F, + /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF, + /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, + 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF, + /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, + 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF, + /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, + 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF, + + // Table 4 (for high byte 0x04) + + /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, + 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F, + /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F, + /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, + 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F, + /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, + 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F, + /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F, + /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, + 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F, + /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, + 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF, + /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, + 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF, + /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, + 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF, + /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, + 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF, + /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, + 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF, + /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, + 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF, + + // Table 5 (for high byte 0x05) + + /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, + 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F, + /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, + 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F, + /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, + 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F, + /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, + /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, + /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, + 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F, + /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, + /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, + /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, + 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F, + /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, + 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F, + /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, + 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF, + /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, + 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF, + /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF, + /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, + 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF, + + // Table 6 (for high byte 0x10) + + /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, + 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F, + /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, + 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F, + /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, + 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F, + /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, + 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F, + /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, + 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F, + /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, + 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F, + /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, + 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F, + /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, + 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F, + /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, + 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F, + /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, + 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F, + /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, + 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, + /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, + 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, + /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, + 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF, + /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, + 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, + /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, + 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, + /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, + 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF, + + // Table 7 (for high byte 0x20) + + /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, + 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000, + /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, + 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F, + /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, + 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F, + /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, + 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F, + /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, + 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F, + /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, + 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F, + /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, + 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, + 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F, + /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, + 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F, + /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, + 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F, + /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, + 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF, + /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, + 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF, + /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, + 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF, + /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, + 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF, + /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, + 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF, + /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, + 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF, + + // Table 8 (for high byte 0x21) + + /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, + 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F, + /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, + 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F, + /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, + 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F, + /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, + 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F, + /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, + 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F, + /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, + 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F, + /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, + /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, + /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, + 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F, + /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, + 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F, + /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, + 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF, + /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, + 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF, + /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, + 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF, + /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, + 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF, + /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, + 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF, + /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, + 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF, + + // Table 9 (for high byte 0xFE) + + /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, + 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F, + /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, + 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F, + /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, + 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F, + /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, + 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F, + /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, + 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F, + /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, + 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F, + /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, + 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F, + /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, + 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F, + /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, + 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F, + /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, + 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F, + /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, + 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF, + /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, + 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF, + /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, + 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF, + /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, + 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF, + /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, + 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF, + /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, + 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000, + + // Table 10 (for high byte 0xFF) + + /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, + 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F, + /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, + 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F, + /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, + 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, + /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, + 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F, + /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, + 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, + /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, + 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F, + /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, + 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F, + /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, + 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F, + /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, + 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F, + /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, + 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F, + /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, + 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF, + /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, + 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF, + /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, + 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF, + /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, + 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF, + /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, + 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF, + /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, + 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF, +}; diff --git a/fs/hfsplus/volume.c b/fs/hfsplus/volume.c new file mode 100644 index 0000000..7d9dc0e --- /dev/null +++ b/fs/hfsplus/volume.c @@ -0,0 +1,289 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * Code to acces the basic volume information of a HFS+ volume. + * + * Copyright (C) 2000 Klaus Halfmann + * Original work by 1996-1998 Robert Leslie + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: volume.c,v 1.21 2000/10/25 05:43:04 hasi Exp $ + */ + +#include "openbios/config.h" +#include "libhfsp.h" +#include "volume.h" +#include "record.h" +#include "btree.h" +#include "blockiter.h" +#include "os.h" +#include "swab.h" +#include "hfstime.h" + +/* Fill a given buffer with the given block in volume. + */ +int +volume_readinbuf(volume * vol,void* buf, long block) +{ + UInt16 blksize_bits; + ASSERT( block < vol->maxblocks); + + blksize_bits = vol->blksize_bits; + block += vol->startblock; + if( os_seek(vol->os_fd, block, blksize_bits) == block) + if( 1 == os_read(vol->os_fd, buf, 1, blksize_bits)) + return 0; + return -1; +} + +/* read multiple blocks into given memory. + * + * returns given pinter or NULL on failure. + */ +void* +volume_readfromfork(volume* vol, void* buf, + hfsp_fork_raw* f, UInt32 block, + UInt32 count, UInt8 forktype, UInt32 fileId) +{ + blockiter iter; + char *cbuf = buf; + + blockiter_init(&iter, vol, f, forktype, fileId); + if( blockiter_skip(&iter, block)) + return NULL; + + while( count > 0) { + --count; + if( volume_readinbuf(vol, cbuf, blockiter_curr(&iter))) + return NULL; + cbuf += vol->blksize; + if( count > 0 && blockiter_next(&iter)) + return NULL; + } + return buf; +} + + +/* Read a raw hfsp_extent_rec from memory. + * + * return pointer right after the structure. + */ +void* +volume_readextent(void *p, hfsp_extent_rec er) +{ + int i; + hfsp_extent *e; + + for( i=0; i < 8; i++) { + e = &er[i]; + e->start_block = bswabU32_inc(p); + e->block_count = bswabU32_inc(p); + } + return p; +} + +/* Read a raw hfsp_fork from memory. + * + * return pointer right after the structure. + */ +void* +volume_readfork(void *p, hfsp_fork_raw* f) +{ + f->total_size = bswabU64_inc(p); + f->clump_size = bswabU32_inc(p); + f->total_blocks = bswabU32_inc(p); + + return volume_readextent(p, f->extents); +} + +/* Read the volume from the given buffer and swap the bytes. + * + * ToDo: add more consitency checks. + */ +static int +volume_readbuf(volume * vol, hfsp_vh* vh, void* p) +{ + if( (vh->signature = bswabU16_inc(p)) != HFSP_VOLHEAD_SIG) + HFSP_ERROR(-1, "This is not a HFS+ volume"); + + vh->version = bswabU16_inc(p); + vh->attributes = bswabU32_inc(p); + vh->last_mount_vers = bswabU32_inc(p); + vh->reserved = bswabU32_inc(p); + vh->create_date = bswabU32_inc(p); + vh->modify_date = bswabU32_inc(p); + vh->backup_date = bswabU32_inc(p); + vh->checked_date = bswabU32_inc(p); + vh->file_count = bswabU32_inc(p); + vh->folder_count = bswabU32_inc(p); + vh->blocksize = bswabU32_inc(p); + vh->total_blocks = bswabU32_inc(p); + vh->free_blocks = bswabU32_inc(p); + vh->next_alloc = bswabU32_inc(p); + vh->rsrc_clump_sz = bswabU32_inc(p); + vh->data_clump_sz = bswabU32_inc(p); + vh->next_cnid = bswabU32_inc(p); + vh->write_count = bswabU32_inc(p); + vh->encodings_bmp = bswabU64_inc(p); + memcpy(vh->finder_info, p, 32); + ((char*) p) += 32; // So finderinfo must be swapped later, *** + p = volume_readfork(p, &vh->alloc_file ); + p = volume_readfork(p, &vh->ext_file ); + p = volume_readfork(p, &vh->cat_file ); + p = volume_readfork(p, &vh->attr_file ); + p = volume_readfork(p, &vh->start_file ); + return 0; + fail: + return -1; +} + +/* Read the volume from the given block */ +static int +volume_read(volume * vol, hfsp_vh* vh, UInt32 block) +{ + char buf[vol->blksize]; + + if( volume_readinbuf(vol, buf, block)) + return -1; + return volume_readbuf(vol, vh, buf); +} + +/* Find out wether the volume is wrapped and unwrap it eventually */ +static int +volume_read_wrapper(volume * vol, hfsp_vh* vh) +{ + UInt16 signature; + char buf[vol->blksize]; + void *p = buf; + + if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here + return -1; + + signature = bswabU16_inc(p); + if( signature == HFS_VOLHEAD_SIG) { /* Wrapper */ + UInt32 drAlBlkSiz; /* size (in bytes) of allocation blocks */ + UInt32 sect_per_block; /* how may block build an hfs sector */ + UInt16 drAlBlSt; /* first allocation block in volume */ + UInt16 embeds, embedl; /* Start/lenght of embedded area in blocks */ + + ((char*) p) += 0x12; /* skip unneded HFS vol fields */ + drAlBlkSiz = bswabU32_inc(p); /* offset 0x14 */ + ((char*) p) += 0x4; /* skip unneded HFS vol fields */ + drAlBlSt = bswabU16_inc(p); /* offset 0x1C */ + + ((char*) p) += 0x5E; /* skip unneded HFS vol fields */ + signature = bswabU16_inc(p); /* offset 0x7C, drEmbedSigWord */ + if( signature != HFSP_VOLHEAD_SIG) + HFSP_ERROR(-1, "This looks like a normal HFS volume"); + embeds = bswabU16_inc(p); + embedl = bswabU16_inc(p); + sect_per_block = (drAlBlkSiz / HFSP_BLOCKSZ); + // end is absolute (not relative to HFS+ start) + vol->maxblocks = embedl * sect_per_block; + vol->startblock = drAlBlSt + embeds * sect_per_block; + /* Now we can try to read the embedded HFS+ volume header */ + return volume_read(vol,vh,2); + } + else if( signature == HFSP_VOLHEAD_SIG) { /* Native HFS+ volume */ + p = buf; // Restore to begin of block + return volume_readbuf(vol, vh, p); + } else + HFSP_ERROR(-1, "Neither Wrapper nor native HFS+ volume header found"); +fail: + return -1; +} + + +/* Open the device, read and verify the volume header + (and its backup) */ +int +volume_open( volume* vol, int os_fd ) +{ + hfsp_vh backup; /* backup volume found at second to last block */ + long sect_per_block; + int shift; + + vol->blksize_bits = HFSP_BLOCKSZ_BITS; + vol->blksize = HFSP_BLOCKSZ; + vol->startblock = 0; + vol->maxblocks = 3; + /* this should be enough until we find the volume descriptor */ + vol->extents = NULL; /* Thanks to Jeremias Sauceda */ + + btree_reset(&vol->catalog); + vol->os_fd = os_fd; + + // vol->maxblocks = os_seek(vol->os_fd, -1, HFSP_BLOCKSZ_BITS); + // This wont work for /dev/... but we do not really need it + + if( volume_read_wrapper(vol, &vol->vol)) + return -1; + if( volume_read(vol, &backup, vol->maxblocks - 2)) + return -1; + + /* Now switch blksize from HFSP_BLOCKSZ (512) to value given in header + and adjust depend values accordingly, after that a block always + means a HFS+ allocation size */ + + /* Usually 4096 / 512 == 8 */ + sect_per_block = vol->vol.blocksize / HFSP_BLOCKSZ; + shift = 0; + if( sect_per_block > 1) { + shift = 1; + while( sect_per_block > 2) { + sect_per_block >>=1; + shift++; + } /* shift = 3 */ + } + vol -> blksize_bits += shift; + vol -> blksize = 1 << vol->blksize_bits; + vol -> startblock >>= shift; + vol -> maxblocks = vol->vol.total_blocks; /* cant calculate via shift ? */ + + if( btree_init_cat(&vol->catalog, vol, &vol->vol.cat_file)) + return -1; + + return 0; +} + +/* Write back all data eventually cached and close the device */ +int +volume_close(volume* vol) +{ + btree_close(&vol->catalog); + if( vol->extents) { + btree_close(vol->extents); + FREE(vol->extents); + } + return 0; +} + +/* internal fucntion used to create the extents btree, + is called by inline function when needed */ +void +volume_create_extents_tree(volume* vol) +{ + btree* result = (btree*) ALLOC(btree*, sizeof(btree)); + if( !result) + HFSP_ERROR(ENOMEM, "No memory for extents btree"); + if( !btree_init_extent(result, vol, &vol->vol.ext_file)) { + vol->extents = result; + return; + } + fail: + vol->extents = NULL; +} diff --git a/fs/ioglue.c b/fs/ioglue.c new file mode 100644 index 0000000..e8a3a57 --- /dev/null +++ b/fs/ioglue.c @@ -0,0 +1,86 @@ +/* + * Creation Date: <2001/05/06 22:27:09 samuel> + * Time-stamp: <2003/12/12 02:24:56 samuel> + * + * + * + * I/O API used by the filesystem code + * + * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/fs.h" +#include "libc/diskio.h" +#include "os.h" +#include "hfs_mdb.h" + +/************************************************************************/ +/* functionsions used by the various filesystems */ +/************************************************************************/ + +char * +get_hfs_vol_name( int fd, char *buf, int size ) +{ + char sect[512]; + hfs_mdb_t *mdb = (hfs_mdb_t*)§ + + seek_io( fd, 0x400 ); + read_io( fd, sect, sizeof(sect) ); + if( hfs_get_ushort(mdb->drSigWord) == HFS_SIGNATURE ) { + unsigned int n = mdb->drVN[0]; + if( n >= size ) + n = size - 1; + memcpy( buf, &mdb->drVN[1], n ); + buf[n] = 0; + } else if( hfs_get_ushort(mdb->drSigWord) == HFS_PLUS_SIGNATURE ) { + strncpy( buf, "Unembedded HFS+", size ); + } else { + strncpy( buf, "Error", size ); + } + return buf; +} + +ulong +os_read( int fd, void *buf, ulong len, int blksize_bits ) +{ + /* printk("os_read %d\n", (int)len); */ + + int cnt = read_io( fd, buf, len << blksize_bits ); + return (cnt > 0)? (cnt >> blksize_bits) : cnt; +} + +ulong +os_seek( int fd, ulong blknum, int blksize_bits ) +{ + /* printk("os_seek %d\n", blknum ); */ + llong offs = (llong)blknum << blksize_bits; + + /* offset == -1 means seek to EOF */ + if( (int)blknum == -1 ) + offs = -1; + + if( seek_io(fd, offs) ) { + printk("os_seek failure\n"); + return (ulong)-1; + } + + if( (int)blknum == -1 ) { + if( (offs=tell(fd)) < 0 ) + return -1; + blknum = offs >> blksize_bits; + } + return blknum; +} + +int +os_same( int fd1, int fd2 ) +{ + return fd1 == fd2; +} diff --git a/fs/os.h b/fs/os.h new file mode 100644 index 0000000..1aa38ea --- /dev/null +++ b/fs/os.h @@ -0,0 +1,50 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * Copyright (C) 1996-1998, 2003 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: os.h,v 1.1.1.1 2000/07/25 10:33:40 kkaempf Exp $ + */ + +#ifndef _H_OS +#define _H_OS + +/* + * NAME: os->same() + * DESCRIPTION: return 1 iff path is same as the open descriptor + */ +int os_same( int fd1, int fd2 ); + +/* + * NAME: os->seek() + * DESCRIPTION: set a descriptor's seek pointer (offset in blocks) + */ +unsigned long os_seek( int fd, unsigned long offset, int blksize_bits); + +/* + * NAME: os->read() + * DESCRIPTION: read blocks from an open descriptor + */ +unsigned long os_read( int fd, void *buf, unsigned long len, int blksize_bits); + +/* + * NAME: os->write() + * DESCRIPTION: write blocks to an open descriptor + */ +unsigned long os_write( int fd, const void *buf, unsigned long len, int blksize_bits); + + +#endif /* _H_OS */ diff --git a/include/amd64/elf.h b/include/amd64/elf.h new file mode 100644 index 0000000..e391c62 --- /dev/null +++ b/include/amd64/elf.h @@ -0,0 +1,6 @@ +/* for now we're a 32bit architecture */ +#define ARCH_ELF_CLASS ELFCLASS32 +#define ARCH_ELF_DATA ELFDATA2LSB +#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486) +typedef Elf32_Ehdr Elf_ehdr; +typedef Elf32_Phdr Elf_phdr; diff --git a/include/amd64/io.h b/include/amd64/io.h new file mode 100644 index 0000000..18a3efe --- /dev/null +++ b/include/amd64/io.h @@ -0,0 +1,68 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +extern unsigned long virt_offset; + +#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset)) +#define virt_to_phys(virt) ((unsigned long) (virt) + virt_offset) + +#define __SLOW_DOWN_IO "outb %%al,$0x80;" +static inline void slow_down_io(void) +{ + __asm__ __volatile__( + __SLOW_DOWN_IO +#ifdef REALLY_SLOW_IO + __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + : : ); +} + +#define BUILDIO(bwl,bw,type) \ +static inline void out##bwl(unsigned type value, int port) { \ + __asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \ +} \ +static inline unsigned type in##bwl(int port) { \ + unsigned type value; \ + __asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \ + return value; \ +} \ +static inline void out##bwl##_p(unsigned type value, int port) { \ + out##bwl(value, port); \ + slow_down_io(); \ +} \ +static inline unsigned type in##bwl##_p(int port) { \ + unsigned type value = in##bwl(port); \ + slow_down_io(); \ + return value; \ +} \ +static inline void outs##bwl(int port, const void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \ +} \ +static inline void ins##bwl(int port, void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \ +} + +#ifndef BOOTSTRAP +BUILDIO(b,b,char) +BUILDIO(w,w,short) +BUILDIO(l,,int) +#else +#ifdef FCOMPILER +#define inb(reg) ((u8)0xff) +#define inw(reg) ((u16)0xffff) +#define inl(reg) ((u32)0xffffffff) +#define outb(reg, val) /* nothing */ +#define outw(reg, val) /* nothing */ +#define outl(reg, val) /* nothing */ +#else +extern u8 inb( u32 reg ); +extern u16 inw( u32 reg ); +extern u32 inl( u32 reg ); +extern void insw( u32 reg, void *addr, unsigned long count ); +extern void outb( u32 reg, u8 val ); +extern void outw( u32 reg, u16 val ); +extern void outl( u32 reg, u32 val ); +extern void outsw( u32 reg, const void *addr, unsigned long count); +#endif +#endif +#endif diff --git a/include/amd64/types.h b/include/amd64/types.h new file mode 100644 index 0000000..cfaa708 --- /dev/null +++ b/include/amd64/types.h @@ -0,0 +1,43 @@ +/* tag: data types for forth engine + * + * This file is autogenerated by types.sh. Do not edit! + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __TYPES_H +#define __TYPES_H + +#include + +/* endianess */ +#include + +/* cell based types */ + +typedef int64_t cell; +typedef uint64_t ucell; +typedef __int128_t dcell; +typedef __uint128_t ducell; + +#define bitspercell (sizeof(cell)<<3) +#define bitsperdcell (sizeof(dcell)<<3) + +#define BITS 64 + +/* size named types */ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long u64; + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long s64; + +#endif diff --git a/include/elf_boot.h b/include/elf_boot.h new file mode 100644 index 0000000..f9a026b --- /dev/null +++ b/include/elf_boot.h @@ -0,0 +1,104 @@ +#ifndef ELF_BOOT_H +#define ELF_BOOT_H + + +/* This defines the structure of a table of parameters useful for ELF + * bootable images. These parameters are all passed and generated + * by the bootloader to the booted image. For simplicity and + * consistency the Elf Note format is reused. + * + * All of the information must be Position Independent Data. + * That is it must be safe to relocate the whole ELF boot parameter + * block without changing the meaning or correctnes of the data. + * Additionally it must be safe to permute the order of the ELF notes + * to any possible permutation without changing the meaning or correctness + * of the data. + * + */ + +#define ELF_BHDR_MAGIC 0x0E1FB007 + +#ifndef __ASSEMBLY__ +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; + +/* + * Elf boot notes... + */ + +typedef struct Elf_Bhdr +{ + Elf_Word b_signature; /* "0x0E1FB007" */ + Elf_Word b_size; + Elf_Half b_checksum; + Elf_Half b_records; +} Elf_Bhdr; + +/* + * ELF Notes. + */ + +typedef struct Elf_Nhdr +{ + Elf_Word n_namesz; /* Length of the note's name. */ + Elf_Word n_descsz; /* Length of the note's descriptor. */ + Elf_Word n_type; /* Type of the note. */ +} Elf_Nhdr; + +#endif /* __ASSEMBLY__ */ + +/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */ +#define ELF_NOTE_BOOT "ELFBoot" + +#define EIN_PROGRAM_NAME 0x00000001 +/* The program in this ELF file */ +#define EIN_PROGRAM_VERSION 0x00000002 +/* The version of the program in this ELF file */ +#define EIN_PROGRAM_CHECKSUM 0x00000003 +/* ip style checksum of the memory image. */ + + +/* Linux image notes for booting... The name for all of these is Linux */ + +#define LIN_COMMAND_LINE 0x00000001 +/* The command line to pass to the loaded kernel. */ +#define LIN_ROOT_DEV 0x00000002 +/* The root dev to pass to the loaded kernel. */ +#define LIN_RAMDISK_FLAGS 0x00000003 +/* Various old ramdisk flags */ +#define LIN_INITRD_START 0x00000004 +/* Start of the ramdisk in bytes */ +#define LIN_INITRD_SIZE 0x00000005 +/* Size of the ramdisk in bytes */ + +/* Notes that are passed to a loaded image */ +/* For the standard elf boot notes n_namesz must be zero */ +#define EBN_FIRMWARE_TYPE 0x00000001 +/* ASCIZ name of the platform firmware. */ +#define EBN_BOOTLOADER_NAME 0x00000002 +/* This specifies just the ASCIZ name of the bootloader */ +#define EBN_BOOTLOADER_VERSION 0x00000003 +/* This specifies the version of the bootloader as an ASCIZ string */ +#define EBN_COMMAND_LINE 0x00000004 +/* This specifies a command line that can be set by user interaction, + * and is provided as a free form ASCIZ string to the loaded image. + */ +#define EBN_NOP 0x00000005 +/* A note nop note has no meaning, useful for inserting explicit padding */ +#define EBN_LOADED_IMAGE 0x00000006 +/* An ASCIZ string naming the loaded image */ + + +/* Etherboot specific notes */ +#define EB_PARAM_NOTE "Etherboot" +#define EB_IA64_SYSTAB 0x00000001 +#define EB_IA64_MEMMAP 0x00000002 +#define EB_IA64_FPSWA 0x00000003 +#define EB_IA64_CONINFO 0x00000004 +#define EB_BOOTP_DATA 0x00000005 +#define EB_HEADER 0x00000006 +#define EB_IA64_IMAGE_HANDLE 0x00000007 +#define EB_I386_MEMMAP 0x00000008 + + +#endif /* ELF_BOOT_H */ diff --git a/include/ia64/elf.h b/include/ia64/elf.h new file mode 100644 index 0000000..782ddc7 --- /dev/null +++ b/include/ia64/elf.h @@ -0,0 +1,5 @@ +#define ARCH_ELF_CLASS ELFCLASS64 +#define ARCH_ELF_DATA ELFDATA2LSB +#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_IA64) +typedef Elf64_Ehdr Elf_ehdr; +typedef Elf64_Phdr Elf_phdr; diff --git a/include/ia64/io.h b/include/ia64/io.h new file mode 100644 index 0000000..7719a13 --- /dev/null +++ b/include/ia64/io.h @@ -0,0 +1,59 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +extern unsigned long virt_offset; + +#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset)) +#define virt_to_phys(virt) ((unsigned long) (virt) + virt_offset) + +#define __SLOW_DOWN_IO "outb %%al,$0x80;" +static inline void slow_down_io(void) +{ + __asm__ __volatile__( + __SLOW_DOWN_IO +#ifdef REALLY_SLOW_IO + __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + : : ); +} + +#define BUILDIO(bwl,bw,type) \ +static inline void out##bwl(unsigned type value, int port) { \ + __asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \ +} \ +static inline unsigned type in##bwl(int port) { \ + unsigned type value; \ + __asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \ + return value; \ +} \ +static inline void out##bwl##_p(unsigned type value, int port) { \ + out##bwl(value, port); \ + slow_down_io(); \ +} \ +static inline unsigned type in##bwl##_p(int port) { \ + unsigned type value = in##bwl(port); \ + slow_down_io(); \ + return value; \ +} \ +static inline void outs##bwl(int port, const void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \ +} \ +static inline void ins##bwl(int port, void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \ +} + +#ifndef BOOTSTRAP +BUILDIO(b,b,char) +BUILDIO(w,w,short) +BUILDIO(l,,int) +#else +extern u8 inb( u32 reg ); +extern u16 inw( u32 reg ); +extern u32 inl( u32 reg ); +extern void insw( u32 reg, void *addr, unsigned long count ); +extern void outb( u32 reg, u8 val ); +extern void outw( u32 reg, u16 val ); +extern void outl( u32 reg, u32 val ); +extern void outsw( u32 reg, const void *addr, unsigned long count); +#endif +#endif diff --git a/include/ia64/types.h b/include/ia64/types.h new file mode 100644 index 0000000..5bf065a --- /dev/null +++ b/include/ia64/types.h @@ -0,0 +1,44 @@ +/* tag: data types for forth engine + * + * This file is autogenerated by types.sh. Do not edit! + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __TYPES_H +#define __TYPES_H + +#include + +/* endianess */ + +#include + +/* cell based types */ + +typedef int64_t cell; +typedef uint64_t ucell; +typedef __int128_t dcell; +typedef __uint128_t ducell; + +#define bitspercell (sizeof(cell)<<3) +#define bitsperdcell (sizeof(dcell)<<3) + +#define BITS 64 + +/* size named types */ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long u64; + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long s64; + +#endif diff --git a/include/ipchecksum.h b/include/ipchecksum.h new file mode 100644 index 0000000..24cc1d7 --- /dev/null +++ b/include/ipchecksum.h @@ -0,0 +1,7 @@ +#ifndef IPCHECKSUM_H +#define IPCHECKSUM_H + +unsigned short ipchksum(const void *data, unsigned long length); +unsigned short add_ipchksums(unsigned long offset, unsigned short sum, unsigned short new); + +#endif /* IPCHECKSUM_H */ diff --git a/include/libc/byteorder.h b/include/libc/byteorder.h new file mode 100644 index 0000000..046d13d --- /dev/null +++ b/include/libc/byteorder.h @@ -0,0 +1,42 @@ +/* tag: byteorder prototypes + * + * Copyright (C) 2004 Stefan Reinauer + * + * see the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ +#ifndef __BYTEORDER_H +#define __BYTEORDER_H + +#define __bswap32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define __bswap16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) + + +#ifdef CONFIG_LITTLE_ENDIAN +#define __cpu_to_le32(x) ((u32) (x)) +#define __le32_to_cpu(x) ((u32) (x)) +#define __cpu_to_le16(x) ((u16) (x)) +#define __le16_to_cpu(x) ((u16) (x)) +#define __cpu_to_be32(x) (__bswap32((u32) (x))) +#define __be32_to_cpu(x) (__bswap32((u32) (x))) +#define __cpu_to_be16(x) (__bswap16((u16) (x))) +#define __be16_to_cpu(x) (__bswap16((u16) (x))) +#endif +#ifdef CONFIG_BIG_ENDIAN +#define __cpu_to_le32(x) (__bswap32((u32) (x))) +#define __le32_to_cpu(x) (__bswap32((u32) (x))) +#define __cpu_to_le16(x) (__bswap16((u16) (x))) +#define __le16_to_cpu(x) (__bswap16((u16) (x))) +#define __cpu_to_be32(x) ((u32) (x)) +#define __be32_to_cpu(x) ((u32) (x)) +#define __cpu_to_be16(x) ((u16) (x)) +#define __be16_to_cpu(x) ((u16) (x)) +#endif + + + +#endif + diff --git a/include/libc/diskio.h b/include/libc/diskio.h new file mode 100644 index 0000000..cf0c526 --- /dev/null +++ b/include/libc/diskio.h @@ -0,0 +1,33 @@ +/* + * Creation Date: <2003/12/20 00:57:01 samuel> + * Time-stamp: <2004/01/07 19:32:29 samuel> + * + * + * + * + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_DISKIO +#define _H_DISKIO + +extern int open_ih( ihandle_t ih ); +extern int open_io( const char *spec ); +extern int close_io( int fd ); +extern int read_io( int fd, void *buf, size_t cnt ); +extern int seek_io( int fd, llong offs ); +extern llong tell( int fd ); +extern int reopen( int fd, const char *filename ); +extern int reopen_nwrom( int fd ); +extern ihandle_t get_ih_from_fd( int fd ); +const char *get_file_path( int fd ); +const char *get_fstype( int fd ); +const char *get_volume_name( int fd ); + +#endif /* _H_DISKIO */ diff --git a/include/libc/stdlib.h b/include/libc/stdlib.h new file mode 100644 index 0000000..b92fc9d --- /dev/null +++ b/include/libc/stdlib.h @@ -0,0 +1,26 @@ +/* + * Creation Date: <2003/12/19 18:52:20 samuel> + * Time-stamp: <2003/12/19 18:52:21 samuel> + * + * + * + * + * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_STDLIB +#define _H_STDLIB + +extern void *malloc( int size ); +extern void free( void *ptr ); +extern void *realloc( void *ptr, size_t size ); + +/* should perhaps go somewhere else... */ +extern void qsort( void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); + +#endif /* _H_STDLIB */ diff --git a/include/libc/string.h b/include/libc/string.h new file mode 100644 index 0000000..92350c9 --- /dev/null +++ b/include/libc/string.h @@ -0,0 +1,99 @@ +/* + * Creation Date: <2002/10/12 20:41:57 samuel> + * Time-stamp: <2003/10/25 12:51:22 samuel> + * + * + * + * string library functions + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_STRING +#define _H_STRING + +#define bzero(s,n) memset( s, 0, n ) +#define atol(nptr) strtol(nptr, NULL, 10 ) + +extern long strtol( const char *nptr, char **endptr, int base ); + +extern int strnicmp(const char *s1, const char *s2, size_t len); +extern char *strcpy(char * dest,const char *src); +extern char *strncpy(char * dest,const char *src,size_t count); +extern char *strcat(char * dest, const char * src); +extern char *strncat(char *dest, const char *src, size_t count); +extern int strcmp(const char * cs,const char * ct); +extern int strncmp(const char * cs,const char * ct,size_t count); +extern char *strchr(const char * s, int c); +extern char *strrchr(const char * s, int c); +extern size_t strlen(const char * s); +extern size_t strnlen(const char * s, size_t count); +extern size_t strspn(const char *s, const char *accept); +extern char *strpbrk(const char * cs,const char * ct); +extern char *strtok(char * s,const char * ct); +extern char *strsep(char **s, const char *ct); +extern void *memset(void * s,int c,size_t count); +extern char *bcopy(const char * src, char * dest, int count); +extern void *memcpy(void * dest,const void *src,size_t count); +extern void *memmove(void * dest,const void *src,size_t count); +extern int memcmp(const void * cs,const void * ct,size_t count); +extern void *memscan(void * addr, int c, size_t size);void * memscan(void * addr, int c, size_t size); +extern char *strstr(const char * s1,const char * s2); +extern void *memchr(const void *s, int c, size_t n); + +extern char *strdup( const char *str ); +extern int strcasecmp( const char *cs, const char *ct ); + +extern char *strncpy_nopad( char *dest, const char *src, size_t n ); + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern unsigned char _ctype[]; + +#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) + +#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) +#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) +#define iscntrl(c) ((__ismask(c)&(_C)) != 0) +#define isdigit(c) ((__ismask(c)&(_D)) != 0) +#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) +#define islower(c) ((__ismask(c)&(_L)) != 0) +#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) +#define ispunct(c) ((__ismask(c)&(_P)) != 0) +#define isspace(c) ((__ismask(c)&(_S)) != 0) +#define isupper(c) ((__ismask(c)&(_U)) != 0) +#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define toascii(c) (((unsigned char)(c))&0x7f) + + +static inline unsigned char __tolower(unsigned char c) { + if (isupper(c)) + c -= 'A'-'a'; + return c; +} + +static inline unsigned char __toupper(unsigned char c) { + if (islower(c)) + c -= 'a'-'A'; + return c; +} + +#define tolower(c) __tolower(c) +#define toupper(c) __toupper(c) + + +#endif /* _H_STRING */ diff --git a/include/libc/vsprintf.h b/include/libc/vsprintf.h new file mode 100644 index 0000000..b760224 --- /dev/null +++ b/include/libc/vsprintf.h @@ -0,0 +1,24 @@ +/* + * Creation Date: <2003/12/20 01:51:22 samuel> + * Time-stamp: <2004/01/07 19:02:17 samuel> + * + * + * + * + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_VSPRINTF +#define _H_VSPRINTF + +#include +extern int vsprintf(char *buf, const char *fmt, va_list args ); +extern int sprintf(char * buf, const char *fmt, ...); + +#endif /* _H_VSPRINTF */ diff --git a/include/mconfig.h b/include/mconfig.h new file mode 100644 index 0000000..2040ca0 --- /dev/null +++ b/include/mconfig.h @@ -0,0 +1,79 @@ +/* + * We got rid of configure for now, and I hope it stays like this. + * This file may have to be changed/reworked completely + * + * + */ + +/* mconfig.h. Generated by configure. */ +/* mconfig.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACHINE_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Minor OpenBIOS version */ +#define MINOR_VERSION 0 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Patchlevel */ +#define PATCH_LEVEL RC1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version */ +#define VERSION "1.0.RC1" + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ diff --git a/include/ofmem.h b/include/ofmem.h new file mode 100644 index 0000000..f6d5174 --- /dev/null +++ b/include/ofmem.h @@ -0,0 +1,38 @@ +/* + * Creation Date: <1999/11/16 00:47:06 samuel> + * Time-stamp: <2003/10/18 13:28:14 samuel> + * + * + * + * + * + * Copyright (C) 1999, 2002 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_OFMEM +#define _H_OFMEM + +extern void ofmem_cleanup( void ); +extern void ofmem_init( void ); + +extern ulong ofmem_claim( ulong addr, ulong size, ulong align ); +extern ulong ofmem_claim_phys( ulong mphys, ulong size, ulong align ); +extern ulong ofmem_claim_virt( ulong mvirt, ulong size, ulong align ); + +extern int ofmem_map( ulong phys, ulong virt, ulong size, int mode ); + +extern void ofmem_release( ulong virt, ulong size ); +extern ulong ofmem_translate( ulong virt, ulong *ret_mode ); + +/* allocations from the private pool */ +extern void *malloc( int size ); +extern void free( void *ptr ); +extern void *realloc( void *ptr, size_t size ); + + +#endif /* _H_OFMEM */ diff --git a/include/openbios/asm.m4 b/include/openbios/asm.m4 new file mode 100644 index 0000000..213589b --- /dev/null +++ b/include/openbios/asm.m4 @@ -0,0 +1,138 @@ +/* -*- asm -*- + * Creation Date: <2001/12/30 20:08:53 samuel> + * Time-stamp: <2002/01/14 00:48:09 samuel> + * + * + * + * m4 initialization (m4 is used as an assembly preprocessor) + * + * Copyright (C) 2001, 2002 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +/* This end-of-quote matches the start-of-quote in mol_config.h */ +]]]]] +changequote([,]) + +dnl m4 macros to avoid in header files (we can not rename these) +dnl ========================================================== +dnl shift, eval, expr, decr, incr, ifelse, popdef, pushdef + + +dnl ************************************************************** +dnl * Rename to reduce namespace conflicts +dnl ************************************************************** + +dnl *** Changing the name of built-in macros using defn does not always work *** + +undefine([changecom]) +undefine([changequote]) +dnl undefine([decr]) +undefine([defn]) +undefine([divert]) +undefine([divnum]) +undefine([errprint]) +dnl undefine([eval]) +dnl undefine([expr]) +undefine([file]) +undefine([format]) +undefine([len]) +undefine([line]) +dnl undefine([ifelse]) +dnl undefine([incr]) +undefine([indir]) +undefine([include]) +undefine([index]) +undefine([maketemp]) +undefine([paste]) +undefine([patsubst]) +dnl undefine([popdef]) +dnl undefine([pushdef]) +undefine([regexp]) +dnl undefine([shift]) +undefine([sinclude]) +undefine([spaste]) +undefine([substr]) +undefine([syscmd]) +undefine([sysval]) +undefine([translit]) +undefine([traceoff]) +undefine([traceon]) +undefine([undivert]) +undefine([unix]) +dnl undefine([__gnu__]) +dnl undefine([__unix__]) + +dnl Uncomment to list m4 definitions +dnl dumpdef m4exit + +/************************************************************************/ +/* M4 Macros */ +/************************************************************************/ + +/* WARNING - M4 BUG IN MacOS X (10.1.2): + * eval() in MacOS X (10.1.2) handles '&' as '&&' and '|' as '||'. + */ + +/* FORLOOP(var, from, to, [body var...]) */ +define([mFORLOOP], [pushdef([$1], [$2])_mFORLOOP([$1], [$2], [$3], [$4])popdef([$1])]) +define([_mFORLOOP], [$4[]ifelse($1, [$3], , + [define([$1], incr($1))_mFORLOOP([$1], [$2], [$3], [$4])])]) + +define([mFIRST],[$1]) +define([mCONCAT_C],[ [$@] ]) + +/* FOREACH(var, [item1, ...], [body var ...]) */ +define([mFOREACH],[pushdef([$1],mFIRST($2))_mFOREACH([$1],[shift($2)],[$3])popdef([$1])]) +define([_mFOREACH],[$3] [ifelse(mFIRST($2),,,[define([$1],mFIRST($2)) _mFOREACH([$1],[shift($2)],[$3])])]) + + +/******************** Nice macro definitions **************************/ + +/* MACRO(name, [param1, ...], [body _param1 ...]) */ +#ifdef __linux__ +define([MACRO], [ + .macro [$1] $2 + mFOREACH([i],[$2],[ pushdef(_[]i,\i) ]) + $3 + .endm + mFOREACH([i],[$2],[ popdef(_[]i) ]) +]) +#else +define([MACRO], [ + .macro [$1] + pushdef([_n],0) + mFOREACH([i],[$2],[ pushdef(_[]i,[$[]]_n) define([_n],incr(_n)) ]) + $3 + .endmacro + mFOREACH([i],[$2],[ popdef(_[]i) ]) + popdef([_n]) +]) +#endif +define([MACRO_0], [MACRO([$1],[_dummy_param_],[$2])]) + + +/* mDEFINE(name, [param1, ...], [body _param1 ...]) */ +define([mDEFINE], [ + pushdef([_n],1) + mFOREACH([i],[$2],[ pushdef(_[]i,[$[]]_n) define([_n],incr(_n)) ]) + define([$1], mCONCAT_C($3) ) + mFOREACH([i],[$2],[ popdef(_[]i) ]) + popdef([_n]) +]) + + +/* rLABEL(label): b label_b ; b label_f */ +define(rLABEL,[dnl +ifdef([$1]_curnum,,[$1[]f:])dnl + define([_tmp_curnum],ifdef($1[]_curnum, [eval($1_curnum+1)], 1)) dnl + define([$1]_curnum,_tmp_curnum)dnl + define([$1]f,$1_[]eval($1_curnum[]+1) )dnl + define([$1]b,$1_[]$1_curnum[] ) +$1[]_[]$1_curnum[]dnl +]) + diff --git a/include/openbios/bindings.h b/include/openbios/bindings.h new file mode 100644 index 0000000..ce729f4 --- /dev/null +++ b/include/openbios/bindings.h @@ -0,0 +1,137 @@ +/* + * Creation Date: <2003/12/19 23:09:56 samuel> + * Time-stamp: <2004/01/07 19:36:42 samuel> + * + * + * + * Forth bindings + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_BINDINGS +#define _H_BINDINGS + +#include "openbios/stack.h" +#include "openbios/kernel.h" + +#define PUSH3(a,b,c) do { PUSH((a)); PUSH((b)); PUSH((c)); } while(0) +#define PUSH2(a,b) do { PUSH((a)); PUSH((b)); } while(0) +#define RET( v ) do { PUSH(v); return; } while(0) + +/* initialization */ +extern int initialize_forth( void ); +extern void exception( cell errcode ); + +/* panic */ +extern int forth_segv_handler( char *segv_addr ); + +/* active package */ +extern phandle_t find_dev( const char *path ); +extern phandle_t get_cur_dev( void ); +extern phandle_t activate_device( const char *str ); +extern void device_end( void ); +extern void activate_dev( phandle_t ph ); + + +/* ihandle related */ +extern phandle_t ih_to_phandle( ihandle_t ih ); +extern ihandle_t my_parent( void ); +extern ihandle_t my_self( void ); +extern char *my_args_copy( void ); + +extern xt_t find_package_method( const char *meth, phandle_t ph ); +extern xt_t find_ih_method( const char *method, ihandle_t ih ); +extern xt_t find_parent_method( const char *method ); +extern void call_package( xt_t xt, ihandle_t ihandle ); +extern void call_parent( xt_t xt ); +extern void call_parent_method( const char *method ); + +/* package */ +extern ihandle_t open_package( const char *argstr, phandle_t ph ); +extern ihandle_t open_dev( const char *spec ); +extern void close_package( ihandle_t ih ); +extern void close_dev( ihandle_t ih ); + +/* property access */ +extern void set_property( phandle_t ph, const char *name, + const char *buf, int len ); +extern void set_int_property( phandle_t ph, const char *name, + int val ); +extern int get_int_property( phandle_t ph, const char *name, + int *retlen ); +extern char *get_property( phandle_t ph, const char *name, + int *retlen ); + +/* device tree iteration */ +extern phandle_t dt_iter_begin( void ); +extern phandle_t dt_iterate( phandle_t last ); +extern phandle_t dt_iterate_type( phandle_t last, const char *type ); +static inline phandle_t dt_find_type( const char *type ) { + return dt_iterate_type( 0, type ); +} + +/* forth bindings */ +extern int feval( const char *str ); +extern void bind_xtfunc( const char *name, xt_t xt, + ucell arg, void (*func)(void) ); +extern void bind_func( const char *name, void (*func)(void) ); +extern xt_t bind_noname_func( void (*func)(void) ); +extern void push_str( const char *str ); +extern char *pop_fstr_copy( void ); + +extern int _fword( const char *word, xt_t *cache_xt ); +extern int _eword( const char *word, xt_t *cache_xt, int nargs ); +extern int _selfword( const char *method, xt_t *cache_xt ); +extern int _parword( const char *method, xt_t *cache_xt ); + +#define fword(w) ({ static xt_t cache_xt = 0; _fword(w, &cache_xt); }) +#define eword(w, nargs) ({ static xt_t cache_xt = 0; _eword(w, &cache_xt, nargs); }) +#define selfword(w) ({ static xt_t cache_xt = 0; _selfword(w, &cache_xt); }) +#define parword(w) ({ static xt_t cache_xt = 0; _parword(w, &cache_xt); }) + +extern void throw( int error ); + + +/* node bindings */ +extern void make_openable( int only_parents ); + + +typedef struct { + const char *name; + void *func; +} method_t; + +#define DECLARE_UNNAMED_NODE( name, flags, size ) \ +static const int name##_flags_ = flags; \ +static const int name##_size_ = size; + +#define DECLARE_NODE( name, flags, size, paths... ) \ +static char *name##_p[] = { paths }; \ +DECLARE_UNNAMED_NODE(name, flags, size) + +#define NODE_METHODS( name ) \ +static method_t name##_m[] + +#define REGISTER_NODE( name ) do { \ + bind_node( name##_flags_, name##_size_, \ + name##_p, sizeof(name##_p)/sizeof(char*), \ + name##_m, sizeof(name##_m)/sizeof(method_t) ); \ + } while(0) + +extern void bind_node( int flags, int size, char **paths, int npaths, + method_t *methods, int nmethods ); + +extern void bind_new_node( int flags, int size, char *name, + method_t *methods, int nmethods ); + +#define INSTALL_OPEN 1 /* install trivial open and close methods */ + + + +#endif /* _H_BINDINGS */ diff --git a/include/openbios/config.h b/include/openbios/config.h new file mode 100644 index 0000000..007990e --- /dev/null +++ b/include/openbios/config.h @@ -0,0 +1,77 @@ +/* + * Creation Date: <2003/12/20 00:07:16 samuel> + * Time-stamp: <2004/01/19 17:40:26 stepan> + * + * + * + * + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_CONFIG +#define _H_CONFIG + +#include "autoconf.h" +#include "mconfig.h" +#include "asm/types.h" + +#define PROGRAM_NAME "OpenBIOS" +#define PROGRAM_VERSION VERSION + +#ifndef BOOTSTRAP + +#ifndef NULL +#define NULL ((void*)0) +#endif + +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; + +typedef unsigned int size_t; +typedef unsigned int usize_t; +typedef signed int ssize_t; +typedef signed int off_t; + +typedef unsigned long long ullong; +typedef long long llong; + +typedef unsigned int time_t; + +#define UINT_MAX ((uint)-1) + +#define ENOMEM 1 +#define EIO 2 +#define EINVAL 3 +#define ENOENT 4 +#define ENOTDIR 5 +#define EISDIR 6 +#define ENAMETOOLONG 7 + +#define SEEK_CUR 1 +#define SEEK_SET 2 +#define SEEK_END 3 + +#endif /* BOOTSTRAP */ + +#include "openbios/sysinclude.h" + +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#endif + +/* errno is a macro on some systems, which might cause nasty problems. + * We try to cope with this here. + */ +#undef errno +#define errno errno_int + +#endif /* _H_CONFIG */ diff --git a/include/openbios/drivers.h b/include/openbios/drivers.h new file mode 100644 index 0000000..a40af0a --- /dev/null +++ b/include/openbios/drivers.h @@ -0,0 +1,20 @@ +/* + * OpenBIOS driver prototypes + * + * (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" + +#ifdef CONFIG_DRIVER_PCI +int ob_pci_init(void); +#endif +#ifdef CONFIG_DRIVER_IDE +int ob_ide_init(void); +#endif + diff --git a/include/openbios/elf.h b/include/openbios/elf.h new file mode 100644 index 0000000..f2cca55 --- /dev/null +++ b/include/openbios/elf.h @@ -0,0 +1,227 @@ +#ifndef ELF_H +#define ELF_H + +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for e_type. */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ + +/* Values for e_machine (architecute). */ +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386+ */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_AT19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_NUM 95 + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ + + +#define ELF_PROGRAM_RETURNS_BIT 0x8000000 /* e_flags bit 31 */ + +#define EI_MAG0 0 +#define ELFMAG0 0x7f + +#define EI_MAG1 1 +#define ELFMAG1 'E' + +#define EI_MAG2 2 +#define ELFMAG2 'L' + +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define ELFMAG "\177ELF" + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_DATA 5 /* Data encodeing byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement little endian */ +#define ELFDATA2MSB 2 /* 2's complement big endian */ + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EV_NONE 0 /* Invalid ELF Version */ +#define EV_CURRENT 1 /* Current version */ + +#define ELF32_PHDR_SIZE (8*4) /* Size of an elf program header */ + +#ifndef __ASSEMBLY__ +#include "asm/types.h" +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Size; + +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Size; + +/* + * ELF header. + */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf64_Half e_type; /* File type. */ + Elf64_Half e_machine; /* Machine architecture. */ + Elf64_Word e_version; /* ELF format version. */ + Elf64_Addr e_entry; /* Entry point. */ + Elf64_Off e_phoff; /* Program header file offset. */ + Elf64_Off e_shoff; /* Section header file offset. */ + Elf64_Word e_flags; /* Architecture-specific flags. */ + Elf64_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf64_Half e_phentsize; /* Size of program header entry. */ + Elf64_Half e_phnum; /* Number of program header entries. */ + Elf64_Half e_shentsize; /* Size of section header entry. */ + Elf64_Half e_shnum; /* Number of section header entries. */ + Elf64_Half e_shstrndx; /* Section name strings section. */ +} Elf64_Ehdr; + +/* + * Program header. + */ +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address (not used). */ + Elf32_Addr p_paddr; /* Physical address. */ + Elf32_Size p_filesz; /* Size of contents in file. */ + Elf32_Size p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Size p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; /* Entry type. */ + Elf64_Word p_flags; /* Access permission flags. */ + Elf64_Off p_offset; /* File offset of contents. */ + Elf64_Addr p_vaddr; /* Virtual address (not used). */ + Elf64_Addr p_paddr; /* Physical address. */ + Elf64_Size p_filesz; /* Size of contents in file. */ + Elf64_Size p_memsz; /* Size of contents in memory. */ + Elf64_Size p_align; /* Alignment in memory and file. */ +} Elf64_Phdr; + +#endif /* __ASSEMBLY__ */ + +#endif /* ELF_H */ diff --git a/include/openbios/elfload.h b/include/openbios/elfload.h new file mode 100644 index 0000000..0d24e1e --- /dev/null +++ b/include/openbios/elfload.h @@ -0,0 +1,29 @@ +/* + * Creation Date: <2001/05/05 16:44:17 samuel> + * Time-stamp: <2003/10/22 23:18:42 samuel> + * + * + * + * Elf loader + * + * Copyright (C) 2001, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_ELFLOAD +#define _H_ELFLOAD + +#include "openbios/elf.h" +#include "asm/elf.h" + +extern int is_elf( int fd, int offs ); +extern int find_elf( int fd ); + +extern Elf32_Phdr * elf_readhdrs( int fd, int offs, Elf32_Ehdr *e ); + + +#endif /* _H_ELFLOAD */ diff --git a/include/openbios/fs.h b/include/openbios/fs.h new file mode 100644 index 0000000..0115110 --- /dev/null +++ b/include/openbios/fs.h @@ -0,0 +1,77 @@ +/* + * Creation Date: <2001/05/06 17:12:45 samuel> + * Time-stamp: <2003/10/22 11:43:45 samuel> + * + * + * + * Generic file system access + * + * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_FS +#define _H_FS + + +typedef struct fs_ops fs_ops_t; +typedef struct opaque_struct file_desc_t; + +#define fs_open_path( fs, path ) (fs)->open_path( fs, path ) +#define fs_search_rom( fs ) (fs)->search_rom( fs ) +#define fs_search_file( fs, name ) (fs)->search_file( fs, name ) +#define fs_vol_name( fs, buf, size ) (fs)->vol_name( fs, buf, size ) + +struct fs_ops { + void *fs_data; + int fd; /* owner block device */ + int type; + + void (*close_fs)( fs_ops_t *fs ); + file_desc_t *(*open_path)( fs_ops_t *fs, const char *path ); + file_desc_t *(*search_rom)( fs_ops_t *fs ); + file_desc_t *(*search_file)( fs_ops_t *fs, const char *name ); + char *(*vol_name)( fs_ops_t *fs, char *buf, int size ); + + /* file ops */ + void (*close)( file_desc_t *file ); + int (*read)( file_desc_t *file, void *buf, size_t count ); + int (*lseek)( file_desc_t *file, off_t offset, int whence ); + char *(*get_path)( file_desc_t *file, char *buf, int len ); + + char *(*get_fstype)( fs_ops_t *fs ); +}; + +extern fs_ops_t *fs_open( int fs_type, int fd ); +extern void fs_close( fs_ops_t *fs ); +const char *fs_get_name( fs_ops_t *fs ); + +#ifdef CONFIG_HFSP +extern int fs_hfsp_open( int fd, fs_ops_t *fs ); +#else +static inline int fs_hfsp_open( int fd, fs_ops_t *fs ) { return -1; } +#endif + +#ifdef CONFIG_HFS +extern int fs_hfs_open( int fd, fs_ops_t *fs ); +#else +static inline int fs_hfs_open( int fd, fs_ops_t *fs ) { return -1; } +#endif + +#ifdef CONFIG_GRUBFS +extern int fs_grubfs_open( int fd, fs_ops_t *fs ); +#else +static inline int fs_grubfs_open( int fd, fs_ops_t *fs ) { return -1; } +#endif + + + +/* misc */ +extern char *get_hfs_vol_name( int fd, char *buf, int size ); + + +#endif /* _H_FS */ diff --git a/include/openbios/kernel.h b/include/openbios/kernel.h new file mode 100644 index 0000000..5da624b --- /dev/null +++ b/include/openbios/kernel.h @@ -0,0 +1,47 @@ +/* + * Creation Date: <2003/12/19 00:20:11 samuel> + * Time-stamp: <2004/01/07 19:19:14 samuel> + * + * + * + * + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * Stefan Reinauer (stepan@openbios.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_KERNEL +#define _H_KERNEL + +#include "openbios/stack.h" +#include "asm/io.h" + +extern volatile int runforth; +extern int enterforth( xt_t xt ); +extern void panic(const char *error) __attribute__ ((noreturn)); + +extern xt_t findword(char *s1); +extern void modules_init( void ); + +/* arch kernel hooks */ +extern void exception(cell no); + +#ifdef FCOMPILER +extern void include_file( const char *str ); +extern void encode_file( const char *str ); +extern int get_inputbyte( void ); +#endif + +#undef putchar +#undef getchar + +extern int putchar( int ch ); +extern int availchar( void ); +extern int getchar( void ); + +#endif /* _H_KERNEL */ diff --git a/include/openbios/nvram.h b/include/openbios/nvram.h new file mode 100644 index 0000000..2166848 --- /dev/null +++ b/include/openbios/nvram.h @@ -0,0 +1,27 @@ +/* + * Creation Date: <2003/12/20 01:04:25 samuel> + * Time-stamp: <2004/01/07 19:59:11 samuel> + * + * + * + * arch NVRAM interface + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_NVRAM +#define _H_NVRAM + +extern int arch_nvram_size( void ); +extern void arch_nvram_get( char *buf ); +extern void arch_nvram_put( char *buf ); + +extern void nvram_init( void ); +extern void update_nvram( void ); + +#endif /* _H_NVRAM */ diff --git a/include/openbios/of.h b/include/openbios/of.h new file mode 100644 index 0000000..8cb6e7b --- /dev/null +++ b/include/openbios/of.h @@ -0,0 +1,22 @@ +/* + * Creation Date: <2004/01/07 19:19:18 samuel> + * Time-stamp: <2004/01/07 19:19:48 samuel> + * + * + * + * OpenFirmware related defines + * + * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_OF +#define _H_OF + +extern int of_client_interface( int *params ); + +#endif /* _H_OF */ diff --git a/include/openbios/stack.h b/include/openbios/stack.h new file mode 100644 index 0000000..c1d786f --- /dev/null +++ b/include/openbios/stack.h @@ -0,0 +1,90 @@ +/* stack.h + * tag: stack and stack access functions + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __STACK_H +#define __STACK_H + +#define dstacksize 512 +extern int dstackcnt; +extern cell dstack[dstacksize]; + +#define rstacksize 512 +extern int rstackcnt; +extern cell rstack[rstacksize]; + +//typedef struct opaque_xt *xt_t; +//typedef struct opaque_ihandle *ihandle_t; +//typedef struct opaque_phandle *phandle_t; + +typedef ucell xt_t; +typedef ucell ihandle_t; +typedef ucell phandle_t; + + + + +static inline void PUSH(ucell value) { + dstack[++dstackcnt] = (value); +} +static inline void PUSH_xt( xt_t xt ) { PUSH( (ucell)xt ); } +static inline void PUSH_ih( ihandle_t ih ) { PUSH( (ucell)ih ); } +static inline void PUSH_ph( phandle_t ph ) { PUSH( (ucell)ph ); } + +static inline ucell POP(void) { + return (ucell) dstack[dstackcnt--]; +} +static inline xt_t POP_xt( void ) { return (xt_t)POP(); } +static inline ihandle_t POP_ih( void ) { return (ihandle_t)POP(); } +static inline phandle_t POP_ph( void ) { return (phandle_t)POP(); } + +static inline void DROP(void) { + dstackcnt--; +} + +static inline void DDROP(void) { + dstackcnt -= 2; +} + +static inline void DPUSH(ducell value) { + dstack[++dstackcnt] = (cell) value; + dstack[++dstackcnt] = (cell) (value >> bitspercell); +} + +static inline ducell DPOP(void) { + ducell du; + du = ((ducell) ((ucell) dstack[dstackcnt--]) << bitspercell); + du |= (ucell) dstack[dstackcnt--]; + return du; +} + +static inline ucell GETTOS(void) { + return dstack[dstackcnt]; +} + +#define GETITEM(number) (dstack[dstackcnt - number]) +static inline void PUSHR(ucell value) { + rstack[++rstackcnt] = (value); +} + +static inline ucell POPR(void) { + return (ucell) rstack[rstackcnt--]; +} +static inline ucell GETTORS(void) { + return rstack[rstackcnt]; +} + + +#if defined(DEBUG_DSTACK) || defined(FCOMPILER) +void printdstack(void); +#endif +#if defined(DEBUG_RSTACK) || defined(FCOMPILER) +void printrstack(void); +#endif + +#endif diff --git a/include/openbios/sysinclude.h b/include/openbios/sysinclude.h new file mode 100644 index 0000000..a8b828b --- /dev/null +++ b/include/openbios/sysinclude.h @@ -0,0 +1,20 @@ +#ifndef __SYSINCLUDE_H +#define __SYSINCLUDE_H + +#ifdef BOOTSTRAP +#include "asm/types.h" +#include +#include +#include +#else /* BOOTSTRAP */ +#include "libc/stdlib.h" +#include "libc/string.h" +#endif /* BOOTSTRAP */ + +extern int printk( const char *fmt, ... ) \ + __attribute__ ((format (printf, 1, 2))); +#ifdef BOOTSTRAP +#define printk printf +#endif + +#endif /* __SYSINCLUDE_H */ diff --git a/include/ppc/asmdefs.h b/include/ppc/asmdefs.h new file mode 100644 index 0000000..92dde4d --- /dev/null +++ b/include/ppc/asmdefs.h @@ -0,0 +1,371 @@ +/* -*- asm -*- + * + * Creation Date: <2001/02/03 19:38:07 samuel> + * Time-stamp: <2003/07/08 18:55:50 samuel> + * + * + * + * Common assembly definitions + * + * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_ASMDEFS +#define _H_ASMDEFS + +#include "openbios/asm.m4" + +#ifndef __ASSEMBLY__ +#error This file is only to be included from assembler code! +#endif + + +/************************************************************************/ +/* High/low halfword compatibility macros */ +/************************************************************************/ + +#ifdef __linux__ +#define ha16( v ) (v)##@ha +#define hi16( v ) (v)##@h +#define lo16( v ) (v)##@l +#endif +#define HA(v) ha16(v) +#define HI(v) hi16(v) +#define LO(v) lo16(v) + + +/************************************************************************/ +/* Register name prefix */ +/************************************************************************/ + +#ifdef __linux__ +define([rPREFIX], []) +define([fPREFIX], []) +define([srPREFIX], []) +#else +define([rPREFIX], [r]) +define([fPREFIX], [f]) +define([srPREFIX], [sr]) +/* frN -> fN */ +mFORLOOP([i],0,31,[define(fr[]i,f[]i)]) +#endif + +/************************************************************************/ +/* Macros and definitions */ +/************************************************************************/ + +#ifdef __darwin__ +#define balign_4 .align 2,0 +#define balign_8 .align 3,0 +#define balign_16 .align 4,0 +#define balign_32 .align 5,0 +#endif + +#ifdef __linux__ +#define balign_4 .balign 4,0 +#define balign_8 .balign 8,0 +#define balign_16 .balign 16,0 +#define balign_32 .balign 32,0 +#endif + +MACRO(LOADVAR, [dreg, variable], [ + lis _dreg,HA(_variable) + lwz _dreg,LO(_variable)(_dreg) +]) + +MACRO(LOADI, [dreg, addr], [ + lis _dreg,HA(_addr) + addi _dreg,_dreg,LO(_addr) +]) + +MACRO(LOAD_GPR_RANGE, [start, endx, offs, base], [ + mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) + lwz rPREFIX[]i,_offs+i[]*4(_base) + .endif +])]) + +MACRO(STORE_GPR_RANGE, [start, endx, offs, base], [ + mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) + stw rPREFIX[]i,_offs+i[]*4(_base) + .endif +])]) + +MACRO(LOAD_FPR_RANGE, [start, endx, offs, base], [ + mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) + lfd fPREFIX[]i,_offs+i[]*8(_base) + .endif +])]) + +MACRO(STORE_FPR_RANGE, [start, endx, offs, base], [ + mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) + stfd fPREFIX[]i,_offs+i[]*8(_base) + .endif +])]) + +/************************************************************************/ +/* FPU load/save macros */ +/************************************************************************/ + + // The FPU macros are used both in the kernel and in + // mainloop_asm.h. + +MACRO(xFPR_LOAD_RANGE, [from, to, mbase], [ + LOAD_FPR_RANGE _from,_to,xFPR_BASE,_mbase +]) +MACRO(xFPR_SAVE_RANGE, [from, to, mbase], [ + STORE_FPR_RANGE _from,_to,xFPR_BASE,_mbase +]) + // The low half of the fpu is fr0-fr12. I.e. the FPU registers + // that might be overwritten when a function call is taken + // (fr13 and fpscr are treated specially). + +MACRO(xLOAD_LOW_FPU, [mbase], [ + xFPR_LOAD_RANGE 0,12,_mbase +]) + +MACRO(xLOAD_TOPHALF_FPU, [mbase], [ + xFPR_LOAD_RANGE 14,31,_mbase +]) +MACRO(xLOAD_FULL_FPU, [mbase], [ + xLOAD_LOW_FPU _mbase + xLOAD_TOPHALF_FPU _mbase +]) + +MACRO(xSAVE_LOW_FPU, [mbase], [ + xFPR_SAVE_RANGE 0,12,_mbase +]) +MACRO(xSAVE_TOPHALF_FPU, [mbase], [ + xFPR_SAVE_RANGE 14,31,_mbase +]) +MACRO(xSAVE_FULL_FPU, [mbase], [ + xSAVE_LOW_FPU _mbase + xSAVE_TOPHALF_FPU _mbase +]) + + +/************************************************************************/ +/* GPR load/save macros */ +/************************************************************************/ + +MACRO(xGPR_SAVE_RANGE, [from, to, mbase], [ + STORE_GPR_RANGE _from, _to, xGPR0, _mbase +]) + +MACRO(xGPR_LOAD_RANGE, [from, to, mbase], [ + LOAD_GPR_RANGE _from, _to, xGPR0, _mbase +]) + + +/************************************************************************/ +/* AltiVec */ +/************************************************************************/ + +#ifdef __linux__ + +define(vPREFIX,[]) + +#ifndef HAVE_ALTIVEC +#define VEC_OPCODE( op1,op2,A,B,C ) \ + .long (((op1) << (32-6)) | (op2) | ((A) << (32-11)) | ((B) << (32-16)) | ((C) << (32-21))) ; + +#define __stvx( vS,rA,rB ) VEC_OPCODE( 31,0x1ce,vS,rA,rB ) +#define __lvx( vD,rA,rB ) VEC_OPCODE( 31,0xce, vD,rA,rB ) +#define __mfvscr( vD ) VEC_OPCODE( 4,1540,vD,0,0 ) +#define __mtvscr( vB ) VEC_OPCODE( 4,1604,0,0,vB ) +#define __stvewx( vS,rA,rB ) VEC_OPCODE( 31,(199<<1), vS,rA,rB ) + +mFORLOOP([i],0,31,[define(v[]i,[]i)]) +MACRO(stvx, [vS,rA,rB], [ __stvx( _vS,_rA,_rB ) ; ]) +MACRO(lvx, [vD,rA,rB], [ __lvx( _vD,_rA,_rB ) ; ]) +MACRO(mfvscr, [vD], [ __mfvscr( _vD ) ; ]) +MACRO(mtvscr, [vB], [ __mtvscr( _vB ) ; ]) +MACRO(stvewx, [vS,rA,rB], [ __stvewx( _vS,_rA,_rB ) ; ]) +#endif +#else /* __linux__ */ + +define(vPREFIX,[v]) + +#endif /* __linux__ */ + + +// NOTE: Writing to VSCR won't cause exceptions (this +// is different compared to FPSCR). + +MACRO(xVEC_SAVE, [mbase, scr], [ + addi _scr,_mbase,xVEC_BASE + mFORLOOP([i],0,31,[ + stvx vPREFIX[]i,0,_scr + addi _scr,_scr,16 + ]) + addi _scr,_mbase,xVSCR-12 + mfvscr v0 + stvx v0,0,_scr + addi _scr,_mbase,xVEC0 + lvx v0,0,_scr + mfspr _scr,S_VRSAVE + stw _scr,xVRSAVE(_mbase) +]) + +MACRO(xVEC_LOAD, [mbase, scr], [ + addi _scr,_mbase,xVSCR-12 + lvx v0,0,_scr + mtvscr v0 + addi _scr,_mbase,xVEC_BASE + mFORLOOP([i],0,31,[ + lvx vPREFIX[]i,0,_scr + addi _scr,_scr,16 + ]) + lwz _scr,xVRSAVE(_mbase) + mtspr S_VRSAVE,_scr +]) + +/************************************************************************/ +/* Instructions */ +/************************************************************************/ + +#ifdef __darwin__ +MACRO(mtsprg0, [reg], [mtspr SPRG0,_reg] ) +MACRO(mtsprg1, [reg], [mtspr SPRG1,_reg] ) +MACRO(mtsprg2, [reg], [mtspr SPRG2,_reg] ) +MACRO(mtsprg3, [reg], [mtspr SPRG3,_reg] ) +MACRO(mfsprg0, [reg], [mfspr _reg,SPRG0] ) +MACRO(mfsprg1, [reg], [mfspr _reg,SPRG1] ) +MACRO(mfsprg2, [reg], [mfspr _reg,SPRG2] ) +MACRO(mfsprg3, [reg], [mfspr _reg,SPRG3] ) +#endif + +/************************************************************************/ +/* Register names */ +/************************************************************************/ + +#ifdef __darwin__ +/* These symbols are not defined under Darwin */ +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 +#define cr8 8 +#define lt 0 /* Less than */ +#define gt 1 /* Greater than */ +#define eq 2 /* Equal */ +#define so 3 /* Summary Overflow */ +#define un 3 /* Unordered (after floating point) */ +#endif + +/* FPU register names (to be used as macro arguments) */ +#define FR0 0 +#define FR1 1 +#define FR2 2 +#define FR3 3 +#define FR4 4 +#define FR5 5 +#define FR6 6 +#define FR7 7 +#define FR8 8 +#define FR9 9 +#define FR10 10 +#define FR11 11 +#define FR12 12 +#define FR13 13 +#define FR14 14 +#define FR15 15 +#define FR16 16 +#define FR17 17 +#define FR18 18 +#define FR19 19 +#define FR20 20 +#define FR21 21 +#define FR22 22 +#define FR23 23 +#define FR24 24 +#define FR25 25 +#define FR26 26 +#define FR27 27 +#define FR28 28 +#define FR29 29 +#define FR30 30 +#define FR31 31 + +/* GPR register names (to be used as macro arguments) */ +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 +#define R16 16 +#define R17 17 +#define R18 18 +#define R19 19 +#define R20 20 +#define R21 21 +#define R22 22 +#define R23 23 +#define R24 24 +#define R25 25 +#define R26 26 +#define R27 27 +#define R28 28 +#define R29 29 +#define R30 30 +#define R31 31 + +#ifndef __darwin__ + +/* GPR register names, rN -> N, frN -> N, vN -> N */ +mFORLOOP([i],0,31,[define(r[]i,[]i)]) +mFORLOOP([i],0,31,[define(fr[]i,[]i)]) +mFORLOOP([i],0,31,[define(v[]i,[]i)]) + +#endif /* __darwin__ */ + + +/************************************************************************/ +/* useful macros */ +/************************************************************************/ + +MACRO(ori_, [reg1, reg2, value], [ + .if (_value & 0xffff) + ori _reg1, _reg2, (_value) & 0xffff + .endif + .if (_value & ~0xffff) + oris _reg1, _reg2, (_value) >> 16 + .endif +]) + +/************************************************************************/ +/* MISC */ +/************************************************************************/ + +#ifdef __linux__ +#define GLOBL( name ) .globl name ; name +#define EXTERN( name ) name +#else +/* an underscore is needed on Darwin */ +#define GLOBL( name ) .globl _##name ; name: ; _##name +#define EXTERN( name ) _##name +#endif + +#define BIT(n) (1<<(31-(n))) + +#endif /* _H_ASMDEFS */ + diff --git a/include/ppc/elf.h b/include/ppc/elf.h new file mode 100644 index 0000000..fd2a3f9 --- /dev/null +++ b/include/ppc/elf.h @@ -0,0 +1,5 @@ +#define ARCH_ELF_CLASS ELFCLASS32 +#define ARCH_ELF_DATA ELFDATA2MSB +#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_PPC) +typedef Elf32_Ehdr Elf_ehdr; +typedef Elf32_Phdr Elf_phdr; diff --git a/include/ppc/io.h b/include/ppc/io.h new file mode 100644 index 0000000..adf65b5 --- /dev/null +++ b/include/ppc/io.h @@ -0,0 +1,165 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +#include "asm/types.h" + +extern unsigned long virt_offset; + +#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset)) +#define virt_to_phys(virt) ((unsigned long) (virt) + virt_offset) + +#ifndef BOOTSTRAP + +#ifndef _IO_BASE +#define _IO_BASE 0x80000000 +#endif + +/* + * The insw/outsw/insl/outsl macros don't do byte-swapping. + * They are only used in practice for transferring buffers which + * are arrays of bytes, and byte-swapping is not appropriate in + * that case. - paulus + */ +#define insw(port, buf, ns) _insw_ns((uint16_t *)((port)+_IO_BASE), (buf), (ns)) +#define outsw(port, buf, ns) _outsw_ns((uint16_t *)((port)+_IO_BASE), (buf), (ns)) + +#define inb(port) in_8((uint8_t *)((port)+_IO_BASE)) +#define outb(val, port) out_8((uint8_t *)((port)+_IO_BASE), (val)) +#define inw(port) in_le16((uint16_t *)((port)+_IO_BASE)) +#define outw(val, port) out_le16((uint16_t *)((port)+_IO_BASE), (val)) +#define inl(port) in_le32((uint32_t *)((port)+_IO_BASE)) +#define outl(val, port) out_le32((uint32_t *)((port)+_IO_BASE), (val)) + +/* + * 8, 16 and 32 bit, big and little endian I/O operations, with barrier. + */ +static inline int in_8(volatile unsigned char *addr) +{ + int ret; + + __asm__ __volatile__("lbz%U1%X1 %0,%1; eieio":"=r"(ret):"m"(*addr)); + return ret; +} + +static inline void out_8(volatile unsigned char *addr, int val) +{ + __asm__ __volatile__("stb%U0%X0 %1,%0; eieio":"=m"(*addr):"r"(val)); +} + +static inline int in_le16(volatile unsigned short *addr) +{ + int ret; + + __asm__ __volatile__("lhbrx %0,0,%1; eieio":"=r"(ret): + "r"(addr), "m"(*addr)); + return ret; +} + +static inline int in_be16(volatile unsigned short *addr) +{ + int ret; + + __asm__ __volatile__("lhz%U1%X1 %0,%1; eieio":"=r"(ret):"m"(*addr)); + return ret; +} + +static inline void out_le16(volatile unsigned short *addr, int val) +{ + __asm__ __volatile__("sthbrx %1,0,%2; eieio":"=m"(*addr):"r"(val), + "r"(addr)); +} + +static inline void out_be16(volatile unsigned short *addr, int val) +{ + __asm__ __volatile__("sth%U0%X0 %1,%0; eieio":"=m"(*addr):"r"(val)); +} + +static inline unsigned in_le32(volatile unsigned *addr) +{ + unsigned ret; + + __asm__ __volatile__("lwbrx %0,0,%1; eieio":"=r"(ret): + "r"(addr), "m"(*addr)); + return ret; +} + +static inline unsigned in_be32(volatile unsigned *addr) +{ + unsigned ret; + + __asm__ __volatile__("lwz%U1%X1 %0,%1; eieio":"=r"(ret):"m"(*addr)); + return ret; +} + +static inline void out_le32(volatile unsigned *addr, int val) +{ + __asm__ __volatile__("stwbrx %1,0,%2; eieio":"=m"(*addr):"r"(val), + "r"(addr)); +} + +static inline void out_be32(volatile unsigned *addr, int val) +{ + __asm__ __volatile__("stw%U0%X0 %1,%0; eieio":"=m"(*addr):"r"(val)); +} + +static inline void _insw_ns(volatile uint16_t * port, void *buf, int ns) +{ + uint16_t *b = (uint16_t *) buf; + + while (ns > 0) { + *b++ = in_le16(port); + ns--; + } +} + +static inline void _outsw_ns(volatile uint16_t * port, const void *buf, + int ns) +{ + uint16_t *b = (uint16_t *) buf; + + while (ns > 0) { + out_le16(port, *b++); + ns--; + } +} + +static inline void _insw(volatile uint16_t * port, void *buf, int ns) +{ + uint16_t *b = (uint16_t *) buf; + + while (ns > 0) { + *b++ = in_be16(port); + ns--; + } +} + +static inline void _outsw(volatile uint16_t * port, const void *buf, + int ns) +{ + uint16_t *b = (uint16_t *) buf; + + while (ns > 0) { + out_be16(port, *b++); + ns--; + } +} +#else /* BOOTSTRAP */ +#ifdef FCOMPILER +#define inb(reg) ((u8)0xff) +#define inw(reg) ((u16)0xffff) +#define inl(reg) ((u32)0xffffffff) +#define outb(reg, val) // nothing +#define outw(reg, val) // nothing +#define outl(reg, val) // nothing +#else +extern u8 inb(u32 reg); +extern u16 inw(u32 reg); +extern u32 inl(u32 reg); +extern void insw(u32 reg, void *addr, unsigned long count); +extern void outb(u32 reg, u8 val); +extern void outw(u32 reg, u16 val); +extern void outl(u32 reg, u32 val); +extern void outsw(u32 reg, const void *addr, unsigned long count); +#endif +#endif +#endif /* _ASM_IO_H */ diff --git a/include/ppc/pci.h b/include/ppc/pci.h new file mode 100644 index 0000000..677a5c8 --- /dev/null +++ b/include/ppc/pci.h @@ -0,0 +1,84 @@ +#ifndef PPC_PCI_H +#define PPC_PCI_H + +#include "asm/io.h" + +/* Sandpoint example */ +#define ISA_IO_BASE 0x80000000 +#define ISA_MEM_BASE 0xc0000000 +#define PCIC0_CFGADDR 0xfec00cf8 +#define PCIC0_CFGDATA 0xfee00cfc +#ifndef _IO_BASE +#define _IO_BASE ISA_IO_BASE +#endif + +#if !(PCI_CONFIG_1 || PCI_CONFIG_2) +#define PCI_CONFIG_1 1 /* default */ +#endif + +#ifdef PCI_CONFIG_1 + +/* PCI Configuration Mechanism #1 */ + +/* Have pci_addr in the same format as the values written to PCIC0_CFGADDR + * so register accesses can be made easy. */ +#define PCI_ADDR(bus, dev, fn) \ + ((pci_addr) (0x80000000u \ + | (uint32_t) (bus) << 16 \ + | (uint32_t) (dev) << 11 \ + | (uint32_t) (fn) << 8)) + +#define PCI_BUS(pcidev) ((uint8_t) ((pcidev) >> 16)) +#define PCI_DEV(pcidev) ((uint8_t) ((pcidev) >> 11) & 0x1f) +#define PCI_FN(pcidev) ((uint8_t) ((pcidev) >> 8) & 7) + +static inline uint8_t pci_config_read8(pci_addr dev, uint8_t reg) +{ + uint8_t res; + + out_le32((unsigned *)PCIC0_CFGADDR, (dev | (reg & ~3))); + res = in_8((unsigned char *)PCIC0_CFGDATA + (reg & 3)); + return res; +} + +static inline uint16_t pci_config_read16(pci_addr dev, uint8_t reg) +{ + uint16_t res; + + out_le32((unsigned *)PCIC0_CFGADDR, (dev | (reg & ~3))); + res = in_le16((unsigned char *)PCIC0_CFGDATA + (reg & 2)); + return res; +} + +static inline uint32_t pci_config_read32(pci_addr dev, uint8_t reg) +{ + uint32_t res; + + out_le32((unsigned *)PCIC0_CFGADDR, (dev | (reg & ~3))); + res = in_le32((unsigned char *)PCIC0_CFGDATA); + return res; +} + +static inline void pci_config_write8(pci_addr dev, uint8_t reg, uint8_t val) +{ + outl(dev | (reg & ~3), 0xcf8); + outb(val, 0xcfc | (reg & 3)); +} + +static inline void pci_config_write16(pci_addr dev, uint8_t reg, uint16_t val) +{ + outl(dev | (reg & ~3), 0xcf8); + outw(val, 0xcfc | (reg & 2)); +} + +static inline void pci_config_write32(pci_addr dev, uint8_t reg, uint32_t val) +{ + outl(dev | reg, 0xcf8); + outl(val, 0xcfc); +} + +#else /* !PCI_CONFIG_1 */ +#error PCI Configuration Mechanism is not specified or implemented +#endif + +#endif /* PPC_PCI_H */ diff --git a/include/ppc/processor.h b/include/ppc/processor.h new file mode 100644 index 0000000..fff1bc5 --- /dev/null +++ b/include/ppc/processor.h @@ -0,0 +1,404 @@ +/* + * Creation Date: <2000/10/29 01:43:29 samuel> + * Time-stamp: <2003/07/27 22:37:49 samuel> + * + * + * + * Extract from + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_PROCESSOR +#define _H_PROCESSOR + + +#define PTE0_VSID(s) (((s)>>7) & 0xffffff) +#define PTE0_V BIT(0) +#define PTE0_H BIT(25) +#define PTE0_API 0x3f + +#define PTE1_R BIT(23) +#define PTE1_C BIT(24) +#define PTE1_W BIT(25) +#define PTE1_I BIT(26) +#define PTE1_M BIT(27) +#define PTE1_G BIT(28) +#define PTE1_WIMG (PTE1_W | PTE1_I | PTE1_M | PTE1_G) +#define PTE1_PP 0x3 +#define PTE1_RPN (~0xfffUL) + +#define VSID_Ks BIT(1) +#define VSID_Kp BIT(2) +#define VSID_N BIT(3) + + + +#ifndef MSR_VEC + +#define MSR_VEC (1<<25) /* 6: Enable AltiVec */ +#define MSR_POW (1<<18) /* 13: Enable Power Management */ +#define MSR_TGPR (1<<17) /* 14: TLB Update registers in use */ +#define MSR_ILE (1<<16) /* 15: Interrupt Little Endian */ +#define MSR_EE (1<<15) /* 16: External Interrupt Enable */ +#define MSR_PR (1<<14) /* 17: Privilege Level */ +#define MSR_FP (1<<13) /* 18: Floating Point enable */ +#define MSR_ME (1<<12) /* 19: Machine Check Enable */ +#define MSR_FE0 (1<<11) /* 20: Floating Exception mode 0 */ +#define MSR_SE (1<<10) /* 21: Single Step */ +#define MSR_BE (1<<9) /* 22: Branch Trace */ +#define MSR_FE1 (1<<8) /* 23: Floating Exception mode 1 */ +#define MSR_IP (1<<6) /* 25: Exception prefix 0x000/0xFFF */ +#define MSR_IR (1<<5) /* 26: Instruction Relocate */ +#define MSR_DR (1<<4) /* 27: Data Relocate */ +#define MSR_PE (1<<2) /* 29: Performance Monitor Flag */ +#define MSR_RI (1<<1) /* 30: Recoverable Exception */ +#define MSR_LE (1<<0) /* 31: Little Endian */ + +#endif /* MSR_VEC */ + +#ifndef S_SPRG0 + +#define NUM_SPRS 1024 +//#define S_XER 1 +#define S_RTCU_R 4 /* 601 RTC Upper/Lower (Reading) */ +#define S_RTCL_R 5 +//#define S_LR 8 +//#define S_CTR 9 +#define S_DSISR 18 /* Source Instruction Service Register */ +#define S_DAR 19 /* Data Address Register */ +#define S_RTCU_W 20 /* 601 RTC Upper/Lower (Writing) */ +#define S_RTCL_W 21 +#define S_DEC 22 /* Decrementer Register */ +#define S_SDR1 25 /* Table Search Description Register */ +#define S_SRR0 26 /* Save and Restore Register 0 */ +#define S_SRR1 27 /* Save and Restore Register 1 */ +#define S_VRSAVE 256 /* (AltiVec) Vector Register Save Register */ +#define S_TBRL 268 /* Time base Upper/Lower (Reading) */ +#define S_TBRU 269 +#define S_SPRG0 272 /* SPR General 0-3 */ +#define S_SPRG1 273 +#define S_SPRG2 274 +#define S_SPRG3 275 +#define S_SPRG4 276 /* SPR General 4-7 (7445/7455) */ +#define S_SPRG5 277 +#define S_SPRG6 278 +#define S_SPRG7 279 +#define S_EAR 282 /* External Access Register */ +#define S_TBWL 284 /* Time base Upper/Lower (Writing) */ +#define S_TBWU 285 +#define S_PVR 287 /* Processor Version Register */ +#define S_IBAT0U 528 +#define S_IBAT0L 529 +#define S_IBAT1U 530 +#define S_IBAT1L 531 +#define S_IBAT2U 532 +#define S_IBAT2L 533 +#define S_IBAT3U 534 +#define S_IBAT3L 535 +#define S_DBAT0U 536 +#define S_DBAT0L 537 +#define S_DBAT1U 538 +#define S_DBAT1L 539 +#define S_DBAT2U 540 +#define S_DBAT2L 541 +#define S_DBAT3U 542 +#define S_DBAT3L 543 +#define S_UMMCR2 928 +#define S_UPMC5 929 /* User Performance Monitor Counter Register */ +#define S_UPMC6 930 +#define S_UBAMR 935 +#define S_UMMCR0 936 /* User Monitor Mode Control Register */ +#define S_UPMC1 937 +#define S_UPMC2 938 +#define S_USIAR 939 /* User Sampled Instruction Address Register */ +#define S_UMMCR1 940 +#define S_UPMC3 941 +#define S_UPMC4 942 /* User Performance Monitor Counter Register 4 */ +#define S_USDAR 943 /* User Sampled Data Address Register */ +#define S_MMCR2 944 /* Monitor Mode Control Register */ +#define S_PMC5 945 +#define S_PMC6 946 +#define S_BAMR 951 /* Breakpoint Address Mask Register (74xx) */ +#define S_MMCR0 952 /* Monitor Mode Control Register 0 */ +#define S_PMC1 953 /* Performance Counter Register */ +#define S_PMC2 954 +#define S_SIAR 955 /* Sampled Instruction Address Register */ +#define S_MMCR1 956 +#define S_PMC3 957 +#define S_PMC4 958 +#define S_SDAR 959 /* Sampled Data Address Register */ +#define S_DMISS 976 /* 603 */ +#define S_DCMP 977 /* 603 */ +#define S_HASH1 978 /* 603 */ +#define S_HASH2 979 /* 603 */ +#define S_IMISS 980 /* 603 */ +#define S_TLBMISS 980 /* 7445/7455 */ +#define S_ICMP 981 /* 603 */ +#define S_PTEHI 981 /* 7445/7455 */ +#define S_RPA 982 /* 603 */ +#define S_PTELO 982 /* 7445/7455 */ +#define S_L3PM 983 /* L3 Private Memory Address Control Register */ +#define S_L3ITCR0 984 /* ??? */ +#define S_L3OHCR 1000 /* ??? */ +#define S_L3ITCR1 1001 /* ??? */ +#define S_L3ITCR2 1002 /* ??? */ +#define S_L3ITCR3 1003 /* ??? */ +#define S_HID0 1008 /* Hardware Implementation Registers */ +#define S_HID1 1009 +#define S_HID2 1010 +#define S_IABR S_HID2 /* HID2 - Instruction Address Breakpoint Register */ +#define S_ICTRL 1011 /* HID3 - Instruction Cache & Interrupt control reg */ +#define S_HID4 1012 /* HID4 - Instruction Address Compare 1 (?) */ +#define S_HID5 1013 +#define S_DABR S_HID5 /* HID5 - Data Address Breakpoint */ +#define S_MSSCR0 1014 /* HID6 - Memory Subsystem Control Register 0 */ +#define S_MSSCR1 1015 /* HID7 - Memory Subsystem Control Register 1 */ +#define S_LDSTCR 1016 /* HID8 - Load/Store Control Register */ +#define S_L2CR 1017 /* HID9 - Level 2 Cache Control Regsiter */ +#define S_L3CR 1018 /* HID10 - Level 3 Cache Control Regsiter (7450) */ +#define S_HID11 1019 +#define S_ICTC S_HID11 /* HID11 - Instruction Cache Throttling Control Reg */ +#define S_ICCR S_HID11 /* Instruction Cache Cacheability Reigster */ +#define S_THRM1 1020 /* HID12 - Thermal Management Register 1 */ +#define S_THRM2 1021 /* HID13 - Thermal Management Register 2 */ +#define S_THRM3 1022 /* HID14 - Thermal Management Register 3 */ +#define S_HID15 1023 +#define S_PIR S_HID15 /* HID15 - Processor Identification Register */ + +#endif /* S_SPRG0 */ + +/* the kernel might define these too... */ +#if !defined(__KERNEL__) || defined(__ASSEMBLY__) + +/* Floating Point Status and Control Register (FPSCR) Fields */ +#define FPSCR_FX 0x80000000 /* FPU exception summary */ +#define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ +#define FPSCR_VX 0x20000000 /* Invalid operation summary */ +#define FPSCR_OX 0x10000000 /* Overflow exception summary */ +#define FPSCR_UX 0x08000000 /* Underflow exception summary */ +#define FPSCR_ZX 0x04000000 /* Zero-devide exception summary */ +#define FPSCR_XX 0x02000000 /* Inexact exception summary */ +#define FPSCR_VXSNAN 0x01000000 /* Invalid op for SNaN */ +#define FPSCR_VXISI 0x00800000 /* Invalid op for Inv - Inv */ +#define FPSCR_VXIDI 0x00400000 /* Invalid op for Inv / Inv */ +#define FPSCR_VXZDZ 0x00200000 /* Invalid op for Zero / Zero */ +#define FPSCR_VXIMZ 0x00100000 /* Invalid op for Inv * Zero */ +#define FPSCR_VXVC 0x00080000 /* Invalid op for Compare */ +#define FPSCR_FR 0x00040000 /* Fraction rounded */ +#define FPSCR_FI 0x00020000 /* Fraction inexact */ +#define FPSCR_FPRF 0x0001f000 /* FPU Result Flags */ +#define FPSCR_FPCC 0x0000f000 /* FPU Condition Codes */ +#define FPSCR_VXSOFT 0x00000400 /* Invalid op for software request */ +#define FPSCR_VXSQRT 0x00000200 /* Invalid op for square root */ +#define FPSCR_VXCVI 0x00000100 /* Invalid op for integer convert */ +#define FPSCR_VE 0x00000080 /* Invalid op exception enable */ +#define FPSCR_OE 0x00000040 /* IEEE overflow exception enable */ +#define FPSCR_UE 0x00000020 /* IEEE underflow exception enable */ +#define FPSCR_ZE 0x00000010 /* IEEE zero divide exception enable */ +#define FPSCR_XE 0x00000008 /* FP inexact exception enable */ +#define FPSCR_NI 0x00000004 /* FPU non IEEE-Mode */ +#define FPSCR_RN 0x00000003 /* FPU rounding control */ + +/* SPR_HID0 */ +#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ +#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ +#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ +#define HID0_SBCLK (1<<27) +#define HID0_EICE (1<<26) +#define HID0_ECLK (1<<25) +#define HID0_PAR (1<<24) +#define HID0_DOZE (1<<23) +#define HID0_NAP (1<<22) +#define HID0_SLEEP (1<<21) +#define HID0_DPM (1<<20) +#define HID0_NHR (1<<16) /* Not Hard Reset */ +#define HID0_ICE (1<<15) /* Instruction Cache Enable */ +#define HID0_DCE (1<<14) /* Data Cache Enable */ +#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ +#define HID0_DLOCK (1<<12) /* Data Cache Lock */ +#define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */ +#define HID0_DCFI (1<<10) /* Data Cache Flash Invalidate */ +#define HID0_SPD (1<<9) /* Speculative disable */ +#define HID0_SGE (1<<7) /* Store Gathering Enable */ +#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */ +#define HID0_BTIC (1<<5) /* Branch Target Instruction Cache Enable */ +#define HID0_ABE (1<<3) /* Address Broadcast Enable */ +#define HID0_BHT (1<<2) /* Branch History Table Enable */ +#define HID0_BTCD (1<<1) /* Branch target cache disable */ + +#define L2CR_L2E BIT(0) /* L2 enable */ +#define L2CR_L2PE BIT(1) /* L2 data parity generation and checking */ +#define L2CR_L2SIZ_512K BIT(2) +#define L2CR_L2SIZ_256K BIT(3) +#define L2CR_L2SIZ_1MB (BIT(2)|BIT(3)) +#define L2CR_L2CLK_1 BIT(6) /* L2 clock ration */ +#define L2CR_L2CLK_15 (BIT(6)*2) +#define L2CR_L2CLK_2 (BIT(6)*4) +#define L2CR_L2CLK_25 (BIT(6)*5) +#define L2CR_L2CLK_3 (BIT(6)*6) +#define L2CR_L2RAM_FT 0 /* flow-through (reg-buf) synchronous SRAM */ +#define L2CR_L2RAM_PB BIT(7) /* Piplined (reg-reg) synchronous burst SRAM */ +#define L2CR_L2RAM_PLW (BIT(7)|BIT(8)) /* Piplined (reg-reg) synchronous late-write */ +#define L2CR_L2DO BIT(9) /* L2 data-only */ +#define L2CR_L2I BIT(10) /* L2 global invalidate */ +#define L2CR_L2CTL BIT(11) /* L2 RAM control (ZZ enable, low-power mode) */ +#define L2CR_L2WT BIT(12) /* L2 write-through */ +#define L2CR_L2TS BIT(13) /* L2 test support */ +#define L2CR_L2OH_05 0 /* L2 output hold 0.5 nS */ +#define L2CR_L2OH_10 BIT(15) /* L2 output hold 1.0 nS */ +#define L2CR_L2SL BIT(16) /* L2 DLL slow (use if bus freq < 150 MHz) */ +#define L2CR_L2DF BIT(17) /* L2 differential clock */ +#define L2CR_L2BYP BIT(18) /* L2 DLL bypass */ +#define L2CR_L2IP BIT(31) /* L2 global invalidate in progress */ + +/* SPR_THRM1 */ +#define THRM1_TIN (1 << 31) +#define THRM1_TIV (1 << 30) +#define THRM1_THRES(x) ((x&0x7f)<<23) +#define THRM3_SITV(x) ((x&0x3fff)<<1) +#define THRM1_TID (1<<2) +#define THRM1_TIE (1<<1) +#define THRM1_V (1<<0) + +/* SPR_THRM3 */ +#define THRM3_E (1<<0) + +/* Processor Version Numbers */ + +#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ +#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ + +#define PVR_403GA 0x00200000 +#define PVR_403GB 0x00200100 +#define PVR_403GC 0x00200200 +#define PVR_403GCX 0x00201400 +#define PVR_405GP 0x40110000 +#define PVR_601 0x00010000 +#define PVR_602 0x00050000 +#define PVR_603 0x00030000 +#define PVR_603e 0x00060000 +#define PVR_603ev 0x00070000 +#define PVR_603r 0x00071000 +#define PVR_604 0x00040000 +#define PVR_604e 0x00090000 +#define PVR_604r 0x000A0000 +#define PVR_620 0x00140000 +#define PVR_740 0x00080000 +#define PVR_750 PVR_740 +#define PVR_740P 0x10080000 +#define PVR_750P PVR_740P +#define PVR_821 0x00500000 +#define PVR_823 PVR_821 +#define PVR_850 PVR_821 +#define PVR_860 PVR_821 +#define PVR_7400 0x000C0000 +#define PVR_8240 0x00810100 +#define PVR_8260 PVR_8240 + +/* Vector VSCR register */ +#define VSCR_NJ 0x10000 +#define VSCR_SAT 0x1 + +#endif /* __KERNEL__ */ + + +#ifdef __ASSEMBLY__ + +#define CTR S_CTR /* Counter Register */ +#define DAR S_DAR /* Data Address Register */ +#define DABR S_DABR /* Data Address Breakpoint Register */ +#define DBAT0L S_DBAT0L /* Data BAT 0 Lower Register */ +#define DBAT0U S_DBAT0U /* Data BAT 0 Upper Register */ +#define DBAT1L S_DBAT1L /* Data BAT 1 Lower Register */ +#define DBAT1U S_DBAT1U /* Data BAT 1 Upper Register */ +#define DBAT2L S_DBAT2L /* Data BAT 2 Lower Register */ +#define DBAT2U S_DBAT2U /* Data BAT 2 Upper Register */ +#define DBAT3L S_DBAT3L /* Data BAT 3 Lower Register */ +#define DBAT3U S_DBAT3U /* Data BAT 3 Upper Register */ +#define DCMP S_DCMP /* Data TLB Compare Register */ +#define DEC S_DEC /* Decrement Register */ +#define DMISS S_DMISS /* Data TLB Miss Register */ +#define DSISR S_DSISR /* Data Storage Interrupt Status Register */ +#define EAR S_EAR /* External Address Register */ +#define HASH1 S_HASH1 /* Primary Hash Address Register */ +#define HASH2 S_HASH2 /* Secondary Hash Address Register */ +#define HID0 S_HID0 /* Hardware Implementation Register 0 */ +#define HID1 S_HID1 /* Hardware Implementation Register 1 */ +#define IABR S_IABR /* Instruction Address Breakpoint Register */ +#define IBAT0L S_IBAT0L /* Instruction BAT 0 Lower Register */ +#define IBAT0U S_IBAT0U /* Instruction BAT 0 Upper Register */ +#define IBAT1L S_IBAT1L /* Instruction BAT 1 Lower Register */ +#define IBAT1U S_IBAT1U /* Instruction BAT 1 Upper Register */ +#define IBAT2L S_IBAT2L /* Instruction BAT 2 Lower Register */ +#define IBAT2U S_IBAT2U /* Instruction BAT 2 Upper Register */ +#define IBAT3L S_IBAT3L /* Instruction BAT 3 Lower Register */ +#define IBAT3U S_IBAT3U /* Instruction BAT 3 Upper Register */ +#define ICMP S_ICMP /* Instruction TLB Compare Register */ +#define IMISS S_IMISS /* Instruction TLB Miss Register */ +#define IMMR S_IMMR /* PPC 860/821 Internal Memory Map Register */ +#define L2CR S_L2CR /* PPC 750 L2 control register */ +#define PVR S_PVR /* Processor Version */ +#define RPA S_RPA /* Required Physical Address Register */ +#define SDR1 S_SDR1 /* MMU hash base register */ +#define SPR0 S_SPRG0 /* Supervisor Private Registers */ +#define SPR1 S_SPRG1 +#define SPR2 S_SPRG2 +#define SPR3 S_SPRG3 +#define SPRG0 S_SPRG0 +#define SPRG1 S_SPRG1 +#define SPRG2 S_SPRG2 +#define SPRG3 S_SPRG3 +#define SRR0 S_SRR0 /* Save and Restore Register 0 */ +#define SRR1 S_SRR1 /* Save and Restore Register 1 */ +#define TBRL S_STBRL /* Time Base Read Lower Register */ +#define TBRU S_TBRU /* Time Base Read Upper Register */ +#define TBWL S_TBWL /* Time Base Write Lower Register */ +#define TBWU S_TBWU /* Time Base Write Upper Register */ +#define ICTC S_ICTC +#define THRM1 S_THRM1 /* Thermal Management Register 1 */ +#define THRM2 S_THRM2 /* Thermal Management Register 2 */ +#define THRM3 S_THRM3 /* Thermal Management Register 3 */ +#define SIAR S_SIAR +#define SDAR S_SDAR +#define XER 1 + +#define SR0 0 /* Segment registers */ +#define SR1 1 +#define SR2 2 +#define SR3 3 +#define SR4 4 +#define SR5 5 +#define SR6 6 +#define SR7 7 +#define SR8 8 +#define SR9 9 +#define SR10 10 +#define SR11 11 +#define SR12 12 +#define SR13 13 +#define SR14 14 +#define SR15 15 + +#endif /* __ASSEMBLY__ */ + +/* opcode macros */ + +#define OPCODE_PRIM(n) ( ((ulong)(n)) >> 26 ) +#define OPCODE_EXT(n) ( (((ulong)(n)) >> 1) & 0x3ff ) +#define OPCODE(op,op_ext) ( ((op)<<10) + op_ext ) + +#define B1(n) ( (((ulong)(n)) >> 21) & 0x1f ) +#define B2(n) ( (((ulong)(n)) >> 16) & 0x1f ) +#define B3(n) ( (((ulong)(n)) >> 11) & 0x1f ) + +#define BD(n) ((ulong)((n) & 0x7fff) + (((n) & 0x8000) ? (ulong)0xffff8000 : 0)) + +#define SPRNUM_FLIP( v ) ( (((v)>>5) & 0x1f) | (((v)<<5) & 0x3e0) ) + +#endif /* _H_PROCESSOR */ + diff --git a/include/ppc/types.h b/include/ppc/types.h new file mode 100644 index 0000000..63b8384 --- /dev/null +++ b/include/ppc/types.h @@ -0,0 +1,63 @@ +/* tag: data types for forth engine + * + * Copyright (C) 2003-2005 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __TYPES_H +#define __TYPES_H + +#include "mconfig.h" + +#ifndef __APPLE__ +#include +#else +/* Mac OS X */ +typedef char int8_t; +typedef unsigned char uint8_t; +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef unsigned int u_int32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; +typedef unsigned long long u_int64_t; +#endif + +/* endianess */ +#ifdef HAVE_ENDIAN_H +#include +#else +#include +#endif + +/* cell based types */ + +typedef int32_t cell; +typedef uint32_t ucell; +typedef int64_t dcell; +typedef uint64_t ducell; + +#define bitspercell (sizeof(cell)<<3) +#define bitsperdcell (sizeof(dcell)<<3) + +#define BITS 32 + +/* size named types */ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +#endif diff --git a/include/sys_info.h b/include/sys_info.h new file mode 100644 index 0000000..324b77c --- /dev/null +++ b/include/sys_info.h @@ -0,0 +1,34 @@ +#ifndef SYS_INFO_H +#define SYS_INFO_H + +/* Information collected from firmware/bootloader */ + +struct sys_info { + /* Values passed by bootloader */ + unsigned long boot_type; + unsigned long boot_data; + unsigned long boot_arg; + + char *firmware; /* "PCBIOS", "LinuxBIOS", etc. */ + char *command_line; /* command line given to us */ + + /* memory map */ + int n_memranges; + struct memrange { + unsigned long long base; + unsigned long long size; + } *memrange; + unsigned long *dict_start; + unsigned long *dict_end; +}; + +void collect_sys_info(struct sys_info *info); +void collect_elfboot_info(struct sys_info *info); +void collect_linuxbios_info(struct sys_info *info); + +/* Our name and version. I want to see single instance of these in the image */ +extern const char *program_name, *program_version; + +#define LOADER_NOT_SUPPORT 0xbadf11e + +#endif /* SYS_INFO_H */ diff --git a/include/unix/plugin_pci.h b/include/unix/plugin_pci.h new file mode 100644 index 0000000..c0f94fe --- /dev/null +++ b/include/unix/plugin_pci.h @@ -0,0 +1,25 @@ +/* tag: openbios pci plugin headers + * + * Copyright (C) 2003 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __PLUGINS_PCI_H +#define __PLUGINS_PCI_H + +typedef struct pci_dev pci_dev_t; + +struct pci_dev { + unsigned bus; + unsigned dev; + unsigned fn; + + u8 *config; + pci_dev_t *next; +}; + +int pci_register_device(unsigned bus, unsigned dev, unsigned fn, u8 *config); + +#endif diff --git a/include/unix/plugins.h b/include/unix/plugins.h new file mode 100644 index 0000000..be09e50 --- /dev/null +++ b/include/unix/plugins.h @@ -0,0 +1,31 @@ + +#ifndef __PLUGINS_H +#define __PLUGINS_H + +#include "asm/types.h" + +struct io_ops { + u8 (*inb)(u32 reg); + u16 (*inw)(u32 reg); + u32 (*inl)(u32 reg); + void (*outb)(u32 reg, u8 val); + void (*outw)(u32 reg, u16 val); + void (*outl)(u32 reg, u32 val); +}; +typedef struct io_ops io_ops_t; + +extern unsigned char *plugindir; + +#define PLUGIN_DEPENDENCIES(x...) const char *plugin_deps[]={ x, NULL }; +#define PLUGIN_AUTHOR(author) const char *plugin_author=author; +#define PLUGIN_LICENSE(license) const char *plugin_license=license; +#define PLUGIN_DESCRIPTION(desc) const char *plugin_description=desc; + +int register_iorange(const char *name, io_ops_t *ops, + unsigned int rstart, unsigned int rend); +io_ops_t *find_iorange(u32 reg); + +int load_plugin(const char *plugin_name); +int is_loaded(const char *plugin_name); + +#endif diff --git a/include/x86/elf.h b/include/x86/elf.h new file mode 100644 index 0000000..86c6725 --- /dev/null +++ b/include/x86/elf.h @@ -0,0 +1,5 @@ +#define ARCH_ELF_CLASS ELFCLASS32 +#define ARCH_ELF_DATA ELFDATA2LSB +#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486) +typedef Elf32_Ehdr Elf_ehdr; +typedef Elf32_Phdr Elf_phdr; diff --git a/include/x86/io.h b/include/x86/io.h new file mode 100644 index 0000000..587ab90 --- /dev/null +++ b/include/x86/io.h @@ -0,0 +1,70 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +extern unsigned long virt_offset; + +#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset)) +#define virt_to_phys(virt) ((unsigned long) (virt) + virt_offset) + +#define __SLOW_DOWN_IO "outb %%al,$0x80;" +static inline void slow_down_io(void) +{ + __asm__ __volatile__( + __SLOW_DOWN_IO +#ifdef REALLY_SLOW_IO + __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + : : ); +} + +#define BUILDIO(bwl,bw,type) \ +static inline void out##bwl(unsigned type value, int port) { \ + __asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \ +} \ +static inline unsigned type in##bwl(int port) { \ + unsigned type value; \ + __asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \ + return value; \ +} \ +static inline void out##bwl##_p(unsigned type value, int port) { \ + out##bwl(value, port); \ + slow_down_io(); \ +} \ +static inline unsigned type in##bwl##_p(int port) { \ + unsigned type value = in##bwl(port); \ + slow_down_io(); \ + return value; \ +} \ +static inline void outs##bwl(int port, const void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \ +} \ +static inline void ins##bwl(int port, void *addr, unsigned long count) { \ + __asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \ +} + +#ifndef BOOTSTRAP +BUILDIO(b,b,char) +BUILDIO(w,w,short) +BUILDIO(l,,int) +#else +#ifdef FCOMPILER +#define inb(reg) ((u8)0xff) +#define inw(reg) ((u16)0xffff) +#define inl(reg) ((u32)0xffffffff) +// #define insw( u32 reg, void *addr, unsigned long count ); +#define outb(reg, val) // nothing +#define outw(reg, val) // nothing +#define outl(reg, val) // nothing +// #define outsw( u32 reg, const void *addr, unsigned long count); +#else +extern u8 inb( u32 reg ); +extern u16 inw( u32 reg ); +extern u32 inl( u32 reg ); +extern void insw( u32 reg, void *addr, unsigned long count ); +extern void outb( u32 reg, u8 val ); +extern void outw( u32 reg, u16 val ); +extern void outl( u32 reg, u32 val ); +extern void outsw( u32 reg, const void *addr, unsigned long count); +#endif +#endif +#endif diff --git a/include/x86/pci.h b/include/x86/pci.h new file mode 100644 index 0000000..4433e7d --- /dev/null +++ b/include/x86/pci.h @@ -0,0 +1,66 @@ +#ifndef i386_PCI_H +#define i386_PCI_H + +#include "asm/io.h" + +#if !(PCI_CONFIG_1 || PCI_CONFIG_2) +#define PCI_CONFIG_1 1 /* default */ +#endif + +#ifdef PCI_CONFIG_1 + +/* PCI Configuration Mechanism #1 */ + +/* Have pci_addr in the same format as the values written to 0xcf8 + * so register accesses can be made easy. */ +#define PCI_ADDR(bus, dev, fn) \ + ((pci_addr) (0x80000000u \ + | (uint32_t) (bus) << 16 \ + | (uint32_t) (dev) << 11 \ + | (uint32_t) (fn) << 8)) + +#define PCI_BUS(pcidev) ((uint8_t) ((pcidev) >> 16)) +#define PCI_DEV(pcidev) ((uint8_t) ((pcidev) >> 11) & 0x1f) +#define PCI_FN(pcidev) ((uint8_t) ((pcidev) >> 8) & 7) + +static inline uint8_t pci_config_read8(pci_addr dev, uint8_t reg) +{ + outl(dev | (reg & ~3), 0xcf8); + return inb(0xcfc | (reg & 3)); +} + +static inline uint16_t pci_config_read16(pci_addr dev, uint8_t reg) +{ + outl(dev | (reg & ~3), 0xcf8); + return inw(0xcfc | (reg & 2)); +} + +static inline uint32_t pci_config_read32(pci_addr dev, uint8_t reg) +{ + outl(dev | reg, 0xcf8); + return inl(0xcfc | reg); +} + +static inline void pci_config_write8(pci_addr dev, uint8_t reg, uint8_t val) +{ + outl(dev | (reg & ~3), 0xcf8); + outb(val, 0xcfc | (reg & 3)); +} + +static inline void pci_config_write16(pci_addr dev, uint8_t reg, uint16_t val) +{ + outl(dev | (reg & ~3), 0xcf8); + outw(val, 0xcfc | (reg & 2)); +} + +static inline void pci_config_write32(pci_addr dev, uint8_t reg, uint32_t val) +{ + outl(dev | reg, 0xcf8); + outl(val, 0xcfc); +} + +#else /* !PCI_CONFIG_1 */ +#error PCI Configuration Mechanism is not specified or implemented +#endif + +#endif /* i386_PCI_H */ diff --git a/include/x86/types.h b/include/x86/types.h new file mode 100644 index 0000000..a54dcef --- /dev/null +++ b/include/x86/types.h @@ -0,0 +1,44 @@ +/* tag: data types for forth engine + * + * This file is autogenerated by types.sh. Do not edit! + * + * Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __TYPES_H +#define __TYPES_H + +#include + +/* endianess */ + +#include "autoconf.h" + +/* cell based types */ + +typedef int32_t cell; +typedef uint32_t ucell; +typedef int64_t dcell; +typedef uint64_t ducell; + +#define bitspercell (sizeof(cell)<<3) +#define bitsperdcell (sizeof(dcell)<<3) + +#define BITS 32 + +/* size named types */ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +#endif diff --git a/kernel/Kconfig b/kernel/Kconfig new file mode 100644 index 0000000..e4dc867 --- /dev/null +++ b/kernel/Kconfig @@ -0,0 +1,89 @@ +menu "Kernel Debugging" + +config DEBUG + bool "Kernel Debugging" + default y + help + Kernel Debugging + +config DEBUG_BOOT + bool "Boot messages" + depends on DEBUG + default y + help + early boot code (multiboot parsing etc) + +config DEBUG_DSTACK + bool "dstack messages" + depends on DEBUG + default n + help + stack debugging. warning: heavy output! + +config DEBUG_RSTACK + bool "rstack messages" + depends on DEBUG + default n + help + stack debugging. warning: heavy output! + +config DEBUG_DICTIONARY + bool "Dictionary loading/dumping" + depends on DEBUG + default n + help + print few additional information on dictionary loading/dumping + +config DEBUG_INTERNAL + bool "Prime Words" + depends on DEBUG + default n + help + print additional information for some prime words, like branches + +config DEBUG_INTERPRETER + bool "Interpreter" + depends on DEBUG + default n + help + additional information about the unix.c builtin C interpreter + and some other places where it actually does not belong. + +config DEBUG_CONSOLE + bool "Console" + default y + help + use builtin C console code for user interaction. There is no + real alternative to this until someone writes a display/kbd or + serial driver in forth. + +config DEBUG_CONSOLE_SERIAL + bool "Serial Console" + depends on DEBUG_CONSOLE + default y + help + use serial console. + +config SERIAL_PORT + int "Serial Port" + depends on DEBUG_CONSOLE_SERIAL + default "1" + help + 0 for none, 1 for ttyS0, 2 for ttyS1 + +config SERIAL_SPEED + int "Serial line speed" + depends on DEBUG_CONSOLE_SERIAL + default "115200" + help + supported speeds are: 115200, 57600, 38400, 19200, 9600 + +config DEBUG_CONSOLE_VGA + bool "VGA Console" + depends on DEBUG_CONSOLE + default y + help + use vga textmode and keyboard console + +endmenu + diff --git a/kernel/README b/kernel/README new file mode 100644 index 0000000..c84879b --- /dev/null +++ b/kernel/README @@ -0,0 +1,93 @@ + +Welcome to the OpenBIOS forth core "begin again". + +Find more information about OpenBIOS at http://www.openbios.org/ + +This program was written by Patrick Mauritz and Stefan Reinauer in 2003 +For license details on this piece of software, check Documentation/COPYING. + +How OpenBIOS works +------------------ + + The OpenBIOS forth core is split into a forth kernel written in C + and a forth dictionary which operated on by the kernel. + + When building the forth core, you get different versions of + the forth kernel: + + * a "hosted" unix binary. This binary can be used on a unix system + + - to execute a forth dictionary from a file. This can be used for + testing openbios code in a development environment on a unix host. + + - to create a dictionary file. Such a dictionary file sets up + all of the forth language. Primitives are indexed to save relocations. + + The default is to create a forth dictionary forth.dict from + forth/start.fs. This file includes all of the basic forth language + constructs from forth/bootstrap.fs and starts the interpreter. + + To achieve this, the hosted unix version contains a basic set of + forth words coded in C that allow creating a full dictionary. + + * a varying number of target specific binaries. On x86 you can start + openbios for example from GRUB or LinuxBIOS. They are all based on + the same forth engine consisting of a dictionary scheduler, primitive + words needed to build the forth environment, 2 stacks and a simple + set of console functions. These binaries can not be started directly + in the unix host environment. + +Requirements +------------ + * gcc + * grub or any other multiboot loader to run the standalone + binary "openbios.multiboot" + +Building & Usage +---------------- + + * make + + this builds "openbios.multiboot", the standalone image and "unix", + the hosted image. Additionally it creates a forth dictionary + file from forth/start.fs. All generated files are written to + the absolute directory held by the variable BUILDDIR, which defaults + to obj-[platform]. Some compile time parameters can be tweaked in + include/config.h + + * use "unix" to create a forth dictionary on your own: + $ ./unix -Iforth start.fs + creates the file forth.dict from forth source forth/start.fs. + + * use "unix" to run a created dictionary: + $ ./unix forth.dict + This is useful for testing + + * booting openbios + You can boot openbios i.e. in grub. Add the following lines to + your menu.lst: + + title openbios + kernel (hd0,2)/boot/openbios.multiboot + module (hd0,2)/boot/openfirmware.dict + + Note: change (hd0,2) to the partition you copied openbios and + forth.dict to. + + To boot OpenBIOS from LinuxBIOS/etherboot, you can either use + "openbios" or "openbios.full": + + - openbios is the pure kernel that loads the dictionary from a + hardcoded address in flash memory (0xfffe0000) + + - openbios.full also includes the dictionary directly so that it + can be easily used from etherboot or the LinuxBIOS builtin ELF + loader without taking care of the dictionary + + +Comments are welcome. + + OpenBIOS team + +------------------------------------------------------------------------ +tag: README for openbios forth core diff --git a/kernel/bootstrap.c b/kernel/bootstrap.c new file mode 100644 index 0000000..8fc4dd8 --- /dev/null +++ b/kernel/bootstrap.c @@ -0,0 +1,1111 @@ +/* tag: forth bootstrap environment + * + * Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/sysinclude.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __GLIBC__ +#define _GNU_SOURCE +#include +#endif + +#include "openbios/config.h" +#include "openbios/stack.h" +#include "openbios/sysinclude.h" +#include "openbios/kernel.h" +#include "dict.h" +#include "cross.h" + + +#define MEMORY_SIZE (1024*1024) /* 1M ram for hosted system */ +#define DICTIONARY_SIZE (256*1024) /* 256k for the dictionary */ +#define TRAMPOLINE_SIZE (4*sizeof(cell)) /* 4 cells for the trampoline */ + +/* state variables */ +ucell *latest, *state, *base; +ucell *memory; +ucell *trampoline; + +/* local variables */ +static int errors = 0; +static int segfault = 0; +int verbose = 0; + +static FILE *srcfiles[64]; +static unsigned int cursrc = 0; + +#ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH +unsigned long base_address; +#endif + +/* include path handling */ +typedef struct include_path include; +struct include_path { + char *path; + include *next; +}; + +include includes = { ".", NULL }; + +static ucell * relocation_address=NULL; +static int relocation_length=0; + +/* the word names are used to generate the prim words in the + * dictionary. This is done by the C written interpreter. + */ +static const char *wordnames[] = { + "(semis)", "", "(lit)", "", "", "", "", "(do)", "(?do)", "(loop)", + "(+loop)", "", "", "", "dup", "2dup", "?dup", "over", "2over", "pick", "drop", + "2drop", "nip", "roll", "rot", "-rot", "swap", "2swap", ">r", "r>", + "r@", "depth", "depth!", "rdepth", "rdepth!", "+", "-", "*", "u*", + "mu/mod", "abs", "negate", "max", "min", "lshift", "rshift", ">>a", + "and", "or", "xor", "invert", "d+", "d-", "m*", "um*", "@", "c@", + "w@", "l@", "!", "+!", "c!", "w!", "l!", "=", ">", "<", "u>", "u<", + "sp@", "move", "fill", "(emit)", "(key?)", "(key)", "execute", + "here", "here!", "dobranch", "do?branch", "unaligned-w@", + "unaligned-w!", "unaligned-l@", "unaligned-l!", "ioc@", "iow@", + "iol@", "ioc!", "iow!", "iol!", "i", "j", "call", "sys-debug", + "$include", "$encode-file" +}; + +void init_trampoline(void) +{ + if (!trampoline) { + /* We're using side effects which is to some extent nasty */ + printf("WARNING: no trampoline!\n"); + return; + } + + trampoline[0]=DOCOL; + trampoline[1]=0; + trampoline[2]=target_ucell(pointer2cell(trampoline)+3*sizeof(ucell)); + trampoline[3]=0; +} + +/* + * dictionary related functions. + */ + +static void relocation_table(char * dict_one, char *dict_two, int length) +{ + ucell *d1=(ucell *)dict_one, *d2=(ucell *)dict_two; + ucell *reloc_table; + int pos, bit; + int l=(length+(sizeof(cell)-1))/sizeof(ucell), i; + + /* prepare relocation table */ + relocation_length=(l+BITS-1)/BITS; + reloc_table = malloc(relocation_length*sizeof(cell)); + memset(reloc_table,0,relocation_length*sizeof(cell)); + + for (i=0; i<=l; i++) { + + pos=i/BITS; + bit=i&~(-BITS); + + if(d1[i]==d2[i]) { + reloc_table[pos] &= target_ucell(~(1UL<= pointer2cell(dict_one) && + d1[i] <= pointer2cell(dict_one+length)) + printk("\nWARNING: inconsistent relocation (%x:%x)!\n", d1[i], d2[i]); + } else { + /* This is a pointer, it needs relocation, d2==dict */ + reloc_table[pos] |= target_ucell(1UL<relocation=0; + } + + /* + * Calculate Checksum + */ + + walk_data=write_data; + while (walk_datachecksum=target_long(checksum); + + dump_header(header); + + f = fopen(filename, "w"); + if (!f) { + printk("panic: can't write to dictionary '%s'.\n", filename); + exit(1); + } + + fwrite(write_data, write_len, 1, f); + + free(write_data); + fclose(f); + +#ifdef CONFIG_DEBUG_DICTIONARY + printk("wrote dictionary to file %s.\n", filename); +#endif +} + +static ucell read_dictionary(char *fil) +{ + int ilen; + ucell ret; + char *mem; + FILE *f; + struct stat finfo; + + if (stat(fil, &finfo)) + return 0; + + ilen = finfo.st_size; + + if ((mem = malloc(ilen)) == NULL) { + printk("panic: not enough memory.\n"); + exit(1); + } + + f = fopen(fil, "r"); + if (!f) { + printk("panic: can't open dictionary.\n"); + exit(1); + } + + if (fread(mem, ilen, 1, f) != 1) { + printk("panic: can't read dictionary.\n"); + fclose(f); + exit(1); + } + fclose(f); + + ret = load_dictionary(mem, ilen); + + free(mem); + return ret; +} + + +/* + * C Parser related functions + */ + +/* + * skipws skips all whitespaces (space, tab, newline) from the input file + */ + +static void skipws(FILE * f) +{ + int c; + while (!feof(f)) { + c = getc(f); + + if (c == ' ' || c == '\t' || c == '\n') + continue; + + ungetc(c, f); + break; + } +} + +/* + * parse gets the next word from the input stream, delimited by + * delim. If delim is 0, any word delimiter will end the stream + * word delimiters are space, tab and newline. The resulting word + * will be put zero delimited to the char array line. + */ + +static int parse(FILE * f, char *line, char delim) +{ + int cnt = 0, c; + + while (!feof(f)) { + c = getc(f); + + if (delim && c == delim) + break; + + if ((!delim) && (c == ' ' || c == '\n' || c == '\t')) + break; + + line[cnt++] = c; + } + + line[cnt] = 0; + + return cnt; +} + +/* + * parse_word is a small helper that skips whitespaces before a word. + * it's behaviour is similar to the forth version parse-word. + */ + +static void parse_word(FILE * f, char *line) +{ + skipws(f); + parse(f, line, 0); +} + + +static void writestring(const char *str) +{ + unsigned int i; + for (i = 0; i < strlen(str); i++) { + dict[dicthead + i] = str[i]; + } + dicthead += i + 1; + dict[dicthead - 1] = (char) strlen(str) + 128; +} + +#define writebyte(value) {write_byte(dict+dicthead,value); dicthead++;} +#define writecell(value) {write_cell(dict+dicthead, value); dicthead+=sizeof(cell);} + +/* + * reveal a word, ie. make it visible. + */ + +static void reveal(void) +{ + *last = *latest; +} + +/* + * dictionary padding + */ + +static void paddict(ucell align) +{ + while (dicthead % align != 0) + writebyte(0); +} + +/* + * generic forth word creator function. + */ + +static void fcreate(char *word, ucell cfaval) +{ + if (strlen(word) == 0) { + printk("WARNING: tried to create unnamed word.\n"); + return; + } + + writestring(word); + /* get us at least 1 byte for flags */ + writebyte(0); + paddict(sizeof(cell)); + /* set flags high bit. */ + dict[dicthead - 1] = 128; + /* lfa and cfa */ + writecell(read_ucell(latest)); + *latest = target_ucell(pointer2cell(dict) + dicthead - sizeof(cell)); + writecell(cfaval); +} + + +static ucell *buildvariable(char *name, cell defval) +{ + fcreate(name, DOVAR); /* see dict.h for DOVAR and other CFA ids */ + writecell(defval); + return (ucell *) (dict + dicthead - sizeof(cell)); +} + +static void buildconstant(char *name, cell defval) +{ + fcreate(name, DOCON); /* see dict.h for DOCON and other CFA ids */ + writecell(defval); +} + +static void builddefer(char *name) +{ + fcreate(name, DODFR); /* see dict.h for DODFR and other CFA ids */ + writecell(0); + writecell((ucell)findword("(semis)")); +} + +/* + * Include file handling + */ + +static void add_includepath(char *path) +{ + include *incl = &includes; + include *newpath; + + while (incl->next) + incl = incl->next; + + newpath = malloc(sizeof(include)); + if (!newpath) { + printk("panic: not enough memory for include path.\n"); + exit(1); + } + + incl->next = newpath; + newpath->path = path; + newpath->next = NULL; +} + + +static FILE *fopen_include(const char *fil) +{ +#define MAX_PATH_LEN 256 + char fullpath[MAX_PATH_LEN]; + FILE *ret; + include *incl = &includes; + + while (incl) { + strncpy(fullpath, incl->path, MAX_PATH_LEN); + strncat(fullpath, "/", MAX_PATH_LEN); + strncat(fullpath, fil, MAX_PATH_LEN); + ret = fopen(fullpath, "r"); + if (ret != NULL) + return ret; + incl = incl->next; + } + return NULL; +} + +/* + * This is the C version of the forth interpreter + */ + +static int interpret_source(char *fil) +{ + FILE *f; + char tib[160]; + long num; + char *test; + + const ucell SEMIS = (ucell)findword("(semis)"); + const ucell LIT = (ucell)findword("(lit)"); + const ucell DOBRANCH = (ucell)findword("dobranch"); + + if ((f = fopen_include(fil)) == NULL) { + printk("error while loading source file '%s'\n", fil); + errors++; + exit(1); + } + + /* FIXME: We should read this file at + * once. No need to get it char by char + */ + + while (!feof(f)) { + xt_t res; + parse_word(f, tib); + + /* if there is actually no word, we continue right away */ + if (strlen(tib) == 0) { + continue; + } + + /* Checking for builtin words that are needed to + * bootstrap the forth base dictionary. + */ + + if (!strcmp(tib, "(")) { + parse(f, tib, ')'); + continue; + } + + if (!strcmp(tib, "\\")) { + parse(f, tib, '\n'); + continue; + } + + if (!strcmp(tib, ":")) { + parse_word(f, tib); + +#ifdef CONFIG_DEBUG_INTERPRETER + printk("create colon word %s\n\n", tib); +#endif + fcreate(tib, DOCOL); /* see dict.h for DOCOL and other CFA ids */ + *state = (ucell) (-1); + continue; + } + + if (!strcmp(tib, ";")) { +#ifdef CONFIG_DEBUG_INTERPRETER + printk("finish colon definition\n\n"); +#endif + writecell((cell)SEMIS); + *state = (ucell) 0; + reveal(); + continue; + } + + if (!strcasecmp(tib, "variable")) { + parse_word(f, tib); +#ifdef CONFIG_DEBUG_INTERPRETER + printk("defining variable %s\n\n", tib); +#endif + buildvariable(tib, 0); + reveal(); + continue; + } + + if (!strcasecmp(tib, "constant")) { + parse_word(f, tib); +#ifdef CONFIG_DEBUG_INTERPRETER + printk("defining constant %s\n\n", tib); +#endif + buildconstant(tib, POP()); + reveal(); + continue; + } + + if (!strcasecmp(tib, "value")) { + parse_word(f, tib); +#ifdef CONFIG_DEBUG_INTERPRETER + printk("defining value %s\n\n", tib); +#endif + buildconstant(tib, POP()); + reveal(); + continue; + } + + if (!strcasecmp(tib, "defer")) { + parse_word(f, tib); +#ifdef CONFIG_DEBUG_INTERPRETER + printk("defining defer word %s\n\n", tib); +#endif + builddefer(tib); + reveal(); + continue; + } + + if (!strcasecmp(tib, "include")) { + parse_word(f, tib); +#ifdef CONFIG_DEBUG_INTERPRETER + printk("including file %s\n\n", tib); +#endif + interpret_source(tib); + continue; + } + + if (!strcmp(tib, "[']")) { + xt_t xt; + parse_word(f, tib); + xt = findword(tib); + if (*state == 0) { +#ifdef CONFIG_DEBUG_INTERPRETER + printk + ("writing address of %s to stack\n\n", + tib); +#endif + PUSH_xt(xt); + } else { +#ifdef CONFIG_DEBUG_INTERPRETER + printk("writing lit, addr(%s) to dict\n\n", + tib); +#endif + writecell(LIT); /* lit */ + writecell((cell)xt); + } + continue; + /* we have no error detection here */ + } + + if (!strcasecmp(tib, "s\"")) { + int cnt; + cell loco; + + cnt = parse(f, tib, '"'); +#ifdef CONFIG_DEBUG_INTERPRETER + printk("compiling string %s\n", tib); +#endif + loco = dicthead + (6 * sizeof(cell)); + writecell(LIT); + writecell(pointer2cell(dict) + loco); + writecell(LIT); + writecell(cnt); + writecell(DOBRANCH); + loco = cnt + sizeof(cell) - 1; + loco &= ~(sizeof(cell) - 1); + writecell(loco); + memcpy(dict + dicthead, tib, cnt); + dicthead += cnt; + paddict(sizeof(cell)); + continue; + } + + /* look if tib is in dictionary. */ + /* should the dictionary be searched before the builtins ? */ + res = findword(tib); + if (res) { + u8 flags = read_byte((u8*)cell2pointer(res) - + sizeof(cell) - 1); +#ifdef CONFIG_DEBUG_INTERPRETER + printk("%s is 0x%p\n", tib, (ucell) res); +#endif + if (!(*state) || (flags & 3)) { +#ifdef CONFIG_DEBUG_INTERPRETER + printk("executing %s, %p (flags: %s %s)\n", + tib, res, + (flags & 1) ? "immediate" : "", + (flags & 2) ? "compile-only" : ""); +#endif + PC = (ucell)res; + enterforth(res); + } else { +#ifdef CONFIG_DEBUG_INTERPRETER + printk("writing %s to dict\n\n", tib); +#endif + writecell((cell)res); + } + continue; + } + + /* if not look if it's a number */ + if (tib[0] == '-') + num = strtol(tib, &test, read_ucell(base)); + else + num = strtoul(tib, &test, read_ucell(base)); + + + if (*test != 0) { + /* what is it?? */ + printk("%s is not defined.\n\n", tib); + errors++; +#ifdef CONFIG_DEBUG_INTERPRETER + continue; +#else + return -1; +#endif + } + + if (*state == 0) { +#ifdef CONFIG_DEBUG_INTERPRETER + printk("pushed %x to stack\n\n", num); +#endif + PUSH(num); + } else { +#ifdef CONFIG_DEBUG_INTERPRETER + printk("writing lit, %x to dict\n\n", num); +#endif + writecell(LIT); /* lit */ + writecell(num); + } + } + fclose(f); + + return 0; +} + +static int build_dictionary(void) +{ + ucell lfa = 0; + unsigned int i; + + /* we need a temporary place for latest outside the dictionary */ + latest = &lfa; + + /* starting a new dictionary: clear dicthead */ + dicthead = 0; + +#ifdef CONFIG_DEBUG_DICTIONARY + printk("building dictionary, %d primitives.\nbuilt words:", + sizeof(wordnames) / sizeof(void *)); +#endif + + for (i = 0; i < sizeof(wordnames) / sizeof(void *); i++) { + if (strlen(wordnames[i]) != 0) { + fcreate((char *) wordnames[i], i); +#ifdef CONFIG_DEBUG_DICTIONARY + printk(" %s", wordnames[i]); +#endif + } + } +#ifdef CONFIG_DEBUG_DICTIONARY + printk(".\n"); +#endif + + /* get last/latest and state */ + state = buildvariable("state", 0); + last = buildvariable("forth-last", 0); + latest = buildvariable("latest", 0); + + *latest = target_ucell(pointer2cell(latest)-2*sizeof(cell)); + + base=buildvariable("base", 10); + + buildconstant("/c", sizeof(u8)); + buildconstant("/w", sizeof(u16)); + buildconstant("/l", sizeof(u32)); + buildconstant("/n", sizeof(ucell)); + + reveal(); + printk("Dictionary initialization finished.\n"); + + return 0; +} + +/* + * functions used by primitives + */ + +int availchar(void) +{ + int tmp; + if( cursrc < 1 ) { + runforth = 0; + /* return -1 in order to exit the loop in key() */ + return -1; + } + + tmp = getc( srcfiles[cursrc-1] ); + if (tmp != EOF) { + ungetc(tmp, srcfiles[cursrc-1]); + return -1; + } + fclose( srcfiles[--cursrc] ); + + return availchar(); +} + +int get_inputbyte( void ) +{ + int tmp; + + if( cursrc < 1 ) { + runforth = 0; + return 0; + } + + tmp = getc( srcfiles[cursrc-1] ); + if (tmp != EOF) + return tmp; + fclose( srcfiles[--cursrc] ); + + return get_inputbyte(); +} + +/* + * segmentation fault handler. linux specific? + */ + +static void +segv_handler(int signo __attribute__ ((unused)), + siginfo_t * si, void *context __attribute__ ((unused))) +{ + static int count = 0; + ucell addr = 0xdeadbeef; + + if (count) { + printk("Died while dumping forth dictionary core.\n"); + goto out; + } + + count++; + + if (PC >= pointer2cell(dict) && PC <= pointer2cell(dict) + dicthead) + addr = read_cell(cell2pointer(PC)); + + printk("panic: segmentation violation at %p\n", (char *)si->si_addr); + printk("dict=%p here=%p(dict+0x%x) pc=0x%x(dict+0x%x)\n", + dict, dict + dicthead, dicthead, PC, PC - pointer2cell(dict)); + printk("dstackcnt=%d rstackcnt=%d instruction=%x\n", + dstackcnt, rstackcnt, addr); + + printdstack(); + printrstack(); + + printk("Writing dictionary core file\n"); + write_dictionary("forth.dict.core"); + + out: + exit(1); +} + +/* + * allocate memory and prepare engine for memory management. + */ + +static void init_memory(void) +{ + memset(memory, 0, MEMORY_SIZE); + + /* we push start and end of memory to the stack + * so that it can be used by the forth word QUIT + * to initialize the memory allocator. + * Add a cell to the start address so we don't end + * up with a start address of zero during bootstrap + */ + + PUSH(pointer2cell(memory)+sizeof(cell)); + PUSH(pointer2cell(memory) + MEMORY_SIZE-1); +} + +void exception(cell no) +{ + switch (no) { + case -19: + printk(" undefined word.\n"); + break; + default: + printk("\nError %d occured.\n", no); + } + exit(1); +} + + +void +include_file( const char *name ) +{ + FILE *file = fopen_include( name ); + if( !file ) { + printk("\npanic: Failed opening '%s'\n", name ); + exit(1); + } + if( cursrc >= sizeof(srcfiles)/sizeof(srcfiles[0]) ) { + printk("\npanic: Maximum include depth reached!\n"); + exit(1); + } +#ifdef CONFIG_DEBUG_INTERPRETER + printk("Including '%s'\n", name ); +#endif + srcfiles[ cursrc++ ] = file; +} + +void +encode_file( const char *name ) +{ + FILE *file = fopen_include(name); + int size; + + if( !file ) { + printk("\npanic: Can't open '%s'\n", name ); + exit(1); + } + fseek( file, 0, SEEK_END ); + size = ftell( file ); + fseek( file, 0, SEEK_SET ); + + printk("\nEncoding %s [%d bytes]\n", name, size ); + fread( dict + dicthead, size, 1, file ); + PUSH( pointer2cell(dict + dicthead) ); + PUSH( size ); + dicthead += size; +} + + +static void run_dictionary(const char *basedict) +{ + if(!basedict) + return; + + read_dictionary((char *)basedict); + PC = (ucell)findword("initialize"); + + if (!PC) + return; + + if(!srcfiles[0]) { + cursrc = 1; + srcfiles[cursrc-1] = stdin; + } + + dstackcnt=0; + rstackcnt=0; + + init_memory(); + if (verbose) + printk("Jumping to dictionary..."); + + runforth=-1; + enterforth((xt_t)PC); +} + +static void new_dictionary(const char *source) +{ + build_dictionary(); + + interpret_source((char *)source); + + printk("interpretion finished. %d errors occured.\n", + errors); +} + +/* + * main loop + */ + +#define BANNER "OpenBIOS bootstrap kernel. (C) 2003-2005 Patrick Mauritz, Stefan Reinauer\n"\ + "This software comes with absolutely no warranty. "\ + "All rights reserved.\n\n" + +#ifdef __GLIBC__ +#define USAGE "Usage: %s [options] [dictionary file|source file]\n\n" \ + " -h|--help show this help\n" \ + " -V|--version print version and exit\n" \ + " -v|--verbose print debugging information\n" \ + " -I|--include dir add dir to include path\n" \ + " -d|--source-dictionary bootstrap.dict\n" \ + " use this dictionary as base\n" \ + " -D|--target-dictionary output.dict\n" \ + " write to output.dict\n" \ + " -s|--segfault install segfault handler\n\n" +#else +#define USAGE "Usage: %s [options] [dictionary file|source file]\n\n" \ + " -h show this help\n" \ + " -V print version and exit\n" \ + " -v print debugging information\n" \ + " -I add dir to include path\n" \ + " -d bootstrap.dict\n" \ + " use this dictionary as base\n" \ + " -D output.dict\n" \ + " write to output.dict\n" \ + " -s install segfault handler\n\n" + +#endif + +int main(int argc, char *argv[]) +{ + struct sigaction sa; + + unsigned char *ressources=NULL; /* All memory used by us */ + unsigned char *dictname = NULL; + unsigned char *basedict = NULL; + + unsigned char *bootstrapdict[2]; + int c, cnt; + + const char *optstring = "VvhsI:d:D:?"; + + printk(BANNER); + + while (1) { +#ifdef __GLIBC__ + int option_index = 0; + static struct option long_options[] = { + {"version", 0, NULL, 'V'}, + {"verbose", 0, NULL, 'v'}, + {"help", 0, NULL, 'h'}, + {"segfault", 0, NULL, 's'}, + {"include", 1, NULL, 'I'}, + {"source-dictionary", 1, NULL, 'd'}, + {"target-dictionary", 1, NULL, 'D'}, + }; + + /* + * option handling + */ + + c = getopt_long(argc, argv, optstring, long_options, + &option_index); +#else + c = getopt(argc, argv, optstring); +#endif + if (c == -1) + break; + + switch (c) { + case 'V': + printk("Version " VERSION "\n"); + return 0; + case 'h': + case '?': + printk("Version " VERSION "\n" USAGE, argv[0]); + return 0; + case 'v': + verbose = 1; + break; + case 's': + segfault = 1; + break; + case 'I': +#ifdef CONFIG_DEBUG_INTERPRETER + printk("adding '%s' to include path\n", optarg); +#endif + add_includepath(optarg); + break; + case 'd': + if (!basedict) { + printk("Using source dictionary '%s'\n", optarg); + basedict = optarg; + } + case 'D': + if(!dictname) { + printk("Dumping final dictionary to '%s'\n", optarg); + dictname = optarg; + } + break; + default: + return 1; + } + } + + if (argc < optind + 1) { + printk(USAGE, argv[0]); + return 1; + } + + + /* + * Get all required resources + */ + + + ressources = malloc(MEMORY_SIZE + (2 * DICTIONARY_SIZE) + TRAMPOLINE_SIZE); + if (!ressources) { + printk("panic: not enough memory on host system.\n"); + return 1; + } + +#ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH + base_address=(unsigned long)ressources; +#endif + + memory = (ucell *)ressources; + + bootstrapdict[0] = ressources + MEMORY_SIZE; + bootstrapdict[1] = ressources + MEMORY_SIZE + DICTIONARY_SIZE; + trampoline = (ucell *)(ressources + MEMORY_SIZE + DICTIONARY_SIZE + DICTIONARY_SIZE); + +#ifdef CONFIG_DEBUG_INTERPRETER + printf("memory: %p\n",memory); + printf("dict1: %p\n",bootstrapdict[0]); + printf("dict2: %p\n",bootstrapdict[1]); + printf("trampoline: %p\n",trampoline); + printf("size=%d, trampoline_size=%d\n",MEMORY_SIZE + (2 * + DICTIONARY_SIZE) + TRAMPOLINE_SIZE, + TRAMPOLINE_SIZE); +#endif + + init_trampoline(); + + if (!segfault) { + if (verbose) + printk("Installing SIGSEGV handler..."); + + sa.sa_sigaction = segv_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_NODEFER; + sigaction(SIGSEGV, &sa, 0); + + if (verbose) + printk("done.\n"); + } + + /* + * Now do the real work + */ + + for (cnt=0; cnt<2; cnt++) { + printk("Compiling dictionary %d/%d\n", cnt+1, 2); + dict=bootstrapdict[cnt]; + if(!basedict) { + new_dictionary(argv[optind]); + } else { + for (c=argc-1; c>=optind; c--) + include_file(argv[c]); + + run_dictionary(basedict); + } + if(errors) + break; + } + +#ifndef CONFIG_DEBUG_INTERPRETER + if (errors) + printk("dictionary not dumped to file.\n"); + else +#endif + { + relocation_table( bootstrapdict[0], bootstrapdict[1], dicthead); + write_dictionary( dictname ? dictname : + (unsigned char *)"bootstrap.dict"); + } + + free(ressources); + return 0; +} diff --git a/kernel/build.xml b/kernel/build.xml new file mode 100644 index 0000000..5541356 --- /dev/null +++ b/kernel/build.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/kernel/cross.h b/kernel/cross.h new file mode 100644 index 0000000..81be5ed --- /dev/null +++ b/kernel/cross.h @@ -0,0 +1,143 @@ +/* memory access abstraction layer for forth kernel + * + * Copyright (C) 2005 Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __CROSS_H +#define __CROSS_H 1 + +/* The forthstrap compiler has to abstract the underlying dictionary + * type: big/little endian, 32/64bit. All other binaries shall use + * unchanged memory access for performance. + */ + +#if 0 +// This is being moved to rules.xml for now. + +#ifdef FCOMPILER + +/* FIXME these should be automatically determinded. + * Manually setting them here is a PITA. + */ + +#define NATIVE_BITWIDTH_LARGER_THAN_HOST_BITWIDTH +//#define NATIVE_BITWIDTH_EQUALS_HOST_BITWIDTH +//#define NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH + +//#define SWAP_ENDIANNESS +#undef SWAP_ENDIANNESS + +#else /* FCOMPILER */ + +#define NATIVE_BITWIDTH_EQUALS_HOST_BITWIDTH +#undef SWAP_ENDIANNESS + +#endif +#endif + +/* byte swapping */ + +#ifndef SWAP_ENDIANNESS + +/* trivial case - we don't have to change anything */ +#define read_ucell(addr) (*(ucell *)(addr)) +#define read_cell(addr) (*(cell *)(addr)) +#define read_long(addr) (*(u32 *)(addr)) +#define read_word(addr) (*(u16 *)(addr)) +#define read_byte(addr) (*(u8 *)(addr)) + +#define write_ucell(addr, value) {*(ucell *)(addr)=(value);} +#define write_cell(addr, value) {*(cell *)(addr)=(value);} +#define write_long(addr, value) {*(u32 *)(addr)=(value);} +#define write_word(addr, value) {*(u16 *)(addr)=(value);} +#define write_byte(addr, value) {*(u8 *)(addr)=(value);} + +#define target_ucell(x) (x) +#define target_cell(x) (x) +#define target_long(x) (x) +#define target_ulong(x) (x) + +#else /* SWAP_ENDIANNESS */ + +#define target_word(value) ( (((value)>>8)&0xff) | (((value)&0xff)<<8) ) +#define target_long(value) ( (((value)&0xff000000)>>24)|(((value)&0x00ff0000)>>8)|(((value)&0xff00)<<8)|(((value)&0xff)<<24) ) +#define target_ulong(value) (target_long(value)) + +#if BITS==32 +#define target_ucell(value) (target_long(value)) +#define target_cell(value) (target_long(value)) +#elif BITS==64 +#define target_ucell(value) ( ((ucell)target_long((value)&0xffffffff))<<32 | \ + ((ucell)target_long((value)>>32)) ) +#define target_cell(value) ( ((cell)target_long((value)&0xffffffff))<<32 | \ + ((cell)target_long((value)>>32)) ) +#else +#error "Endianness not supported. Please report." +#endif + +#define read_ucell(addr) target_ucell(*(ucell *)(addr)) +#define read_cell(addr) target_cell(*(cell *)(addr)) +#define read_long(addr) target_long(*(u32 *)(addr)) +#define read_word(addr) target_word(*(u16 *)(addr)) +#define read_byte(addr) (*(u8 *)(addr)) + +#define write_ucell(addr, value) {*(ucell *)(addr)=target_ucell(value);} +#define write_cell(addr, value) {*(cell *)(addr)=target_cell(value);} +#define write_long(addr, value) {*(u32 *)(addr)=target_long(value);} +#define write_word(addr, value) {*(u16 *)(addr)=target_word(value);} +#define write_byte(addr, value) {*(u8 *)(addr)=(value);} +#endif + +#ifdef CONFIG_LITTLE_ENDIAN +#define unaligned_read_word(addr) \ + (read_byte(addr)|(read_byte((u8 *)addr+1)<<8)) + +#define unaligned_read_long(addr) \ + (unaligned_read_word(addr)|(unaligned_read_word((u8 *)addr+2)<<16)) + +#define unaligned_write_word(addr, value) \ + write_byte(addr, value & 0xff); write_byte((u8 *)addr+1, value>>8) + +#define unaligned_write_long(addr, value) \ + unaligned_write_word(addr, value & 0xffff); \ + unaligned_write_word(addr, value >> 16) + +#endif + +#ifdef CONFIG_BIG_ENDIAN +#define unaligned_read_word(addr) \ + ((read_byte(addr)<<8)|read_byte((u8 *)addr+1)) + +#define unaligned_read_long(addr) \ + ((unaligned_read_word(addr)<<16)|unaligned_read_word((u8 *)addr+2)) + +#define unaligned_write_word(addr, value) \ + write_byte(addr, value >> 8); write_byte((u8 *)addr+1, value & 0xff) + +#define unaligned_write_long(addr, value) \ + unaligned_write_word(addr, value >> 16); \ + unaligned_write_word(addr, value & 0xffff) +#endif + +/* bit width handling */ + +#ifdef NATIVE_BITWIDTH_EQUALS_HOST_BITWIDTH +#define pointer2cell(x) ((ucell)(x)) +#define cell2pointer(x) ((u8 *)(x)) +#endif + +#ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH +extern unsigned long base_address; +#define pointer2cell(x) ((ucell)(((unsigned long)x)-base_address)) +#define cell2pointer(x) ((u8 *)(((unsigned long)x)+base_address)) +#endif + +#ifdef NATIVE_BITWIDTH_LARGER_THAN_HOST_BITWIDTH +#define pointer2cell(x) ((ucell)(x)) +#define cell2pointer(x) ((u8 *)((unsigned long)x&0xFFFFFFFFUL)) +#endif + +#endif diff --git a/kernel/dict.c b/kernel/dict.c new file mode 100644 index 0000000..b67b58c --- /dev/null +++ b/kernel/dict.c @@ -0,0 +1,183 @@ +/* + * tag: dict management + * + * Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "dict.h" +#ifdef BOOTSTRAP +#include +#else +#include "libc/string.h" +#endif +#include "cross.h" + + +unsigned char *dict = 0; +ucell *last; +cell dicthead = 0; + +/* lfa2nfa + * converts a link field address to a name field address, + * i.e find pointer to a given words name + */ + +ucell lfa2nfa(ucell ilfa) +{ + /* get offset from dictionary start */ + ilfa = ilfa - (ucell)pointer2cell(dict); + ilfa--; /* skip status */ + while (dict[--ilfa] == 0); /* skip all pad bytes */ + ilfa -= (dict[ilfa] - 128); + return ilfa + (ucell)pointer2cell(dict); +} + +/* lfa2cfa + * converts a link field address to a code field address. + * in this forth implementation this is just a fixed offset + */ + +static xt_t lfa2cfa(ucell ilfa) +{ + return (xt_t)(ilfa + sizeof(cell)); +} + + +/* fstrlen - returns length of a forth string. */ + +static ucell fstrlen(ucell fstr) +{ + fstr -= pointer2cell(dict)+1; + //fstr -= pointer2cell(dict); FIXME + while (dict[++fstr] < 128) + ; + return dict[fstr] - 128; +} + +/* to_lower - convert a character to lowecase */ + +static int to_lower(int c) +{ + return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c; +} + +/* fstrcmp - compare null terminated string with forth string. */ + +static int fstrcmp(char *s1, ucell fstr) +{ + char *s2 = (char*)cell2pointer(fstr); + while (*s1) { + if ( to_lower(*(s1++)) != to_lower(*(s2++)) ) + return -1; + } + return 0; +} + +/* findword + * looks up a given word in the dictionary. This function + * is used by the c based interpreter and to find the "initialize" + * word. + */ + +xt_t findword(char *s1) +{ + ucell tmplfa, len; + + if (!last) + return 0; + + tmplfa = read_ucell(last); + + len = strlen(s1); + + while (tmplfa) { + ucell nfa = lfa2nfa(tmplfa); + + if (len == fstrlen(nfa) && !fstrcmp(s1, nfa)) { + return lfa2cfa(tmplfa); + } + + tmplfa = read_ucell(cell2pointer(tmplfa)); + } + + return 0; +} + + +void dump_header(dictionary_header_t *header) +{ + printk("OpenBIOS dictionary:\n"); + printk(" version: %d\n", header->version); + printk(" cellsize: %d\n", header->cellsize); + printk(" endianess: %s\n", header->endianess?"big":"little"); + printk(" compression: %s\n", header->compression?"yes":"no"); + printk(" relocation: %s\n", header->relocation?"yes":"no"); + printk(" checksum: %08x\n", target_long(header->checksum)); + printk(" length: %08x\n", target_long(header->length)); + printk(" last: %08x\n", target_cell(header->last)); +} + +ucell load_dictionary(const char *data, ucell len) +{ + u32 checksum=0; + const char *checksum_walk; + ucell *walk, *reloc_table; + dictionary_header_t *header=(dictionary_header_t *)data; + + /* assertions */ + if (len <= (sizeof(dictionary_header_t)) || strncmp(DICTID, data, 8)) + return 0; +#ifdef CONFIG_DEBUG_DICTIONARY + dump_header(header); +#endif + + checksum_walk=data; + while (checksum_walklength); + + memcpy(dict, data, dicthead); + reloc_table=(ucell *)(data+dicthead); + +#ifdef CONFIG_DEBUG_DICTIONARY + printk("\nmoving dictionary (%x bytes) to %x\n", + (ucell)dicthead, (ucell)dict); + printk("\ndynamic relocation..."); +#endif + + for (walk = (ucell *) dict; walk < (ucell *) (dict + dicthead); + walk++) { + int pos, bit, l; + l=(walk-(ucell *)dict); + pos=l/BITS; + bit=l&~(-BITS); + if (reloc_table[pos]&target_ucell(1UL<last)); + + return -1; +} diff --git a/kernel/forth.c b/kernel/forth.c new file mode 100644 index 0000000..8a147a0 --- /dev/null +++ b/kernel/forth.c @@ -0,0 +1,917 @@ +/* tag: C implementation of all forth primitives + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + + +/* + * dup ( x -- x x ) + */ + +static void fdup(void) +{ + const cell tmp = GETTOS(); + PUSH(tmp); +} + + +/* + * 2dup ( x1 x2 -- x1 x2 x1 x2 ) + */ + +static void twodup(void) +{ + cell tmp = GETITEM(1); + PUSH(tmp); + tmp = GETITEM(1); + PUSH(tmp); +} + + +/* + * ?dup ( x -- 0 | x x ) + */ + +static void isdup(void) +{ + const cell tmp = GETTOS(); + if (tmp) + PUSH(tmp); +} + + +/* + * over ( x y -- x y x ) + */ + +static void over(void) +{ + const cell tmp = GETITEM(1); + PUSH(tmp); +} + + +/* + * 2over ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) + */ + +static void twoover(void) +{ + const cell tmp = GETITEM(3); + const cell tmp2 = GETITEM(2); + PUSH(tmp); + PUSH(tmp2); +} + +/* + * pick ( xu ... x1 x0 u -- xu ... x1 x0 xu ) + */ + +static void pick(void) +{ + const cell u = POP(); + if (dstackcnt >= u) { + ucell tmp = dstack[dstackcnt - u]; + PUSH(tmp); + } else { + /* underrun */ + } +} + + +/* + * drop ( x -- ) + */ + +static void drop(void) +{ + POP(); +} + +/* + * 2drop ( x1 x2 -- ) + */ + +static void twodrop(void) +{ + POP(); + POP(); +} + + +/* + * nip ( x1 x2 -- x2 ) + */ + +static void nip(void) +{ + const cell tmp = POP(); + POP(); + PUSH(tmp); +} + + +/* + * roll ( xu ... x1 x0 u -- xu-1... x1 x0 xu ) + */ + +static void roll(void) +{ + const cell u = POP(); + if (dstackcnt >= u) { + int i; + const cell xu = dstack[dstackcnt - u]; + for (i = dstackcnt - u; i < dstackcnt; i++) { + dstack[i] = dstack[i + 1]; + } + dstack[dstackcnt] = xu; + } else { + /* Stack underrun */ + } +} + + +/* + * rot ( x1 x2 x3 -- x2 x3 x1 ) + */ + +static void rot(void) +{ + const cell tmp = POP(); + const cell tmp2 = POP(); + const cell tmp3 = POP(); + PUSH(tmp2); + PUSH(tmp); + PUSH(tmp3); +} + + +/* + * -rot ( x1 x2 x3 -- x3 x1 x2 ) + */ + +static void minusrot(void) +{ + const cell tmp = POP(); + const cell tmp2 = POP(); + const cell tmp3 = POP(); + PUSH(tmp); + PUSH(tmp3); + PUSH(tmp2); +} + + +/* + * swap ( x1 x2 -- x2 x1 ) + */ + +static void swap(void) +{ + const cell tmp = POP(); + const cell tmp2 = POP(); + PUSH(tmp); + PUSH(tmp2); +} + + +/* + * 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 ) + */ + +static void twoswap(void) +{ + const cell tmp = POP(); + const cell tmp2 = POP(); + const cell tmp3 = POP(); + const cell tmp4 = POP(); + PUSH(tmp2); + PUSH(tmp); + PUSH(tmp4); + PUSH(tmp3); +} + + +/* + * >r ( x -- ) (R: -- x ) + */ + +static void tor(void) +{ + ucell tmp = POP(); +#ifdef CONFIG_DEBUG_RSTACK + printk(" >R: %x\n", tmp); +#endif + PUSHR(tmp); +} + + +/* + * r> ( -- x ) (R: x -- ) + */ + +static void rto(void) +{ + ucell tmp = POPR(); +#ifdef CONFIG_DEBUG_RSTACK + printk(" R>: %x\n", tmp); +#endif + PUSH(tmp); +} + + +/* + * r@ ( -- x ) (R: x -- x ) + */ + +static void rfetch(void) +{ + PUSH(GETTORS()); +} + + +/* + * depth ( -- u ) + */ + +static void depth(void) +{ + const cell tmp = dstackcnt; + PUSH(tmp); +} + + +/* + * depth! ( ... u -- x1 x2 .. xu ) + */ + +static void depthwrite(void) +{ + ucell tmp = POP(); + dstackcnt = tmp; +} + + +/* + * rdepth ( -- u ) + */ + +static void rdepth(void) +{ + const cell tmp = rstackcnt; + PUSH(tmp); +} + + +/* + * rdepth! ( u -- ) ( R: ... -- x1 x2 .. xu ) + */ + +static void rdepthwrite(void) +{ + ucell tmp = POP(); + rstackcnt = tmp; +} + + +/* + * + ( nu1 nu2 -- sum ) + */ + +static void plus(void) +{ + cell tmp = POP() + POP(); + PUSH(tmp); +} + + +/* + * - ( nu1 nu2 -- diff ) + */ + +static void minus(void) +{ + const cell nu2 = POP(); + const cell nu1 = POP(); + PUSH(nu1 - nu2); +} + + +/* + * * ( nu1 nu2 -- prod ) + */ + +static void mult(void) +{ + const cell nu2 = POP(); + const cell nu1 = POP(); + PUSH(nu1 * nu2); +} + + +/* + * u* ( u1 u2 -- prod ) + */ + +static void umult(void) +{ + const ucell tmp = (ucell) POP() * (ucell) POP(); + PUSH(tmp); +} + + +/* + * mu/mod ( n1 n2 -- rem quot.l quot.h ) + */ + +static void mudivmod(void) +{ + const ucell b = POP(); + const ducell a = DPOP(); + PUSH(a % b); + DPUSH(a / b); +} + + +/* + * abs ( n -- u ) + */ + +static void forthabs(void) +{ + const cell tmp = GETTOS(); + if (tmp < 0) { + POP(); + PUSH(-tmp); + } +} + + +/* + * negate ( n1 -- n2 ) + */ + +static void negate(void) +{ + const cell tmp = POP(); + PUSH(-tmp); +} + + +/* + * max ( n1 n2 -- n1|n2 ) + */ + +static void max(void) +{ + const cell tmp = POP(); + const cell tmp2 = POP(); + PUSH((tmp > tmp2) ? tmp : tmp2); +} + + +/* + * min ( n1 n2 -- n1|n2 ) + */ + +static void min(void) +{ + const cell tmp = POP(); + const cell tmp2 = POP(); + PUSH((tmp < tmp2) ? tmp : tmp2); +} + + +/* + * lshift ( x1 u -- x2 ) + */ + +static void lshift(void) +{ + const ucell u = POP(); + const ucell x1 = POP(); + PUSH(x1 << u); +} + + +/* + * rshift ( x1 u -- x2 ) + */ + +static void rshift(void) +{ + const ucell u = POP(); + const ucell x1 = POP(); + PUSH(x1 >> u); +} + + +/* + * >>a ( x1 u -- x2 ) ?? + */ + +static void rshifta(void) +{ + const cell u = POP(); + const cell x1 = POP(); + PUSH(x1 >> u); +} + + +/* + * and ( x1 x2 -- x3 ) + */ + +static void and(void) +{ + const cell x1 = POP(); + const cell x2 = POP(); + PUSH(x1 & x2); +} + + +/* + * or ( x1 x2 -- x3 ) + */ + +static void or(void) +{ + const cell x1 = POP(); + const cell x2 = POP(); + PUSH(x1 | x2); +} + + +/* + * xor ( x1 x2 -- x3 ) + */ + +static void xor(void) +{ + const cell x1 = POP(); + const cell x2 = POP(); + PUSH(x1 ^ x2); +} + + +/* + * invert ( x1 -- x2 ) + */ + +static void invert(void) +{ + const cell x1 = POP(); + PUSH(x1 ^ -1); +} + + +/* + * d+ ( d1 d2 -- d.sum ) + */ + +static void dplus(void) +{ + const dcell d2 = DPOP(); + const dcell d1 = DPOP(); + DPUSH(d1 + d2); +} + + +/* + * d- ( d1 d2 -- d.diff ) + */ + +static void dminus(void) +{ + const dcell d2 = DPOP(); + const dcell d1 = DPOP(); + DPUSH(d1 - d2); +} + + +/* + * m* ( ?? -- ) + */ + +static void mmult(void) +{ + const cell u2 = POP(); + const cell u1 = POP(); + DPUSH((dcell) u1 * u2); +} + + +/* + * um* ( u1 u2 -- d.prod ) + */ + +static void ummult(void) +{ + const ucell u2 = POP(); + const ucell u1 = POP(); + DPUSH((ducell) u1 * u2); +} + + +/* + * @ ( a-addr -- x ) + */ + +static void fetch(void) +{ + const ucell *aaddr = (ucell *)cell2pointer(POP()); + PUSH(read_ucell(aaddr)); +} + + +/* + * c@ ( addr -- byte ) + */ + +static void cfetch(void) +{ + const u8 *aaddr = (u8 *)cell2pointer(POP()); + PUSH(read_byte(aaddr)); +} + + +/* + * w@ ( waddr -- w ) + */ + +static void wfetch(void) +{ + const u16 *aaddr = (u16 *)cell2pointer(POP()); + PUSH(read_word(aaddr)); +} + + +/* + * l@ ( qaddr -- quad ) + */ + +static void lfetch(void) +{ + const u32 *aaddr = (u32 *)cell2pointer(POP()); + PUSH(read_long(aaddr)); +} + + +/* + * ! ( x a-addr -- ) + */ + +static void store(void) +{ + const ucell *aaddr = (ucell *)cell2pointer(POP()); + const ucell x = POP(); +#ifdef CONFIG_DEBUG_INTERNAL + printf("!: %lx : %lx -> %lx\n", aaddr, read_ucell(aaddr), x); +#endif + write_ucell(aaddr,x); +} + + +/* + * +! ( nu a-addr -- ) + */ + +static void plusstore(void) +{ + const ucell *aaddr = (ucell *)cell2pointer(POP()); + const cell nu = POP(); + write_cell(aaddr,read_cell(aaddr)+nu); +} + + +/* + * c! ( byte addr -- ) + */ + +static void cstore(void) +{ + const u8 *aaddr = (u8 *)cell2pointer(POP()); + const ucell byte = POP(); +#ifdef CONFIG_DEBUG_INTERNAL + printk("c!: %x = %x\n", aaddr, byte); +#endif + write_byte(aaddr, byte); +} + + +/* + * w! ( w waddr -- ) + */ + +static void wstore(void) +{ + const u16 *aaddr = (u16 *)cell2pointer(POP()); + const ucell word = POP(); + write_word(aaddr, word); +} + + +/* + * l! ( quad qaddr -- ) + */ + +static void lstore(void) +{ + const u32 *aaddr = (u32 *)cell2pointer(POP()); + const ucell longval = POP(); + write_long(aaddr, longval); +} + + +/* + * = ( x1 x2 -- equal? ) + */ + +static void equals(void) +{ + cell tmp = (POP() == POP()); + PUSH(-tmp); +} + + +/* + * > ( n1 n2 -- greater? ) + */ + +static void greater(void) +{ + cell tmp = ((cell) POP() < (cell) POP()); + PUSH(-tmp); +} + + +/* + * < ( n1 n2 -- less? ) + */ + +static void less(void) +{ + cell tmp = ((cell) POP() > (cell) POP()); + PUSH(-tmp); +} + + +/* + * u> ( u1 u2 -- unsigned-greater? ) + */ + +static void ugreater(void) +{ + cell tmp = ((ucell) POP() < (ucell) POP()); + PUSH(-tmp); +} + + +/* + * u< ( u1 u2 -- unsigned-less? ) + */ + +static void uless(void) +{ + cell tmp = ((ucell) POP() > (ucell) POP()); + PUSH(-tmp); +} + + +/* + * sp@ ( -- stack-pointer ) + */ + +static void spfetch(void) +{ + // FIXME this can only work if the stack pointer + // is within range. + ucell tmp = pointer2cell(&(dstack[dstackcnt])); + PUSH(tmp); +} + + +/* + * move ( src-addr dest-addr len -- ) + */ + +static void fmove(void) +{ + ucell count = POP(); + void *dest = (void *)cell2pointer(POP()); + const void *src = (const void *)cell2pointer(POP()); + memmove(dest, src, count); +} + + +/* + * fill ( addr len byte -- ) + */ + +static void ffill(void) +{ + ucell value = POP(); + ucell count = POP(); + void *src = (void *)cell2pointer(POP()); + memset(src, value, count); +} + + +/* + * unaligned-w@ ( addr -- w ) + */ + +static void unalignedwordread(void) +{ + unsigned char *addr = (unsigned char *) cell2pointer(POP()); + PUSH(unaligned_read_word(addr)); +} + + +/* + * unaligned-w! ( w addr -- ) + */ + +static void unalignedwordwrite(void) +{ + unsigned char *addr = (unsigned char *) cell2pointer(POP()); + ucell w = POP(); + unaligned_write_word(addr, w); +} + + +/* + * unaligned-l@ ( addr -- quad ) + */ + +static void unalignedlongread(void) +{ + unsigned char *addr = (unsigned char *) cell2pointer(POP()); + PUSH(unaligned_read_long(addr)); +} + + +/* + * unaligned-l! ( quad addr -- ) + */ + +static void unalignedlongwrite(void) +{ + unsigned char *addr = (unsigned char *) cell2pointer(POP()); + ucell l = POP(); + unaligned_write_long(addr, l); +} + +/* + * here ( -- dictionary-pointer ) + */ + +static void here(void) +{ + PUSH(pointer2cell(dict) + dicthead); +#ifdef CONFIG_DEBUG_INTERNAL + printk("here: %x\n", pointer2cell(dict) + dicthead); +#endif +} + +/* + * here! ( new-dict-pointer -- ) + */ + +static void herewrite(void) +{ + ucell tmp = POP(); /* converted pointer */ + dicthead = tmp - pointer2cell(dict); +#ifdef CONFIG_DEBUG_INTERNAL + printk("here!: new value: %x\n", tmp); +#endif +} + + +/* + * emit ( char -- ) + */ + +static void emit(void) +{ + cell tmp = POP(); +#ifndef FCOMPILER + putchar(tmp); +#endif +} + + +/* + * key? ( -- pressed? ) + */ + +static void iskey(void) +{ + PUSH((cell) availchar()); +} + + +/* + * key ( -- char ) + */ + +static void key(void) +{ + while (!availchar()); +#ifdef FCOMPILER + PUSH(get_inputbyte()); +#else + PUSH(getchar()); +#endif +} + + +/* + * ioc@ ( reg -- val ) + */ + +static void iocfetch(void) +{ + cell reg = POP(); + PUSH(inb(reg)); +} + + +/* + * iow@ ( reg -- val ) + */ + +static void iowfetch(void) +{ + cell reg = POP(); + PUSH(inw(reg)); +} + +/* + * iol@ ( reg -- val ) + */ + +static void iolfetch(void) +{ + cell reg = POP(); + PUSH(inl(reg)); +} + + +/* + * ioc! ( val reg -- ) + */ + +static void iocstore(void) +{ + cell reg = POP(); + cell val = POP(); + + outb(reg, val); +} + + +/* + * iow! ( val reg -- ) + */ + +static void iowstore(void) +{ + cell reg = POP(); + cell val = POP(); + + outw(reg, val); +} + + +/* + * iol! ( val reg -- ) + */ + +static void iolstore(void) +{ + ucell reg = POP(); + ucell val = POP(); + + outl(reg, val); +} + +/* + * i ( -- i ) + */ + +static void loop_i(void) +{ + PUSH(rstack[rstackcnt]); +} + +/* + * j ( -- i ) + */ + +static void loop_j(void) +{ + PUSH(rstack[rstackcnt - 2]); +} diff --git a/kernel/include/dict.h b/kernel/include/dict.h new file mode 100644 index 0000000..9f5d215 --- /dev/null +++ b/kernel/include/dict.h @@ -0,0 +1,48 @@ +/* tag: dict management headers + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#ifndef __DICT_H +#define __DICT_H + +#define DICTID "OpenBIOS" + +#define DOCOL 1 +#define DOLIT 2 +#define DOCON 3 +#define DOVAR 4 +#define DODFR 5 +#define DODOES 6 + + +/* The header is 28/32 bytes on 32/64bit platforms */ + +typedef struct dictionary_header { + char signature[8]; + u8 version; + u8 cellsize; + u8 endianess; + u8 compression; + u8 relocation; + u8 reserved[3]; + u32 checksum; + u32 length; + ucell last; +} __attribute__((packed)) dictionary_header_t; + +ucell lfa2nfa(ucell ilfa); +ucell load_dictionary(const char *data, ucell len); +void dump_header(dictionary_header_t *header); + +/* program counter */ +extern ucell PC; + +extern unsigned char *dict; +extern cell dicthead; +extern ucell *last; + +#endif diff --git a/kernel/internal.c b/kernel/internal.c new file mode 100644 index 0000000..ea7bf92 --- /dev/null +++ b/kernel/internal.c @@ -0,0 +1,365 @@ +/* tag: internal words, inner interpreter and such + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +/* + * execution works as follows: + * - PC is pushed on return stack + * - PC is set to new CFA + * - address pointed by CFA is executed by CPU + */ + +extern void *words[]; +ucell PC; +volatile int runforth = 0; + +#ifdef FCOMPILER +extern ucell *trampoline; +#else +/* instead of pointing to an explicit 0 variable we + * point behind the pointer. + */ +static ucell t[] = { DOCOL, 0, (ucell)(t+3), 0 }; +ucell *trampoline = t; +#endif + +#ifndef CONFIG_DEBUG_INTERPRETER +#define dbg_interp_printk( a... ) do { } while(0) +#else +#define dbg_interp_printk( a... ) printk( a ) +#endif + +#ifndef CONFIG_DEBUG_INTERNAL +#define dbg_internal_printk( a... ) do { } while(0) +#else +#define dbg_internal_printk( a... ) printk( a ) +#endif + + +static inline void processxt(ucell xt) +{ + void (*tokenp) (void); + + dbg_interp_printk("processxt: pc=%x, xt=%x\n", PC, xt); + tokenp = words[xt]; + tokenp(); +} + +static void docol(void) +{ /* DOCOL */ + PUSHR(PC); + PC = read_ucell(cell2pointer(PC)); + + dbg_interp_printk("docol: %s\n", cell2pointer( lfa2nfa(PC - sizeof(cell)) )); +} + +static void semis(void) +{ + PC = POPR(); +} + +static inline void next(void) +{ + PC += sizeof(ucell); + + dbg_interp_printk("next: PC is now %x\n", PC); + processxt(read_ucell(cell2pointer(read_ucell(cell2pointer(PC))))); +} + +int enterforth(xt_t xt) +{ + ucell *_cfa = (ucell*)cell2pointer(xt); + ucell tmp; + + if (read_ucell(_cfa) != DOCOL ) { + trampoline[1] = target_ucell(xt); + _cfa = trampoline; + } + + if (rstackcnt < 0) + rstackcnt = 0; + + tmp = rstackcnt; + runforth = 1; + + PUSHR(PC); + PC = pointer2cell(_cfa); + while (rstackcnt > tmp && runforth) { + dbg_interp_printk("enterforth: NEXT\n"); + next(); + } + +#if 0 + /* return true if we took an exception. The caller should normally + * handle exceptions by returning immediately since the throw + * is supposed to abort the execution of this C-code too. + */ + + if( rstackcnt != tmp ) + printk("EXCEPTION DETECTED!\n"); +#endif + return rstackcnt != tmp; +} + +/* called inline thus a slightly different behaviour */ +static void lit(void) +{ /* LIT */ + PC += sizeof(cell); + PUSH(read_ucell(cell2pointer(PC))); + dbg_interp_printk("lit: %x\n", read_ucell(cell2pointer(PC))); +} + +static void docon(void) +{ /* DOCON */ + ucell tmp = read_cell(cell2pointer(read_ucell(cell2pointer(PC)) + sizeof(ucell))); + PUSH(tmp); + dbg_interp_printk("docon: PC=%x, value=%x\n", PC, tmp); +} + +static void dovar(void) +{ /* DOVAR */ + ucell tmp = read_cell(cell2pointer(PC)) + sizeof(ucell); + PUSH(tmp); /* returns address to variable */ + dbg_interp_printk("dovar: PC: %x, %x\n", PC, tmp); +} + +static void dobranch(void) +{ /* unconditional branch */ + PC += sizeof(cell); + PC += read_cell(cell2pointer(PC)); +} + +static void docbranch(void) +{ /* conditional branch */ + + PC += sizeof(cell); + if (POP()) { + dbg_internal_printk(" ?branch: end loop\n"); + } else { + dbg_internal_printk(" ?branch: follow branch\n"); + PC += read_cell(cell2pointer(PC)); + } +} + + +static void execute(void) +{ /* EXECUTE */ + ucell address = POP(); + dbg_interp_printk("execute: %x\n", address); + + PUSHR(PC); + trampoline[1] = target_ucell(address); + PC = pointer2cell(trampoline); +} + +/* + * call ( ... function-ptr -- ??? ) + */ +static void call(void) +{ +#ifdef FCOMPILER + printk("Sorry. Usage of Forth2C binding is forbidden during bootstrap.\n"); + exit(1); +#else + void (*funcptr) (void); + funcptr=(void *)POP(); + dbg_interp_printk("call: %x", funcptr); + funcptr(); +#endif +} + +/* + * sys-debug ( errno -- ) + */ + +static void sysdebug(void) +{ + cell errorno=POP(); + exception(errorno); +} + +static void dodoes(void) +{ /* DODOES */ + ucell data = read_ucell(cell2pointer(PC)) + (2 * sizeof(ucell)); + ucell word = read_ucell(cell2pointer(read_ucell(cell2pointer(PC)) + sizeof(ucell))); + + dbg_interp_printk("DODOES data=%x word=%x\n", data, word); + + PUSH(data); + PUSH(word); + + execute(); +} + +static void dodefer(void) +{ + docol(); +} + +static void dodo(void) +{ + cell startval, endval; + startval = POP(); + endval = POP(); + + PUSHR(endval); + PUSHR(startval); +} + +static void doisdo(void) +{ + cell startval, endval, offset; + + startval = POP(); + endval = POP(); + + PC += sizeof(cell); + + if (startval == endval) { + offset = read_cell(cell2pointer(PC)); + PC += offset; + } else { + PUSHR(endval); + PUSHR(startval); + } +} + +static void doloop(void) +{ + cell offset, startval, endval; + + startval = POPR() + 1; + endval = POPR(); + + PC += sizeof(cell); + + if (startval < endval) { + offset = read_cell(cell2pointer(PC)); + PC += offset; + PUSHR(endval); + PUSHR(startval); + } + +} + +static void doplusloop(void) +{ + ucell high, low; + cell increment, startval, endval, offset; + + increment = POP(); + + startval = POPR(); + endval = POPR(); + + low = (ucell) startval; + startval += increment; + + PC += sizeof(cell); + + if (increment >= 0) { + high = (ucell) startval; + } else { + high = low; + low = (ucell) startval; + } + + if (endval - (low + 1) >= high - low) { + offset = read_cell(cell2pointer(PC)); + PC += offset; + + PUSHR(endval); + PUSHR(startval); + } +} + +/* + * instance handling CFAs + */ +#ifndef FCOMPILER +static ucell get_myself(void) +{ + static ucell **myself = 0; + if( !myself ) + myself = (ucell**)findword("my-self") + 1; + return (*myself && **myself) ? (ucell)**myself : 0; +} + +static void doivar(void) +{ + ucell r, *p = (ucell *)(*(ucell *) PC + sizeof(ucell)); + ucell ibase = get_myself(); + + dbg_interp_printk("ivar, offset: %d size: %d (ibase %d)\n", p[0], p[1], ibase ); + + r = ibase ? ibase + p[0] : (ucell)&p[2]; + PUSH( r ); +} + +static void doival(void) +{ + ucell r, *p = (ucell *)(*(ucell *) PC + sizeof(ucell)); + ucell ibase = get_myself(); + + dbg_interp_printk("ivar, offset: %d size: %d\n", p[0], p[1] ); + + r = ibase ? ibase + p[0] : (ucell)&p[2]; + PUSH( *(ucell *)r ); +} + +static void doidefer(void) +{ + ucell *p = (ucell *)(*(ucell *) PC + sizeof(ucell)); + ucell ibase = get_myself(); + + dbg_interp_printk("doidefer, offset: %d size: %d\n", p[0], p[1] ); + + PUSHR(PC); + PC = ibase ? ibase + p[0] : (ucell)&p[2]; + PC -= sizeof(ucell); +} +#else +static void noinstances(void) +{ + printk("Opening devices is not supported during bootstrap. Sorry.\n"); + exit(1); +} +#define doivar noinstances +#define doival noinstances +#define doidefer noinstances +#endif +/* + * $include / $encode-file + */ + +#ifdef FCOMPILER +static void +string_relay( void (*func)(const char *) ) +{ + int len = POP(); + char *name, *p = (char*)cell2pointer(POP()); + name = malloc( len + 1 ); + memcpy( name, p, len ); + name[len]=0; + (*func)( name ); + free( name ); +} +#else +#define string_relay( dummy ) do { DROP(); DROP(); } while(0) +#endif + +static void +do_include( void ) +{ + string_relay( &include_file ); +} + +static void +do_encode_file( void ) +{ + string_relay( &encode_file ); +} diff --git a/kernel/primitives.c b/kernel/primitives.c new file mode 100644 index 0000000..1cd8f7f --- /dev/null +++ b/kernel/primitives.c @@ -0,0 +1,148 @@ +/* tag: the main file which includes all the prim code headers + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * see the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "openbios/config.h" +#include "openbios/sysinclude.h" +#include "openbios/stack.h" +#include "openbios/kernel.h" +#include "dict.h" + +/* + * cross platform abstraction + */ + +#include "cross.h" + +/* + * Code Field Address (CFA) definitions (DOCOL and the like) + */ + +#include "internal.c" + +/* include forth primitives needed to set up + * all the words described in IEEE1275-1994. + */ + +#include "forth.c" + +/* words[] is a function array of all native code functions in used by + * the dictionary, i.e. CFAs and primitives. + * Any change here needs a matching change in the primitive word's + * name list that is kept for bootstrapping in arch/unix/unix.c + * + * NOTE: THIS LIST SHALL NOT CHANGE (EXCEPT MANDATORY ADDITIONS AT + * THE END). ANY OTHER CHANGE WILL BREAK COMPATIBILITY TO OLDER + * BINARY DICTIONARIES. + */ +void *words[] = { + + /* + * CFAs and special words + */ + semis, + docol, + lit, + docon, + dovar, + dodefer, + dodoes, + dodo, + doisdo, + doloop, + doplusloop, + doival, + doivar, + doidefer, + + /* + * primitives + */ + fdup, /* dup */ + twodup, /* 2dup */ + isdup, /* ?dup */ + over, /* over */ + twoover, /* 2over */ + pick, /* pick */ + drop, /* drop */ + twodrop, /* 2drop */ + nip, /* nip */ + roll, /* roll */ + rot, /* rot */ + minusrot, /* -rot */ + swap, /* swap */ + twoswap, /* 2swap */ + tor, /* >r */ + rto, /* r> */ + rfetch, /* r@ */ + depth, /* depth */ + depthwrite, /* depth! */ + rdepth, /* rdepth */ + rdepthwrite, /* rdepth! */ + plus, /* + */ + minus, /* - */ + mult, /* * */ + umult, /* u* */ + mudivmod, /* mu/mod */ + forthabs, /* abs */ + negate, /* negate */ + max, /* max */ + min, /* min */ + lshift, /* lshift */ + rshift, /* rshift */ + rshifta, /* >>a */ + and, /* and */ + or, /* or */ + xor, /* xor */ + invert, /* invert */ + dplus, /* d+ */ + dminus, /* d- */ + mmult, /* m* */ + ummult, /* um* */ + fetch, /* @ */ + cfetch, /* c@ */ + wfetch, /* w@ */ + lfetch, /* l@ */ + store, /* ! */ + plusstore, /* +! */ + cstore, /* c! */ + wstore, /* w! */ + lstore, /* l! */ + equals, /* = */ + greater, /* > */ + less, /* < */ + ugreater, /* u> */ + uless, /* u< */ + spfetch, /* sp@ */ + fmove, /* move */ + ffill, /* fill */ + emit, /* emit */ + iskey, /* key? */ + key, /* key */ + execute, /* execute */ + here, /* here */ + herewrite, /* here! */ + dobranch, /* dobranch */ + docbranch, /* do?branch */ + unalignedwordread, /* unaligned-w@ */ + unalignedwordwrite, /* unaligned-w! */ + unalignedlongread, /* unaligned-w@ */ + unalignedlongwrite, /* unaligned-w! */ + iocfetch, /* ioc@ */ + iowfetch, /* iow@ */ + iolfetch, /* iol@ */ + iocstore, /* ioc! */ + iowstore, /* iow! */ + iolstore, /* iol! */ + loop_i, /* i */ + loop_j, /* j */ + call, /* call */ + sysdebug, /* sys-debug */ + do_include, /* $include */ + do_encode_file, /* $encode-file */ +}; + diff --git a/kernel/stack.c b/kernel/stack.c new file mode 100644 index 0000000..043a42e --- /dev/null +++ b/kernel/stack.c @@ -0,0 +1,42 @@ +/* tag: defines the stacks, program counter and ways to access those + * + * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + + +#include "openbios/config.h" +#include "openbios/stack.h" + +#define dstacksize 512 +int dstackcnt = 0; +cell dstack[dstacksize]; + +#define rstacksize 512 +int rstackcnt = 0; +cell rstack[rstacksize]; + +#if defined(CONFIG_DEBUG_DSTACK) || defined(FCOMPILER) +void printdstack(void) +{ + int i; + printk("dstack:"); + for (i = 0; i <= dstackcnt; i++) { + printk(" 0x%x", dstack[i]); + } + printk("\n"); +} +#endif +#if defined(CONFIG_DEBUG_RSTACK) || defined(FCOMPILER) +void printrstack(void) +{ + int i; + printk("rstack:"); + for (i = 0; i <= rstackcnt; i++) { + printk(" 0x%x", rstack[i]); + } + printk("\n"); +} +#endif diff --git a/libc/build.xml b/libc/build.xml new file mode 100644 index 0000000..cb2b560 --- /dev/null +++ b/libc/build.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/libc/ctype.c b/libc/ctype.c new file mode 100644 index 0000000..c30b9fe --- /dev/null +++ b/libc/ctype.c @@ -0,0 +1,36 @@ +/* + * linux/lib/ctype.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include "openbios/config.h" +#include "libc/string.h" + +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + + diff --git a/libc/diskio.c b/libc/diskio.c new file mode 100644 index 0000000..0d499a0 --- /dev/null +++ b/libc/diskio.c @@ -0,0 +1,215 @@ +/* + * Creation Date: <2003/12/07 19:36:00 samuel> + * Time-stamp: <2004/01/07 19:28:43 samuel> + * + * + * + * I/O wrappers + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/diskio.h" + +typedef struct { + ihandle_t ih; + int do_close; + xt_t read_xt; + xt_t seek_xt; + + xt_t reopen_xt; + xt_t tell_xt; + xt_t get_path_xt; + xt_t get_fstype_xt; + xt_t open_nwrom_xt; + xt_t volume_name_xt; +} priv_fd_t; + +#define MAX_FD 32 +static priv_fd_t *file_descriptors[MAX_FD]; + +static int +lookup_xt( ihandle_t ih, const char *method, xt_t *xt ) +{ + if( *xt ) + return 0; + *xt = find_ih_method( method, ih ); + return (*xt) ? 0:1; +} + +int +open_ih( ihandle_t ih ) +{ + xt_t read_xt=0, seek_xt=0; + priv_fd_t *fdp; + int fd; + + if( !ih || lookup_xt(ih, "read", &read_xt) ) + return -1; + if( lookup_xt(ih, "seek", &seek_xt) ) + return -1; + + for (fd=0; fdih = ih; + fdp->read_xt = read_xt; + fdp->seek_xt = seek_xt; + fdp->do_close = 0; + + file_descriptors[fd]=fdp; + return fd; +} + +int +open_io( const char *spec ) +{ + int fd; + ihandle_t ih = open_dev( spec ); + priv_fd_t *fdp; + + if( !ih ) + return -1; + + if( (fd=open_ih(ih)) == -1 ) { + close_dev( ih ); + return -1; + } + + fdp = file_descriptors[fd]; + fdp->do_close = 1; + + return fd; +} + +int +reopen( int fd, const char *filename ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + int ret; + + if( lookup_xt(fdp->ih, "reopen", &fdp->reopen_xt) ) + return -1; + + push_str( filename ); + call_package( fdp->reopen_xt, fdp->ih ); + ret = (POP() == -1)? 0:-1; + + return ret; +} + +int +reopen_nwrom( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + + if( lookup_xt(fdp->ih, "open-nwrom", &fdp->open_nwrom_xt) ) + return -1; + call_package( fdp->open_nwrom_xt, fdp->ih ); + return (POP() == -1)? 0:-1; +} + +ihandle_t +get_ih_from_fd( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + return fdp->ih; +} + +const char * +get_file_path( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + if( lookup_xt(fdp->ih, "get-path", &fdp->get_path_xt) ) + return NULL; + call_package( fdp->get_path_xt, fdp->ih ); + return (char*)POP(); +} + +const char * +get_volume_name( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + if( lookup_xt(fdp->ih, "volume-name", &fdp->volume_name_xt) ) + return NULL; + call_package( fdp->volume_name_xt, fdp->ih ); + return (char*)POP(); +} + +const char * +get_fstype( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + if( lookup_xt(fdp->ih, "get-fstype", &fdp->get_fstype_xt) ) + return NULL; + call_package( fdp->get_fstype_xt, fdp->ih ); + return (char*)POP(); +} + +int +read_io( int fd, void *buf, size_t cnt ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + ucell ret; + + PUSH( (ucell)buf ); + PUSH( cnt ); + call_package( fdp->read_xt, fdp->ih ); + ret = POP(); + + if( !ret && cnt ) + ret = -1; + return ret; +} + +int +seek_io( int fd, llong offs ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + + DPUSH( offs ); + call_package( fdp->seek_xt, fdp->ih ); + return ((POP() >= 0)? 0 : -1); +} + +llong +tell( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + llong offs; + + if( lookup_xt(fdp->ih, "tell", &fdp->tell_xt) ) + return -1; + call_package( fdp->tell_xt, fdp->ih ); + offs = DPOP(); + return offs; +} + +int +close_io( int fd ) +{ + priv_fd_t *fdp = file_descriptors[fd]; + + if( fdp->do_close ) + close_dev( fdp->ih ); + free( fdp ); + + file_descriptors[fd]=NULL; + + return 0; +} diff --git a/libc/extra.c b/libc/extra.c new file mode 100644 index 0000000..4995563 --- /dev/null +++ b/libc/extra.c @@ -0,0 +1,26 @@ +/* + * Creation Date: <2003/10/18 13:52:32 samuel> + * Time-stamp: <2003/10/18 13:54:24 samuel> + * + * + * + * Libc extras + * + * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "libc/string.h" + +/* strncpy without 0-pad */ +char * +strncpy_nopad( char *dest, const char *src, size_t n ) +{ + int len = MIN( n, strlen(src)+1 ); + return memcpy( dest, src, len ); +} diff --git a/libc/misc.c b/libc/misc.c new file mode 100644 index 0000000..236107c --- /dev/null +++ b/libc/misc.c @@ -0,0 +1,77 @@ +/* + * Creation Date: <2002/10/19 21:05:07 samuel> + * Time-stamp: <2002/10/22 22:29:18 samuel> + * + * + * + * Miscellaneous + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "libc/string.h" + +int errno; + +void +qsort( void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void*) ) +{ + int worked, i, j; + + /* even more inefficient than the glibc variant :-) */ + do { + char *p = base; + worked = 0; + for( i=0; i 0 ) { + worked = 1; + for( j=0; j= base || n < 0 ) + break; + sum *= base; + sum += n; + } + if( endptr ) + *endptr = (char*)nptr; + + return sum * sign; +} diff --git a/libc/string.c b/libc/string.c new file mode 100644 index 0000000..ad1cc99 --- /dev/null +++ b/libc/string.c @@ -0,0 +1,515 @@ +/* + * linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * stupid library routines.. The optimized versions should generally be found + * as inline code in + * + * These are buggy as well.. + * + * * Fri Jun 25 1999, Ingo Oeser + * - Added strsep() which will replace strtok() soon (because strsep() is + * reentrant and should be faster). Use only strsep() in new code, please. + */ + +#include "openbios/config.h" +#include "libc/string.h" +#include "libc/stdlib.h" + +/** + * strnicmp - Case insensitive, length-limited string comparison + * @s1: One string + * @s2: The other string + * @len: the maximum number of characters to compare + */ +int strnicmp(const char *s1, const char *s2, size_t len) +{ + /* Yes, Virginia, it had better be unsigned */ + unsigned char c1, c2; + + c1 = 0; c2 = 0; + if (len) { + do { + c1 = *s1; c2 = *s2; + s1++; s2++; + if (!c1) + break; + if (!c2) + break; + if (c1 == c2) + continue; + c1 = tolower(c1); + c2 = tolower(c2); + if (c1 != c2) + break; + } while (--len); + } + return (int)c1 - (int)c2; +} + +char * ___strtok; + +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ +char * strcpy(char * dest,const char *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + /* nothing */; + return tmp; +} + +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ +char * strncpy(char * dest,const char *src,size_t count) +{ + char *tmp = dest; + + while (count-- && (*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} + +/** + * strcat - Append one %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + */ +char * strcat(char * dest, const char * src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} + +/** + * strncat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @count: The maximum numbers of bytes to copy + * + * Note that in contrast to strncpy, strncat ensures the result is + * terminated. + */ +char * strncat(char *dest, const char *src, size_t count) +{ + char *tmp = dest; + + if (count) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) { + *dest = '\0'; + break; + } + } + } + + return tmp; +} + +/** + * strcmp - Compare two strings + * @cs: One string + * @ct: Another string + */ +int strcmp(const char * cs,const char * ct) +{ + register signed char __res; + + while (1) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + } + + return __res; +} + +/** + * strncmp - Compare two length-limited strings + * @cs: One string + * @ct: Another string + * @count: The maximum number of bytes to compare + */ +int strncmp(const char * cs,const char * ct,size_t count) +{ + register signed char __res = 0; + + while (count) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} + + +/** + * strchr - Find the first occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char * strchr(const char * s, int c) +{ + for(; *s != (char) c; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} + +/** + * strrchr - Find the last occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char * strrchr(const char * s, int c) +{ + const char *p = s + strlen(s); + do { + if (*p == (char)c) + return (char *)p; + } while (--p >= s); + return NULL; +} + +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +/** + * strspn - Calculate the length of the initial substring of @s which only + * contain letters in @accept + * @s: The string to be searched + * @accept: The string to search for + */ +size_t strspn(const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) { + for (a = accept; *a != '\0'; ++a) { + if (*p == *a) + break; + } + if (*a == '\0') + return count; + ++count; + } + + return count; +} + +/** + * strpbrk - Find the first occurrence of a set of characters + * @cs: The string to be searched + * @ct: The characters to search for + */ +char * strpbrk(const char * cs,const char * ct) +{ + const char *sc1,*sc2; + + for( sc1 = cs; *sc1 != '\0'; ++sc1) { + for( sc2 = ct; *sc2 != '\0'; ++sc2) { + if (*sc1 == *sc2) + return (char *) sc1; + } + } + return NULL; +} + +/** + * strtok - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * WARNING: strtok is deprecated, use strsep instead. + */ +char * strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} + +/** + * strsep - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * strsep() updates @s to point after the token, ready for the next call. + * + * It returns empty tokens, too, behaving exactly like the libc function + * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. + * Same semantics, slimmer shape. ;) + */ +char * strsep(char **s, const char *ct) +{ + char *sbegin = *s, *end; + + if (sbegin == NULL) + return NULL; + + end = strpbrk(sbegin, ct); + if (end) + *end++ = '\0'; + *s = end; + + return sbegin; +} + +/** + * memset - Fill a region of memory with the given value + * @s: Pointer to the start of the area. + * @c: The byte to fill the area with + * @count: The size of the area. + * + * Do not use memset() to access IO space, use memset_io() instead. + */ +void * memset(void * s,int c,size_t count) +{ + char *xs = (char *) s; + + while (count--) + *xs++ = c; + + return s; +} + +/** + * bcopy - Copy one area of memory to another + * @src: Where to copy from + * @dest: Where to copy to + * @count: The size of the area. + * + * Note that this is the same as memcpy(), with the arguments reversed. + * memcpy() is the standard, bcopy() is a legacy BSD function. + * + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. + */ +char * bcopy(const char * src, char * dest, int count) +{ + char *tmp = dest; + + while (count--) + *tmp++ = *src++; + + return dest; +} + +/** + * memcpy - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. + */ +void * memcpy(void * dest,const void *src,size_t count) +{ + char *tmp = (char *) dest, *s = (char *) src; + + while (count--) + *tmp++ = *s++; + + return dest; +} + +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +void * memmove(void * dest,const void *src,size_t count) +{ + char *tmp, *s; + + if (dest <= src) { + tmp = (char *) dest; + s = (char *) src; + while (count--) + *tmp++ = *s++; + } + else { + tmp = (char *) dest + count; + s = (char *) src + count; + while (count--) + *--tmp = *--s; + } + + return dest; +} + +/** + * memcmp - Compare two areas of memory + * @cs: One area of memory + * @ct: Another area of memory + * @count: The size of the area. + */ +int memcmp(const void * cs,const void * ct,size_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} + +/** + * memscan - Find a character in an area of memory. + * @addr: The memory area + * @c: The byte to search for + * @size: The size of the area. + * + * returns the address of the first occurrence of @c, or 1 byte past + * the area if @c is not found + */ +void * memscan(void * addr, int c, size_t size) +{ + unsigned char * p = (unsigned char *) addr; + + while (size) { + if (*p == c) + return (void *) p; + p++; + size--; + } + return (void *) p; +} + +/** + * strstr - Find the first substring in a %NUL terminated string + * @s1: The string to be searched + * @s2: The string to search for + */ +char * strstr(const char * s1,const char * s2) +{ + int l1, l2; + + l2 = strlen(s2); + if (!l2) + return (char *) s1; + l1 = strlen(s1); + while (l1 >= l2) { + l1--; + if (!memcmp(s1,s2,l2)) + return (char *) s1; + s1++; + } + return NULL; +} + +/** + * memchr - Find a character in an area of memory. + * @s: The memory area + * @c: The byte to search for + * @n: The size of the area. + * + * returns the address of the first occurrence of @c, or %NULL + * if @c is not found + */ +void *memchr(const void *s, int c, size_t n) +{ + const unsigned char *p = s; + while (n-- != 0) { + if ((unsigned char)c == *p++) { + return (void *)(p-1); + } + } + return NULL; +} + + +char * +strdup( const char *str ) +{ + char *p; + if( !str ) + return NULL; + p = malloc( strlen(str) + 1 ); + strcpy( p, str ); + return p; +} + +int +strcasecmp( const char *cs, const char *ct ) +{ + register signed char __res; + + while (1) { + char ch1 = toupper(*cs), ch2 = toupper(*ct); + ct++; + if ((__res = ch1 - ch2) != 0 || !*cs++) + break; + } + return __res; +} + + diff --git a/libc/vsprintf.c b/libc/vsprintf.c new file mode 100644 index 0000000..f204201 --- /dev/null +++ b/libc/vsprintf.c @@ -0,0 +1,311 @@ +/* + * String functions for logger. + */ + +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992, Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include "openbios/config.h" +#include "libc/string.h" +#include "libc/vsprintf.h" + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static int mstrlen( const char *str ); + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) { +#if 0 + tmp[i++] = digits[do_div(num,base)]; +#endif + int __res; + __res = ((unsigned long) num) % (unsigned) base; + num = ((unsigned long) num) / (unsigned) base; + tmp[i++] = digits[__res]; + } + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. to keep compiler happy. */ +//static int vsprintf(char *buf, const char *fmt, va_list args); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + +#if 0 + len = strnlen(s, precision); +#else + len = mstrlen(s); + if( precision > len ) + len = precision; +#endif + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +static int mstrlen( const char *str ) +{ + int i=0; + if( str == NULL ) + return 0; + while( *str++ ) + i++; + return i; +} diff --git a/modules/Kconfig b/modules/Kconfig new file mode 100644 index 0000000..1b36f19 --- /dev/null +++ b/modules/Kconfig @@ -0,0 +1,97 @@ + + +menu "Module Configuration" + + +config CMDLINE + bool "Command Line Editing" + default y + help + Improved openfirmware prompt + +config DEBLOCKER + bool "Deblocker" + default y + help + Deblocker implementation + +endmenu + +menu "Filesystem Configuration" + +config DISK_LABEL + bool "Disk-Label" + default y + help + Disk-label package implementation + +config PART_SUPPORT + depends on DISK_LABEL + bool "Partition support" + default y + help + Support for partition tables + +config MAC_PARTS + depends on PART_SUPPORT && BIG_ENDIAN + bool "Mac partition support" + default y + help + Support for Macintosh partition tables + +config PC_PARTS + depends on PART_SUPPORT + bool "PC style partition support" + default y + help + Support for PC style partition tables + +config FS + depends on DISK_LABEL + bool "Filesystem Support" + default y + help + Include filesystem support + +config HFS + depends on FS && BIG_ENDIAN + bool "HFS support" + default y + help + Include HFS support + +config HFSP + depends on FS && BIG_ENDIAN + bool "HFS+ support" + default y + help + Include HFS+ support + +config GRUBFS + depends on FS + bool "Additional Filesystems (from GRUB)" + default y + help + Grub provides a lot of filesystem drivers. + +source "fs/grubfs/Kconfig" + +config DEBUG_FS + depends on FS + bool "Debugging output for Filesystem code" + default y + help + Say Y here if you want to debug the filesystem layer + +endmenu + +menu "Miscellaneous" + +config LINUXBIOS + bool "Support reading LinuxBIOS table" + default y + help + If you want to boot OpenBIOS as a LinuxBIOS payload, + you should say Y here. + +endmenu diff --git a/modules/bindings.c b/modules/bindings.c new file mode 100644 index 0000000..7bee0a8 --- /dev/null +++ b/modules/bindings.c @@ -0,0 +1,520 @@ +/* + * Creation Date: <2003/11/24 12:30:18 samuel> + * Time-stamp: <2004/01/07 19:37:38 samuel> + * + * + * + * Forth bindings + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/string.h" +#include "libc/stdlib.h" +#include "libc/byteorder.h" + + +/************************************************************************/ +/* forth interface glue */ +/************************************************************************/ + +void +push_str( const char *str ) +{ + PUSH( (ucell)str ); + PUSH( str ? strlen(str) : 0 ); +} + +/* WARNING: sloooow - AVOID */ +int +feval( const char *str ) +{ + push_str( str ); + return eword("evaluate", 2); +} + +int +_eword( const char *word, xt_t *cache_xt, int nargs ) +{ + static xt_t catch_xt = 0; + int ret = -1; + + if( !catch_xt ) + catch_xt = findword("catch"); + if( !*cache_xt ) + *cache_xt = findword( (char*)word ); + + if( *cache_xt ) { + PUSH_xt( *cache_xt ); + enterforth( catch_xt ); + if( (ret=POP()) ) + dstackcnt -= nargs; + } + return ret; +} + +/* note: only the built-in dictionary is searched */ +int +_fword( const char *word, xt_t *cache_xt ) +{ + if( !*cache_xt ) + *cache_xt = findword( (char*)word ); + + if( *cache_xt ) { + enterforth( *cache_xt ); + return 0; + } + return -1; +} + +int +_selfword( const char *method, xt_t *cache_xt ) +{ + if( !*cache_xt ) + *cache_xt = find_ih_method( method, my_self() ); + if( *cache_xt ) { + enterforth( *cache_xt ); + return 0; + } + return -1; +} + +int +_parword( const char *method, xt_t *cache_xt ) +{ + if( !*cache_xt ) + *cache_xt = find_ih_method( method, my_parent() ); + if( *cache_xt ) { + enterforth( *cache_xt ); + return 0; + } + return -1; +} + +void +bind_func( const char *name, void (*func)(void) ) +{ + PUSH( (ucell)func ); + push_str( name ); + fword("is-cfunc"); +} + +void +bind_xtfunc( const char *name, xt_t xt, ucell arg, void (*func)(void) ) +{ + PUSH_xt( xt ); + PUSH( arg ); + PUSH( (cell)func ); + push_str( name ); + fword("is-xt-cfunc"); +} + +xt_t +bind_noname_func( void (*func)(void) ) +{ + PUSH( (ucell)func ); + fword("is-noname-cfunc"); + return POP_xt(); +} + +void +throw( int error ) +{ + PUSH( error ); + fword("throw"); +} + + +/************************************************************************/ +/* ihandle related */ +/************************************************************************/ + +phandle_t +ih_to_phandle( ihandle_t ih ) +{ + PUSH_ih( ih ); + fword("ihandle>phandle"); + return POP_ph(); +} + +ihandle_t +my_parent( void ) +{ + fword("my-parent"); + return POP_ih(); +} + +ihandle_t +my_self( void ) +{ + fword("my-self"); + return POP_ih(); +} + +xt_t +find_package_method( const char *method, phandle_t ph ) +{ + push_str( method ); + PUSH_ph( ph ); + fword("find-method"); + if( POP() ) + return POP_xt(); + return 0; +} + +xt_t +find_ih_method( const char *method, ihandle_t ih ) +{ + return find_package_method( method, ih_to_phandle(ih) ); +} + + +xt_t +find_parent_method( const char *method ) +{ + return find_ih_method( method, my_parent() ); +} + +void +call_package( xt_t xt, ihandle_t ihandle ) +{ + PUSH_xt( xt ); + PUSH_ih( ihandle ); + fword("call-package"); +} + +void +call_parent( xt_t xt ) +{ + PUSH_xt( xt ); + fword("call-parent"); +} + +void +call_parent_method( const char *method ) +{ + push_str( method ); + fword("$call-parent"); +} + + +/************************************************************************/ +/* open/close package/dev */ +/************************************************************************/ + +ihandle_t +open_dev( const char *spec ) +{ + push_str( spec ); + fword("open-dev"); + return POP_ih(); +} + +void +close_dev( ihandle_t ih ) +{ + PUSH_ih( ih ); + fword("close-dev"); +} + +ihandle_t +open_package( const char *argstr, phandle_t ph ) +{ + push_str( argstr ); + PUSH_ph( ph ); + fword("open-package"); + return POP_ih(); +} + +void +close_package( ihandle_t ih ) +{ + PUSH_ih( ih ); + fword("close-package"); +} + + +/************************************************************************/ +/* ihandle arguments */ +/************************************************************************/ + +char * +pop_fstr_copy( void ) +{ + int len = POP(); + char *str, *p = (char*)POP(); + if( !len ) + return NULL; + str = malloc( len + 1 ); + memcpy( str, p, len ); + str[len] = 0; + return str; +} + +char * +my_args_copy( void ) +{ + fword("my-args"); + return pop_fstr_copy(); +} + + +/************************************************************************/ +/* properties */ +/************************************************************************/ + +void +set_property( phandle_t ph, const char *name, const char *buf, int len ) +{ + if( !ph ) { + printk("set_property: NULL phandle\n"); + return; + } + PUSH((ucell)buf); + PUSH(len); + push_str( name ); + PUSH_ph(ph); + fword("set-property"); +} + +void +set_int_property( phandle_t ph, const char *name, int val ) +{ + int swapped=__cpu_to_be32(val); + set_property( ph, name, (char*)&swapped, 4 ); +} + +char * +get_property( phandle_t ph, const char *name, int *retlen ) +{ + int len; + + if( retlen ) + *retlen = -1; + + push_str( name ); + PUSH_ph( ph ); + fword("get-package-property"); + if( POP() ) + return NULL; + len = POP(); + if( retlen ) + *retlen = len; + return (char*)POP(); +} + +int +get_int_property( phandle_t ph, const char *name, int *retlen ) +{ + int *p; + + if( !(p=(int*)get_property(ph, name, retlen)) ) + return 0; + return *p; +} + + +/************************************************************************/ +/* device selection / iteration */ +/************************************************************************/ + +void +activate_dev( phandle_t ph ) +{ + PUSH_ph( ph ); + fword("active-package!"); +} + +phandle_t +activate_device( const char *str ) +{ + phandle_t ph = find_dev( str ); + activate_dev( ph ); + return ph; +} + +void +device_end( void ) +{ + fword("device-end"); +} + +phandle_t +get_cur_dev( void ) +{ + fword("active-package"); + return POP_ph(); +} + +phandle_t +find_dev( const char *path ) +{ + phandle_t ret = 0; + push_str( path ); + fword("(find-dev)"); + if( POP() ) + return POP_ph(); + return ret; +} + +phandle_t +dt_iter_begin( void ) +{ + fword("iterate-tree-begin"); + return POP_ph(); +} + +phandle_t +dt_iterate( phandle_t last ) +{ + if( !last ) + return dt_iter_begin(); + + PUSH_ph( last ); + fword("iterate-tree"); + return POP_ph(); +} + +phandle_t +dt_iterate_type( phandle_t last, const char *type ) +{ + if( !last ) + last = dt_iter_begin(); + + /* root node is never matched but we don't care about that */ + while( (last=dt_iterate(last)) ) { + char *s = get_property( last, "device_type", NULL ); + if( s && !strcmp(type, s) ) + break; + } + return last; +} + + +/************************************************************************/ +/* node methods */ +/************************************************************************/ + +void +make_openable( int only_parents ) +{ + phandle_t ph, save_ph = get_cur_dev(); + PUSH_ph( save_ph ); + + for( ;; ) { + if( only_parents++ ) + fword("parent"); + if( !(ph=POP_ph()) ) + break; + activate_dev( ph ); + PUSH_ph( ph ); + fword("is-open"); + } + activate_dev( save_ph ); +} + +static void +call1_func( void ) +{ + void (*func)(int v); + func = (void*)POP(); + + (*func)( POP() ); +} + + +static void +add_methods( int flags, int size, method_t *methods, int nmet ) +{ + xt_t xt=0; + int i; + + /* nodes might be matched multiple times */ + if( find_package_method(methods[0].name, get_cur_dev()) ) + return; + + if( size ) { + PUSH( size ); + fword("is-ibuf"); + xt = POP_xt(); + } + + for( i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/clib.fs b/modules/clib.fs new file mode 100644 index 0000000..95ddade --- /dev/null +++ b/modules/clib.fs @@ -0,0 +1,37 @@ +\ tag: C helpers +\ +\ Misc C helpers +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +\ should perhaps be moved somewhere else +: set-property ( buf len propname propname-len phandle -- ) + >r 2swap encode-bytes 2swap r> encode-property +; + +\ install C function +: is-cfunc ( funcaddr word word-len -- ) + $create , does> @ call +; + +\ install a nameless C function +: is-noname-cfunc ( funcaddr -- xt ) + 0 0 is-cfunc last-xt +; + +\ is-xt-cfunc installs a function which does the following: +\ - xt is executes +\ - funcarg is pushed +\ - funcaddr is called + +: is-xt-cfunc ( xt|0 funcarg funcaddr word word-len -- ) + is-func-begin + rot ?dup if , then + swap ['] (lit) , , ['] (lit) , , ['] call , + is-func-end +; + diff --git a/modules/client.c b/modules/client.c new file mode 100644 index 0000000..b96f4b9 --- /dev/null +++ b/modules/client.c @@ -0,0 +1,114 @@ +/* + * Creation Date: <2003/11/25 14:29:08 samuel> + * Time-stamp: <2004/03/27 01:13:53 samuel> + * + * + * + * OpenFirmware client interface + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/of.h" + +/* OF client interface. r3 points to the argument array. On return, + * r3 should contain 0==true or -1==false. r4-r12,cr0,cr1 may + * be modified freely. + * + * -1 should only be returned if the control transfer to OF fails + * (it doesn't) or if the function is unimplemented. + */ + +typedef struct prom_args { + const char *service; + int nargs; + int nret; + ulong args[10]; /* MAX NUM ARGS! */ +} prom_args_t; + + +/* call-method, interpret */ +static int +handle_calls( prom_args_t *pb ) +{ + int i, dstacksave = dstackcnt; + + /* printk("%s ([%d] -- [%d])\n", pb->service, pb->nargs, pb->nret ); */ + + for( i=pb->nargs-1; i>=0; i-- ) + PUSH( pb->args[i] ); + + push_str( pb->service ); + fword("client-call-iface"); + + for( i=0; inret && dstackcnt > dstacksave; i++ ) { + int val = POP(); + pb->args[pb->nargs + i] = val; + + /* don't pop args if an exception occured */ + if( !i && val ) + break; + } +#if 0 + /* useful for debug but not necessarily an error */ + if( i != pb->nret || dstacksave != dstacksave ) { + printk("%s '%s': possible argument error (%d--%d) got %d\n", + pb->service, (char*)pb->args[0], pb->nargs-2, pb->nret, i ); + } +#endif + + dstackcnt = dstacksave; + return 0; +} + +int +of_client_interface( int *params ) +{ + prom_args_t *pb = (prom_args_t*)params; + int val, i, dstacksave; + + if( pb->nargs < 0 || pb->nret < 0 ) + return -1; +#if 0 + printk("of_client_interface: %s ", pb->service ); + for( i=0; inargs; i++ ) + printk("%lx ", pb->args[i] ); + printk("\n"); +#endif + + /* call-method exceptions are special */ + if( !strcmp("call-method", pb->service) || !strcmp("interpret", pb->service) ) + return handle_calls( pb ); + + dstacksave = dstackcnt; + for( i=0; inargs; i++ ) + PUSH( pb->args[i] ); + + push_str( pb->service ); + fword("client-iface"); + + if( (val=POP()) ) { + dstackcnt = dstacksave; + if( val == -1 ) + printk("Unimplemented service %s ([%d] -- [%d])\n", + pb->service, pb->nargs, pb->nret ); + return -1; + } + + for( i=0; inret && dstackcnt > dstacksave ; i++ ) + pb->args[pb->nargs + i] = POP(); + + if( i != pb->nret || dstackcnt != dstacksave ) { + printk("service %s: argument count error (%d %d)\n", + pb->service, i, dstackcnt - dstacksave ); + dstackcnt = dstacksave; + } + return 0; +} diff --git a/modules/cmdline.c b/modules/cmdline.c new file mode 100644 index 0000000..783c396 --- /dev/null +++ b/modules/cmdline.c @@ -0,0 +1,368 @@ +/* + * Creation Date: <2003/12/28 14:16:31 samuel> + * Time-stamp: <2004/01/07 10:37:40 samuel> + * + * + * + * OpenFirmwware User Interface + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "modules.h" +#include "libc/vsprintf.h" + +typedef struct { + char *buf; /* size: ncol+1 */ + char *killbuf; /* size: ncol+1 */ + char *history; + int hsize; /* size of history buffer */ + int ncol; /* #columns */ +} cmdline_info_t; + +DECLARE_NODE( cmdline, INSTALL_OPEN, sizeof(cmdline_info_t), + "+/packages/cmdline" ); + +static void +emit( int ch ) +{ + PUSH( ch ); + fword("emit"); +} + +static int +emit_str( const char *str ) +{ + int n = 0; + while( *str ) { + n++; + emit( *str++ ); + } + return n; +} + +static void +move_cursor( int n ) +{ + if( n >= 0 ) { + while( n-- ) + emit( '\f' ); + } else { + while( n++ ) + emit( 8 ); + } +} + +static void +clear( int n ) +{ + int i; + for( i=0; incol = 80; + ci->buf = malloc( ci->ncol + 1 ); + ci->killbuf = malloc( ci->ncol + 1 ); + + ci->hsize = 40; + ci->history = malloc( ci->hsize ); + ci->history[0] = 0; + + RET( -1 ); +} + +/* ( -- ) */ +static void +cmdline_close( cmdline_info_t *ci ) +{ + free( ci->buf ); + free( ci->killbuf ); + free( ci->history ); +} + + +static char * +history_get( cmdline_info_t *ci, int n ) +{ + char *p = ci->history; + int len; + + while( n-- && p ) + if( (p=strchr(p,'\n')) ) + p++; + + ci->buf[0] = 0; + if( !p ) + return 0; + + for( len=0; len <= ci->ncol && p[len] != '\n' && p[len] ; len++ ) + ; + memcpy( ci->buf, p, len ); + ci->buf[len] = 0; + return p; +} + +static int +history_remove( cmdline_info_t *ci, int line ) +{ + char *s, *p = history_get( ci, line ); + + if( !p || !(s=strchr(p, '\n')) ) + return 1; + s++; + memmove( p, s, strlen(s)+1 ); + return 0; +} + +static int /* ( -- ) */ +add_to_history( cmdline_info_t *ci, char *str ) +{ + int n, len; + + if( !ci->history ) + return 0; + len = strlen(str); + if( !len ) + return 0; + + /* make room for line in history */ + for( ;; ) { + char *p; + n = strlen(ci->history) + 1; + + if( n + len + 1 <= ci->hsize ) + break; + + if( !(p=strrchr(ci->history,'\n')) ) + return 0; + *p = 0; + if( !(p=strrchr(ci->history, '\n')) ) + p = ci->history-1; + p[1] = 0; + } + + memmove( ci->history + len + 1, ci->history, n ); + memcpy( ci->history, str, len ); + ci->history[ len ] = '\n'; + return 1; +} + +static void /* ( -- ) */ +cmdline_prompt( cmdline_info_t *ci ) +{ + int cur_added=0, histind=0, ch, i, pos=0, n=0, prompt=1; + char *buf = ci->buf; + + buf = ci->buf; + selfword("prepare"); + + emit('\n'); +#ifdef NOLEAVE + for (;;) +#else + while (rstackcnt) +#endif + { + int drop = 0; + + if( prompt ) { + fword("print-prompt"); + buf[0] = 0; + cur_added = prompt = histind = pos = n = 0; + } + + switch( (ch=key()) ) { + case 27: + switch( key() ) { + case 'f': + while( buf[pos] == ' ' ) + emit( buf[pos++] ); + while( buf[pos] && buf[pos] != ' ' ) + emit( buf[pos++] ); + break; + + case 'b': + while( pos && buf[pos-1] == ' ' ) { + move_cursor( -1 ); + pos--; + } + while( pos && buf[pos-1] != ' ' ) { + move_cursor( -1 ); + pos--; + } + } + break; + case '\n': + case '\r': + if( cur_added ) + history_remove( ci, 0 ); + add_to_history( ci, ci->buf ); + + emit_str( &buf[pos] ); + emit(' '); + PUSH( feval(buf) ); + fword("print-status"); + prompt = 1; + break; + + case 3: /* ^c */ + emit_str("\n"); + prompt = 1; + if( cur_added ) + history_remove( ci, 0 ); + break; + + case 4: /* ^d */ + if( pos == n ) + break; + emit( buf[pos++] ); + /* fall through */ + + case 8: /* ^h */ + case 127: /* backspace */ + drop = 1; + if( !pos ) + break; + move_cursor( -1 ); + emit_str( &buf[pos] ); + emit(' '); + memmove( &buf[pos-1], &buf[pos], n+1-pos ); + move_cursor( pos-n-1 ); + pos--; + n--; + break; + + case 1: /* ^a */ + move_cursor( -pos ); + pos = 0; + break; + + case 5: /* ^e */ + pos += emit_str( &buf[pos] ); + break; + + case 68: /* left */ + drop = 1; + case 2: /* ^b */ + if( pos ) { + move_cursor( -1 ); + pos--; + } + break; + + case 67: /* right */ + drop = 1; + case 6: /* ^f */ + if( pos < n ) + emit( buf[pos++] ); + break; + + case 11: /* ^k */ + strcpy( ci->killbuf, &buf[pos] ); + clear( n-pos ); + n = pos; + buf[pos] = 0; + break; + + case 25: /* ^y */ + for( i=0; n < ci->ncol && ci->killbuf[i] ; i++, n++ ) { + memmove( &buf[pos+1], &buf[pos], n+1-pos ); + buf[pos] = ci->killbuf[i]; + move_cursor( 1-emit_str(&buf[pos++]) ); + } + break; + + case 9: /* TAB */ + for( i=0; n < ci->ncol && (!i || (pos%4)) ; i++, n++ ) { + memmove( &buf[pos+1], &buf[pos], n+1-pos ); + buf[pos] = ' '; + move_cursor( 1-emit_str(&buf[pos++]) ); + } + break; + + case 12: /* ^l */ + move_cursor( -ci->ncol -pos ); + fword("print-prompt"); + move_cursor( pos-emit_str(buf) ); + break; + + case 66: /* down */ + drop = 1; + case 14: /* ^n */ + if( !histind ) + break; + history_get( ci, --histind ); + clearline( pos, n ); + emit_str( buf ); + pos = n = strlen( buf ); + if( !histind && cur_added ) { + cur_added = 0; + history_remove( ci, 0 ); + } + break; + + case 65: /* up */ + drop = 1; + case 16: /* ^p */ + if( !histind && add_to_history(ci, ci->buf) ) { + cur_added = 1; + histind++; + } + if( history_get(ci, histind) ) + histind++; + clearline( pos, n ); + emit_str( buf ); + pos = n = strlen( buf ); + break; + } + if( (uint)ch < 32 ) + drop = 1; + + if( !drop && n < ci->ncol ) { + memmove( &buf[pos+1], &buf[pos], n+1-pos ); + n++; + buf[pos] = ch; + move_cursor( 1-emit_str(&buf[pos++]) ); + } + } + /* won't come here; if we ever do we should close ourselves */ +} + +NODE_METHODS( cmdline ) = { + { "open", cmdline_open }, + { "close", cmdline_close }, + { "cmdline", cmdline_prompt }, +}; + +void +cmdline_init( void ) +{ + REGISTER_NODE( cmdline ); +} diff --git a/modules/console.c b/modules/console.c new file mode 100644 index 0000000..bea02ea --- /dev/null +++ b/modules/console.c @@ -0,0 +1,208 @@ +/* + * + * + * Simple text console + * + * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2005 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" + +#include "font_8x8.c" + +#define FONT_ADJ_HEIGHT (FONT_HEIGHT + 2) +#define NCOLS 80 +#define NROWS 48 + +static struct { + int inited; + int physw, physh; + int w,h; + + int x,y; + char *buf; + + int cursor_on; +} cons; + +static int +get_conschar( int x, int y ) +{ + if( (uint)x < cons.w && (uint)y < cons.h ) + return cons.buf[y*cons.w + x]; + return ' '; +} + +static void +draw_char( uint h, uint v ) +{ + char *c = fontdata; + int x, y, xx, rskip, m; + int invert = (h==cons.x && v==cons.y && cons.cursor_on); + int ch = get_conschar( h, v ); + + while( h >= cons.w || v >= cons.h ) + return; + + h *= FONT_WIDTH; + v *= FONT_ADJ_HEIGHT; + + rskip = (FONT_WIDTH > 8)? 2 : 1; + c += rskip * (unsigned int)(ch & 0xff) * FONT_HEIGHT; + + for( x=0; x= cons.h || n < 0 ) + return; + for( i=0; i= cons.w ) { + cons.x=0, cons.y++; + continue; + } + if( cons.y >= cons.h ) { + for( y=0; y + * Time-stamp: <2004/01/07 19:34:50 samuel> + * + * + * + * deblocker implementation + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/diskio.h" +#include "modules.h" + +typedef struct { + ullong mark; + xt_t read_xt; + xt_t write_xt; + + int max_xfer; + int blksize; + char *buf; +} deblk_info_t; + +DECLARE_NODE( deblocker, 0, sizeof(deblk_info_t), "+/packages/deblocker" ); + +/* ( -- flag ) */ +static void +deblk_open( deblk_info_t *di ) +{ + xt_t xt; + + di->read_xt = find_parent_method("read-blocks"); + di->write_xt = find_parent_method("write-blocks"); + + if( !di->read_xt ) + RET(0); + + di->blksize = di->max_xfer = 512; + if( (xt=find_parent_method("block-size")) ) { + call_parent( xt ); + di->blksize = POP(); + } + if( (xt=find_parent_method("max-transfer")) ) { + call_parent( xt ); + di->max_xfer = POP(); + } + /* printk("block-size: %x max_xfer: %x read_xt %x write_xt %x\n", + di->blksize, di->max_xfer, di->write_xt, di->read_xt ); */ + + di->buf = malloc( di->blksize ); + PUSH(-1); +} + +/* ( -- ) */ +static void +deblk_close( deblk_info_t *di ) +{ + free( di->buf ); +} + +/* ( pos_lo pos_hi -- status ) */ +static void +deblk_seek( deblk_info_t *di ) +{ + uint pos_hi = POP(); + uint pos_lo = POP(); + ullong mark = ((ullong)pos_hi << 32) | pos_lo; + + /* printk("deblk_seek %x %08x\n", pos_hi, pos_lo ); */ + + /* -1 means seek to EOF (at least in our implementation) */ + if( (llong)mark == -1 ) + RET(-1); + di->mark = mark; + + /* 0,1 == success, -1 == error */ + PUSH(0); +} + +/* ( -- mark.d ) */ +static void +deblk_tell( deblk_info_t *di ) +{ + DPUSH( di->mark ); +} + + +#define DO_IO( xt, buf, blk, n ) \ + ({ PUSH3((ucell)(buf), blk, n); call_parent(xt); POP(); }) + +typedef struct { + /* block operation */ + char *blk_buf; + int nblks; + + /* byte operation */ + int offs; + int len; + char *data; /* start of data */ +} work_t; + +static void +split( deblk_info_t *di, char *data, int len, work_t w[3] ) +{ + memset( w, 0, sizeof(work_t[3]) ); + + w[0].offs = di->mark % di->blksize; + w[0].blk_buf = di->buf; + w[0].data = data; + if( w[0].offs ) { + w[0].len = MIN( len, di->blksize - w[0].offs ); + w[0].nblks = w[0].len ? 1:0; + data += w[0].len; + len -= w[0].len; + } + + w[1].blk_buf = data; + w[1].nblks = (len / di->blksize); + w[1].len = w[1].nblks * di->blksize; + data += w[1].len; + len -= w[1].len; + + w[2].blk_buf = di->buf; + w[2].data = data; + w[2].len = len; + w[2].nblks = len ? 1:0; +} + +static int +do_readwrite( deblk_info_t *di, int is_write, xt_t xt ) +{ + int blk, i, n, len = POP(); + char *dest = (char*)POP(); + int last=0, retlen=0; + work_t w[3]; + + /* printk("read: %x %x\n", (int)dest, len ); */ + + if( !xt ) + return -1; + + blk = di->mark / di->blksize; + split( di, dest, len, w ); + + for( i=0; !last && i<3; i++ ) { + if( !w[i].nblks ) + continue; + + if( is_write && i != 1 ) { + DO_IO( di->read_xt, w[i].blk_buf, blk, w[i].nblks ); + memcpy( w[i].blk_buf + w[i].offs, w[i].data, w[i].len ); + } + + n = DO_IO( xt, w[i].blk_buf, blk, w[i].nblks ); + if( n < 0 ) { + if( !retlen ) + retlen = -1; + break; + } + if( n != w[i].nblks ) { + w[i].len = MIN( n*di->blksize, w[i].len ); + last = 1; + } + if( !is_write && i != 1 ) + memcpy( w[i].data, w[i].blk_buf + w[i].offs, w[i].len ); + retlen += w[i].len; + blk += n; + } + if( retlen > 0 ) + di->mark += retlen; + return retlen; +} + +/* ( addr len -- actual ) */ +static void +deblk_read( deblk_info_t *di ) +{ + /* printk("deblk_read\n"); */ + int ret = do_readwrite( di, 0, di->read_xt ); + PUSH( ret ); +} + +/* ( buf len --- actlen ) */ +static void +deblk_write( deblk_info_t *di ) +{ + int ret = do_readwrite( di, 1, di->write_xt ); + PUSH( ret ); +} + +/* remember to fix is-deblocker if new methods are added */ +NODE_METHODS( deblocker ) = { + { "open", deblk_open }, + { "close", deblk_close }, + { "read", deblk_read }, + { "write", deblk_write }, + { "seek", deblk_seek }, + { "tell", deblk_tell }, +}; + + +void +deblocker_init( void ) +{ + REGISTER_NODE( deblocker ); +} diff --git a/modules/disk-label.c b/modules/disk-label.c new file mode 100644 index 0000000..6250bb3 --- /dev/null +++ b/modules/disk-label.c @@ -0,0 +1,211 @@ +/* + * Creation Date: <2003/12/03 22:10:45 samuel> + * Time-stamp: <2004/01/07 19:17:45 samuel> + * + * + * + * Partition support + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/diskio.h" +#include "modules.h" + +typedef struct { + int fd; + + ullong offs; + ullong size; + int type; /* partition type or -1 */ + + ihandle_t part_ih; +} dlabel_info_t; + +DECLARE_NODE( dlabel, 0, sizeof(dlabel_info_t), "/packages/disk-label" ); + + +/* ( -- ) */ +static void +dlabel_close( dlabel_info_t *di ) +{ + if( di->part_ih ) + close_package( di->part_ih ); + + if( di->fd ) + close_io( di->fd ); +} + +/* ( -- success? ) */ +static void +dlabel_open( dlabel_info_t *di ) +{ + char *s, *filename, *parstr; + char block0[512]; + phandle_t ph; + int fd, success=0; + + parstr = my_args_copy(); + /* printk("dlabel-open '%s'\n", parstr ); */ + + if( (fd=open_ih(my_parent())) == -1 ) + goto out; + di->fd = fd; + + /* argument format: parnum,filename */ + s = parstr; + filename = NULL; + if( s ) { + if( *s == '-' || isdigit(*s) ) { + if( (s=strpbrk(parstr,",")) ) { + filename = s+1; + *s = 0; + } + } else { + filename = s; + parstr = NULL; + if( *s == ',' ) + filename++; + } + } + + /* find partition handler */ + seek_io( fd, 0 ); + if( read_io(fd, block0, sizeof(block0)) != sizeof(block0) ) + goto out; + PUSH( (ucell)block0 ); + selfword("find-part-handler"); + ph = POP_ph(); + + /* open partition package */ + if( ph ) { + xt_t xt; + if( !(di->part_ih=open_package(parstr, ph)) ) + goto out; + if( !(xt=find_ih_method("get-info", di->part_ih)) ) + goto out; + call_package( xt , di->part_ih ); + di->size = DPOP(); + di->offs = DPOP(); + di->type = POP(); + } + + /* probe for filesystem */ + PUSH_ih( my_self() ); + selfword("find-filesystem"); + ph = POP_ph(); + if( ph ) { + push_str( filename ); + PUSH_ph( ph ); + fword("interpose"); + } else if( filename ) { + goto out; + } + success = 1; + + out: + if( parstr ) + free( parstr ); + if( !success ) { + dlabel_close( di ); + RET(0); + } + PUSH(-1); +} + +/* ( addr len -- actual ) */ +static void +dlabel_read( dlabel_info_t *di ) +{ + int ret, len = POP(); + char *buf = (char*)POP(); + + ret = read_io( di->fd, buf, len ); + PUSH( ret ); +} + +/* ( pos.d -- status ) */ +static void +dlabel_seek( dlabel_info_t *di ) +{ + llong pos = DPOP(); + int ret; + + if( pos != -1 ) + pos += di->offs; + else if( di->size ) { + /* printk("Seek EOF\n"); */ + pos = di->offs + di->size; + } else { + /* let parent handle the EOF seek. */ + } + + /* printk("dlabel_seek: %x %08x\n", (int)(pos>>32), (int)pos ); */ + ret = seek_io( di->fd, pos ); + PUSH( ret ); +} + +/* ( -- filepos.d ) */ +static void +dlabel_tell( dlabel_info_t *di ) +{ + llong pos = tell( di->fd ); + if( pos != -1 ) + pos -= di->offs; + + DPUSH( pos ); +} + + +/* ( addr len -- actual ) */ +static void +dlabel_write( dlabel_info_t *di ) +{ + DDROP(); + PUSH( -1 ); +} + +/* ( rel.d -- abs.d ) */ +static void +dlabel_offset( dlabel_info_t *di ) +{ + ullong rel = DPOP(); + rel += di->offs; + DPUSH( rel ); +} + +/* ( addr -- size ) */ +static void +dlabel_load( dlabel_info_t *di ) +{ + /* XXX: try the load method of the part package */ + + printk("Can't load from this device!\n"); + POP(); + PUSH(0); +} + +NODE_METHODS( dlabel ) = { + { "open", dlabel_open }, + { "close", dlabel_close }, + { "offset", dlabel_offset }, + { "load", dlabel_load }, + + { "read", dlabel_read }, + { "write", dlabel_write }, + { "seek", dlabel_seek }, + { "tell", dlabel_tell }, +}; + +void +disklabel_init( void ) +{ + REGISTER_NODE( dlabel ); +} diff --git a/modules/elfload.c b/modules/elfload.c new file mode 100644 index 0000000..ce7c2b6 --- /dev/null +++ b/modules/elfload.c @@ -0,0 +1,129 @@ +/* Mac-on-Linux ELF loader + + Copyright (C) 2001-2003 Samuel Rydh + + adapted from yaboot + + Copyright (C) 1999 Benjamin Herrenschmidt + + portions based on poof + + Copyright (C) 1999 Marius Vollmer + + portions based on quik + + Copyright (C) 1996 Paul Mackerras. + + Because this program is derived from the corresponding file in the + silo-0.64 distribution, it is also + + Copyright (C) 1996 Pete A. Zaitcev + 1996 Maurizio Plaza + 1996 David S. Miller + 1996 Miguel de Icaza + 1996 Jakub Jelinek + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/elfload.h" +#include "libc/diskio.h" +#include "openbios/elf.h" + +#define DEBUG 0 +#define MAX_HEADERS 32 +#define BS 0x100 /* smallest step used when looking for the ELF header */ + + +int +find_elf( int fd ) +{ + int size, offs; + + seek_io( fd, -1 ); + size = tell( fd ); + if( size > 0x10000 ) + size = 0x10000; + + for( offs=0; offs < size; offs+= BS ) + if( is_elf(fd, offs) ) + return offs; + return -1; +} + +int +is_elf( int fd, int offs ) +{ + Elf_ehdr e; + + seek_io( fd, offs ); + if( read_io(fd, &e, sizeof(e)) != sizeof(e) ) { + printk("\nCan't read ELF image header\n"); + return 0; + } + + return (e.e_ident[EI_MAG0] == ELFMAG0 && + e.e_ident[EI_MAG1] == ELFMAG1 && + e.e_ident[EI_MAG2] == ELFMAG2 && + e.e_ident[EI_MAG3] == ELFMAG3 && + e.e_ident[EI_CLASS] == ARCH_ELF_CLASS && + e.e_ident[EI_DATA] == ARCH_ELF_DATA && + e.e_type == ET_EXEC && + ARCH_ELF_MACHINE_OK(e.e_machine)); +} + +Elf_phdr * +elf_readhdrs( int fd, int offs, Elf_ehdr *e ) +{ + int size; + Elf_phdr *ph; + + if( !is_elf(fd, offs) ) { + printk("Not an ELF image\n"); + return NULL; + } + + seek_io( fd, offs ); + if( read_io(fd, e, sizeof(*e)) != sizeof(*e) ) { + printk("\nCan't read ELF image header\n"); + return NULL; + } + +#if DEBUG + printk("ELF header:\n"); + printk(" e.e_type = %d\n", (int)e->e_type); + printk(" e.e_machine = %d\n", (int)e->e_machine); + printk(" e.e_version = %d\n", (int)e->e_version); + printk(" e.e_entry = 0x%08x\n", (int)e->e_entry); + printk(" e.e_phoff = 0x%08x\n", (int)e->e_phoff); + printk(" e.e_shoff = 0x%08x\n", (int)e->e_shoff); + printk(" e.e_flags = %d\n", (int)e->e_flags); + printk(" e.e_ehsize = 0x%08x\n", (int)e->e_ehsize); + printk(" e.e_phentsize = 0x%08x\n", (int)e->e_phentsize); + printk(" e.e_phnum = %d\n", (int)e->e_phnum); +#endif + if (e->e_phnum > MAX_HEADERS) { + printk ("elfload: too many program headers (MAX_HEADERS)\n"); + return NULL; + } + + size = sizeof(Elf_phdr) * e->e_phnum; + if( !(ph=(Elf_phdr *)malloc(size)) ) { + printk("malloc error\n"); + return NULL; + } + + /* Now, we read the section header */ + seek_io( fd, offs+e->e_phoff ); + if( read_io(fd, (char*)ph, size) != size ) { + printk("read error"); + free( ph ); + return NULL; + } + return ph; +} diff --git a/modules/elfnote.c b/modules/elfnote.c new file mode 100644 index 0000000..01fdf74 --- /dev/null +++ b/modules/elfnote.c @@ -0,0 +1,151 @@ +/* Support for ELF Boot Proposal as a boot image */ +#include "openbios/config.h" +#include "elf_boot.h" +#include "sys_info.h" +#include "asm/io.h" +#include "ipchecksum.h" +#define printf printk +#define debug printk + +/* ELF image notes provide information to the loader who boots us */ + +/* This compiles and generates correct PT_NOTE segment for me. + * If it doesn't, use assembly version below. */ + +struct elf_image_note { + Elf_Nhdr hdr0; + char name0[sizeof(ELF_NOTE_BOOT)]; + char prog_name[sizeof(PROGRAM_NAME)]; + + Elf_Nhdr hdr1; + char name1[sizeof(ELF_NOTE_BOOT)]; + char version[sizeof(PROGRAM_VERSION)]; + + Elf_Nhdr hdr2; + char name2[sizeof(ELF_NOTE_BOOT)]; + unsigned short checksum; +}; + +const struct elf_image_note elf_image_notes + __attribute__ ((section (".note.ELFBoot"))) = +{ + .hdr0 = { + .n_namesz = sizeof(ELF_NOTE_BOOT), + .n_descsz = sizeof(PROGRAM_NAME), + .n_type = EIN_PROGRAM_NAME, + }, + .name0 = ELF_NOTE_BOOT, + .prog_name = PROGRAM_NAME, + + .hdr1 = { + .n_namesz = sizeof(ELF_NOTE_BOOT), + .n_descsz = sizeof(PROGRAM_VERSION), + .n_type = EIN_PROGRAM_VERSION, + }, + .name1 = ELF_NOTE_BOOT, + .version = PROGRAM_VERSION, + + .hdr2 = { + .n_namesz = sizeof(ELF_NOTE_BOOT), + .n_descsz = sizeof(unsigned short), + .n_type = EIN_PROGRAM_CHECKSUM, + }, + .name2 = ELF_NOTE_BOOT, + .checksum = 0, /* to be computed by external tool */ +}; + +/* This is refered by other files */ +const char *program_name = elf_image_notes.prog_name; +const char *program_version = elf_image_notes.version; + +#if 0 + + /* This tells the linker to make a PT_NOTE segment. + * If the section is named just ".note", it will be + * mixed up with useless .version notes generated by GCC. + */ + .section ".note.ELFBoot", "a" + + .align 4 + .int 2f - 1f + .int 4f - 3f + .int EIN_PROGRAM_NAME +1: .asciz "ELFBoot" +2: .align 4 +3: .asciz PROGRAM_NAME +4: + + .align 4 + .int 2f - 1f + .int 4f - 3f + .int EIN_PROGRAM_VERSION +1: .asciz "ELFBoot" +2: .align 4 +3: .asciz PROGRAM_VERSION +4: + + .align 4 + .int 2f - 1f + .int 4f - 3f + .int EIN_PROGRAM_CHECKSUM +1: .asciz "ELFBoot" +2: .align 4 +3: .short 0 +4: +#endif + +/* Collect information from the ELF bootloader + * Note that we have to copy them to our own memory, + * otherwise they might be overwritten afterward. */ +void collect_elfboot_info(struct sys_info *info) +{ + Elf_Bhdr *hdr = NULL; + char *addr, *end; + Elf_Nhdr *nhdr; + char *name, *desc; + + if (info->boot_type == ELF_BHDR_MAGIC) + hdr = phys_to_virt(info->boot_data); + else + hdr = phys_to_virt(info->boot_arg); + + if (hdr->b_signature != ELF_BHDR_MAGIC) + return; + + if (ipchksum(hdr, hdr->b_size) != 0) { + printf("Broken ELF boot notes\n"); + return; + } + + addr = (char *) (hdr + 1); + end = addr + hdr->b_size; + while (addr < end) { + nhdr = (Elf_Nhdr *) addr; + addr += sizeof(Elf_Nhdr); + name = addr; + addr += (nhdr->n_namesz + 3) & ~3; + desc = addr; + addr += (nhdr->n_descsz + 3) & ~3; + + if (nhdr->n_namesz == 0) { + /* Standard notes */ + switch (nhdr->n_type) { + case EBN_FIRMWARE_TYPE: + info->firmware = strdup(desc); + break; + case EBN_BOOTLOADER_NAME: + debug("Bootloader: %s\n", desc); + break; + case EBN_BOOTLOADER_VERSION: + debug("Version: %s\n", desc); + break; + case EBN_COMMAND_LINE: + info->command_line = strdup(desc); + break; + case EBN_LOADED_IMAGE: + debug("Image name: %s\n", desc); + break; + } + } + } +} diff --git a/modules/filesystems.c b/modules/filesystems.c new file mode 100644 index 0000000..86966af --- /dev/null +++ b/modules/filesystems.c @@ -0,0 +1,288 @@ +/* + * Creation Date: <2003/12/08 19:19:29 samuel> + * Time-stamp: <2004/01/07 19:22:40 samuel> + * + * + * + * generic filesystem support node + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2004 Stefan Reinauer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/fs.h" +#include "libc/diskio.h" +#include "modules.h" + +#define PATHBUF_SIZE 256 +#define VOLNAME_SIZE 64 + +typedef struct { + fs_ops_t *fs; + file_desc_t *file; + char *pathbuf; + char *volname; + + cell filepos; +} files_info_t; + +DECLARE_NODE( files, 0, sizeof(files_info_t), "+/packages/misc-files" ); + + +static fs_ops_t * +do_open( ihandle_t ih ) +{ + fs_ops_t *fs = malloc( sizeof(*fs) ); + int err, fd; + + err = (fd=open_ih(ih)) == -1; + + if( !err ) { + err=fs_hfsp_open(fd, fs); + if( err ) err = fs_hfs_open(fd, fs); + if( err ) err = fs_grubfs_open(fd, fs); + } + + fs->fd = fd; + + if( err ) { + if( fd != -1 ) + close_io( fd ); + free( fs ); + return NULL; + } + + return fs; +} + +static void +do_close( fs_ops_t *fs ) +{ + fs->close_fs( fs ); + close_io( fs->fd ); + free( fs ); +} + +/* ( -- success? ) */ +static void +files_open( files_info_t *mi ) +{ + fs_ops_t *fs = do_open( my_parent() ); + char *name; + + if( !fs ) + RET( 0 ); + + name = my_args_copy(); + if( name ) { + if( !(mi->file=fs_open_path(fs, name)) ) { + free( name ); + do_close( fs ); + RET(0); + } + /* printk("PATH: %s\n", fs->get_path(mi->file, mi->pathbuf, PATHBUF_SIZE) ); */ + } + mi->fs = fs; + + if( name ) + free( name ); + + RET( -1 ); +} + +static void +do_reopen( files_info_t *mi, file_desc_t *file ) +{ + if( !file ) + return; + if( mi->file ) + mi->fs->close( mi->file ); + mi->file = file; + mi->filepos = 0; +} + +/* ( file-str len -- success? ) */ +static void +files_reopen( files_info_t *mi ) +{ + file_desc_t *file = NULL; + char *name = pop_fstr_copy(); + + if( name ) { + file = fs_open_path( mi->fs, name ); + free( name ); + do_reopen( mi, file ); + } + PUSH( file? -1:0 ); +} + +/* ( -- cstr ) */ +static void +files_get_path( files_info_t *mi ) +{ + char *ret; + + if( !mi->file ) + RET(0); + if( !mi->pathbuf ) + mi->pathbuf = malloc( PATHBUF_SIZE ); + ret = mi->fs->get_path( mi->file, mi->pathbuf, PATHBUF_SIZE ); + PUSH( (ucell)ret ); +} + +/* ( -- cstr|0 ) */ +static void +files_volume_name( files_info_t *mi ) +{ + char *ret; + + if( !mi->volname ) + mi->volname = malloc( VOLNAME_SIZE ); + + ret = mi->fs->vol_name( mi->fs, mi->volname, VOLNAME_SIZE ); + PUSH( (ucell)ret ); +} + +/* ( -- success? ) */ +static void +files_open_nwrom( files_info_t *mi ) +{ + file_desc_t *file = fs_search_rom( mi->fs ); + do_reopen( mi, file ); + PUSH( file? -1:0 ); +} + +/* ( -- ) */ +static void +files_close( files_info_t *mi ) +{ + if( mi->file ) + mi->fs->close( mi->file ); + do_close( mi->fs ); + + if( mi->pathbuf ) + free( mi->pathbuf ); + if( mi->volname ) + free( mi->volname ); +} + +/* ( buf len -- actlen ) */ +static void +files_read( files_info_t *mi ) +{ + int len = POP(); + char *buf = (char*)POP(); + int ret; + + if( mi->file ) { + ret = mi->fs->read( mi->file, buf, len ); + mi->filepos += ret; + } else { + ret = read_io( mi->fs->fd, buf, len ); + } + PUSH( ret ); +} + +/* ( buf len -- actlen ) */ +static void +files_write( files_info_t *mi ) +{ + DDROP(); + PUSH( 0 ); +} + +/* ( pos.d -- status ) */ +static void +files_seek( files_info_t *mi ) +{ + llong pos = DPOP(); + int ret; + + if( mi->file ) { + int offs = (int)pos; + int whence = SEEK_SET; + + if( offs == -1 ) { + offs = 0; + whence = SEEK_END; + } + mi->filepos = mi->fs->lseek( mi->file, offs, whence ); + ret = (mi->filepos < 0)? -1 : 0; + } else { + ret = seek_io( mi->fs->fd, pos ); + } + PUSH( ret ); +} + +/* ( -- filepos.d ) */ +static void +files_tell( files_info_t *mi ) +{ + llong ret = mi->file ? mi->filepos : -1; + DPUSH( ret ); +} + +/* ( -- cstr ) */ +static void +files_get_fstype( files_info_t *mi ) +{ + if (mi->fs->get_fstype) + PUSH( (ucell)(mi->fs->get_fstype(mi->fs)) ); + else + PUSH( (ucell)"unspecified"); +} + +/* static method, ( ih -- flag? ) */ +static void +files_probe( files_info_t *dummy ) +{ + ihandle_t ih = POP_ih(); + fs_ops_t *fs; + int ret = 0; + + if( (fs=do_open(ih)) != NULL ) { + /* printk("HFS[+] filesystem found\n"); */ + do_close( fs ); + ret = -1; + } + PUSH( ret ); +} + +static void +files_initializer( files_info_t *dummy ) +{ + fword("register-fs-package"); +} + +NODE_METHODS( files ) = { + { "probe", files_probe }, + { "open", files_open }, + { "close", files_close }, + { "read", files_read }, + { "write", files_write }, + { "seek", files_seek }, + { "tell", files_tell }, + + /* special */ + { "reopen", files_reopen }, + { "open-nwrom", files_open_nwrom }, + { "get-path", files_get_path }, + { "get-fstype", files_get_fstype }, + { "volume-name", files_volume_name }, + + { NULL, files_initializer }, +}; + + +void +filesystem_init( void ) +{ + REGISTER_NODE( files ); +} diff --git a/modules/font_8x8.c b/modules/font_8x8.c new file mode 100644 index 0000000..756fc43 --- /dev/null +++ b/modules/font_8x8.c @@ -0,0 +1,2573 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +#define FONTDATAMAX 2048 +#define FONT_WIDTH 8 +#define FONT_HEIGHT 8 + +static unsigned char fontdata[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + + /* 2 0x02 '^B' */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xce, /* 11001110 */ + 0x7c, /* 01111100 */ + 0x0e, /* 00001110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x8c, /* 10001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + + /* 96 0x60 '`' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf8, /* 11111000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + + /* 104 0x68 'h' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + + /* 107 0x6b 'k' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x4c, /* 01001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 'ˆ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '™' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c 'œ' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e 'ž' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f 'Ÿ' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '¬' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '­' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 'é' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee 'î' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc 'ü' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; diff --git a/modules/helpers.fs b/modules/helpers.fs new file mode 100644 index 0000000..8f5db9f --- /dev/null +++ b/modules/helpers.fs @@ -0,0 +1,35 @@ +\ tag: helper functions +\ +\ deblocker / filesystem support +\ +\ Copyright (C) 2003 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + + +\ create device node and any missing parents. +\ The new node becomes the active package + +: create-node ( nodepath -- ) + recursive + ascii / right-split + 2dup find-dev if + active-package! + 2drop + else + ( nodename path ) + dup if + create-node + else + device-tree @ active-package! + 2drop + then + then + new-device + device-name + active-package + finish-device + active-package! +; diff --git a/modules/init.c b/modules/init.c new file mode 100644 index 0000000..a807156 --- /dev/null +++ b/modules/init.c @@ -0,0 +1,42 @@ +/* + * Creation Date: <2003/12/23 00:28:05 samuel> + * Time-stamp: <2003/12/28 19:43:41 samuel> + * + * + * + * Module intialization + * + * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/kernel.h" +#include "modules.h" + +void +modules_init( void ) +{ +#ifdef CONFIG_CMDLINE + cmdline_init(); +#endif +#ifdef CONFIG_DEBLOCKER + deblocker_init(); +#endif +#ifdef CONFIG_DISK_LABEL + disklabel_init(); +#endif +#ifdef CONFIG_FS + filesystem_init(); +#endif +#ifdef CONFIG_MAC_PARTS + macparts_init(); +#endif +#ifdef CONFIG_PC_PARTS + pcparts_init(); +#endif +} diff --git a/modules/ipchecksum.c b/modules/ipchecksum.c new file mode 100644 index 0000000..471be06 --- /dev/null +++ b/modules/ipchecksum.c @@ -0,0 +1,55 @@ +/* Taken from Etherboot */ + +#include "ipchecksum.h" + +unsigned short ipchksum(const void *data, unsigned long length) +{ + unsigned long sum; + unsigned long i; + const unsigned char *ptr; + union { + unsigned char byte[2]; + unsigned short word; + } u; + + /* In the most straight forward way possible, + * compute an ip style checksum. + */ + sum = 0; + ptr = data; + for(i = 0; i < length; i++) { + unsigned long value; + value = ptr[i]; + if (i & 1) { + value <<= 8; + } + /* Add the new value */ + sum += value; + /* Wrap around the carry */ + if (sum > 0xFFFF) { + sum = (sum + (sum >> 16)) & 0xFFFF; + } + } + u.byte[0] = (unsigned char) sum; + u.byte[1] = (unsigned char) (sum >> 8); + return (unsigned short) ~u.word; +} + +unsigned short add_ipchksums(unsigned long offset, unsigned short sum, unsigned short new) +{ + unsigned long checksum; + sum = ~sum & 0xFFFF; + new = ~new & 0xFFFF; + if (offset & 1) { + /* byte swap the sum if it came from an odd offset + * since the computation is endian independant this + * works. + */ + new = (new << 8) | (new >> 8); + } + checksum = sum + new; + if (checksum > 0xFFFF) { + checksum -= 0xFFFF; + } + return (~checksum) & 0xFFFF; +} diff --git a/modules/linuxbios.c b/modules/linuxbios.c new file mode 100644 index 0000000..cbfa1dd --- /dev/null +++ b/modules/linuxbios.c @@ -0,0 +1,129 @@ +/* Adapted from Etherboot 5.1.8 */ + +#include "openbios/config.h" +#include "openbios/sysinclude.h" +#include "asm/types.h" +#include "asm/io.h" +#include "linuxbios.h" +#include "ipchecksum.h" +#include "sys_info.h" + +#ifdef CONFIG_DEBUG_BOOT +#define debug printk +#else +#define debug(x...) +#endif + +#define for_each_lbrec(head, rec) \ + for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \ + (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \ + (rec->size >= 1) && \ + ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \ + rec = (struct lb_record *)(((char *)rec) + rec->size)) + +static void convert_memmap(struct lb_memory *lbmem, struct sys_info *info) +{ + int lbcount; + int i; + + lbcount = lbmem->size / sizeof(struct lb_memory_range); + info->memrange = malloc(lbcount * sizeof(struct memrange)); + info->n_memranges = 0; + for (i = 0; i < lbcount; i++) { + debug("%#016Lx %#016Lx %d\n", + lbmem->map[i].start, lbmem->map[i].size, + (int) lbmem->map[i].type); + if (lbmem->map[i].type != LB_MEM_RAM) + continue; + info->memrange[info->n_memranges].base = lbmem->map[i].start; + info->memrange[info->n_memranges].size = lbmem->map[i].size; + info->n_memranges++; + } +} + +static int read_lbtable(struct lb_header *head, struct sys_info *info) +{ + int retval = 0; + + /* Read linuxbios tables... */ + struct lb_record *rec; + + for_each_lbrec(head, rec) { + switch(rec->tag) { + case LB_TAG_MEMORY: + convert_memmap((struct lb_memory *) rec, info); + retval = 1; + break; + }; + } + return retval; +} + +static unsigned long count_lb_records(void *start, unsigned long length) +{ + struct lb_record *rec; + void *end; + unsigned long count; + count = 0; + end = ((char *)start) + length; + for(rec = start; ((void *)rec < end) && + ((signed long)rec->size <= (end - (void *)rec)); + rec = (void *)(((char *)rec) + rec->size)) { + count++; + } + return count; +} + +static int find_lb_table(void *start, void *end, struct lb_header **result) +{ + unsigned char *ptr; + /* For now be stupid.... */ + for(ptr = start; (void *)ptr < end; ptr += 16) { + struct lb_header *head = (struct lb_header *)ptr; + if ( (head->signature[0] != 'L') || + (head->signature[1] != 'B') || + (head->signature[2] != 'I') || + (head->signature[3] != 'O')) { + continue; + } + if (head->header_bytes != sizeof(*head)) + continue; + debug("Found canidate at: %p\n", head); + if (ipchksum((uint16_t *)head, sizeof(*head)) != 0) + continue; + debug("header checksum o.k.\n"); + if (ipchksum((uint16_t *)(ptr + sizeof(*head)), head->table_bytes) != + head->table_checksum) { + continue; + } + debug("table checksum o.k.\n"); + if (count_lb_records(ptr + sizeof(*head), head->table_bytes) != + head->table_entries) { + continue; + } + debug("record count o.k.\n"); + *result = head; + return 1; + }; + return 0; +} + +void collect_linuxbios_info(struct sys_info *info) +{ + struct lb_header *lb_table; + int found; + debug("Searching for LinuxBIOS tables...\n"); + found = 0; + if (!found) { + found = find_lb_table(phys_to_virt(0x00000), phys_to_virt(0x01000), &lb_table); + } + if (!found) { + found = find_lb_table(phys_to_virt(0xf0000), phys_to_virt(0x100000), &lb_table); + } + if (!found) + return; + + debug("Found LinuxBIOS table at: %p\n", lb_table); + info->firmware = "LinuxBIOS"; + read_lbtable(lb_table, info); +} diff --git a/modules/linuxbios.h b/modules/linuxbios.h new file mode 100644 index 0000000..143ece6 --- /dev/null +++ b/modules/linuxbios.h @@ -0,0 +1,181 @@ +#ifndef LINUXBIOS_TABLES_H +#define LINUXBIOS_TABLES_H + +/* The linuxbios table information is for conveying information + * from the firmware to the loaded OS image. Primarily this + * is expected to be information that cannot be discovered by + * other means, such as quering the hardware directly. + * + * All of the information should be Position Independent Data. + * That is it should be safe to relocated any of the information + * without it's meaning/correctnes changing. For table that + * can reasonably be used on multiple architectures the data + * size should be fixed. This should ease the transition between + * 32 bit and 64 bit architectures etc. + * + * The completeness test for the information in this table is: + * - Can all of the hardware be detected? + * - Are the per motherboard constants available? + * - Is there enough to allow a kernel to run that was written before + * a particular motherboard is constructed? (Assuming the kernel + * has drivers for all of the hardware but it does not have + * assumptions on how the hardware is connected together). + * + * With this test it should be straight forward to determine if a + * table entry is required or not. This should remove much of the + * long term compatibility burden as table entries which are + * irrelevant or have been replaced by better alternatives may be + * dropped. Of course it is polite and expidite to include extra + * table entries and be backwards compatible, but it is not required. + */ + + +struct lb_header +{ + uint8_t signature[4]; /* LBIO */ + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +}; + +/* Every entry in the boot enviroment list will correspond to a boot + * info record. Encoding both type and size. The type is obviously + * so you can tell what it is. The size allows you to skip that + * boot enviroment record if you don't know what it easy. This allows + * forward compatibility with records not yet defined. + */ +struct lb_record { + uint32_t tag; /* tag ID */ + uint32_t size; /* size of record (in bytes) */ +}; + +#define LB_TAG_UNUSED 0x0000 + +#define LB_TAG_MEMORY 0x0001 + +struct lb_memory_range { + uint64_t start; + uint64_t size; + uint32_t type; +#define LB_MEM_RAM 1 /* Memory anyone can use */ +#define LB_MEM_RESERVED 2 /* Don't use this memory region */ +#define LB_MEM_TABLE 16 /* Ram configuration tables are kept in */ + +}; + +struct lb_memory { + uint32_t tag; + uint32_t size; + struct lb_memory_range map[0]; +}; + +#define LB_TAG_HWRPB 0x0002 +struct lb_hwrpb { + uint32_t tag; + uint32_t size; + uint64_t hwrpb; +}; + +#define LB_TAG_MAINBOARD 0x0003 +struct lb_mainboard { + uint32_t tag; + uint32_t size; + uint8_t vendor_idx; + uint8_t part_number_idx; + uint8_t strings[0]; +}; + +#define LB_TAG_VERSION 0x0004 +#define LB_TAG_EXTRA_VERSION 0x0005 +#define LB_TAG_BUILD 0x0006 +#define LB_TAG_COMPILE_TIME 0x0007 +#define LB_TAG_COMPILE_BY 0x0008 +#define LB_TAG_COMPILE_HOST 0x0009 +#define LB_TAG_COMPILE_DOMAIN 0x000a +#define LB_TAG_COMPILER 0x000b +#define LB_TAG_LINKER 0x000c +#define LB_TAG_ASSEMBLER 0x000d +struct lb_string { + uint32_t tag; + uint32_t size; + uint8_t string[0]; +}; + +/* The following structures are for the cmos definitions table */ +#define LB_TAG_CMOS_OPTION_TABLE 200 +/* cmos header record */ +struct cmos_option_table { + uint32_t tag; /* CMOS definitions table type */ + uint32_t size; /* size of the entire table */ + uint32_t header_length; /* length of header */ +}; + +/* cmos entry record + This record is variable length. The name field may be + shorter than CMOS_MAX_NAME_LENGTH. The entry may start + anywhere in the byte, but can not span bytes unless it + starts at the beginning of the byte and the length is + fills complete bytes. +*/ +#define LB_TAG_OPTION 201 +struct cmos_entries { + uint32_t tag; /* entry type */ + uint32_t size; /* length of this record */ + uint32_t bit; /* starting bit from start of image */ + uint32_t length; /* length of field in bits */ + uint32_t config; /* e=enumeration, h=hex, r=reserved */ + uint32_t config_id; /* a number linking to an enumeration record */ +#define CMOS_MAX_NAME_LENGTH 32 + uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name of entry in ascii, + variable length int aligned */ +}; + + +/* cmos enumerations record + This record is variable length. The text field may be + shorter than CMOS_MAX_TEXT_LENGTH. +*/ +#define LB_TAG_OPTION_ENUM 202 +struct cmos_enums { + uint32_t tag; /* enumeration type */ + uint32_t size; /* length of this record */ + uint32_t config_id; /* a number identifying the config id */ + uint32_t value; /* the value associated with the text */ +#define CMOS_MAX_TEXT_LENGTH 32 + uint8_t text[CMOS_MAX_TEXT_LENGTH]; /* enum description in ascii, + variable length int aligned */ +}; + +/* cmos defaults record + This record contains default settings for the cmos ram. +*/ +#define LB_TAG_OPTION_DEFAULTS 203 +struct cmos_defaults { + uint32_t tag; /* default type */ + uint32_t size; /* length of this record */ + uint32_t name_length; /* length of the following name field */ + uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name identifying the default */ +#define CMOS_IMAGE_BUFFER_SIZE 128 + uint8_t default_set[CMOS_IMAGE_BUFFER_SIZE]; /* default settings */ +}; + +#define LB_TAG_OPTION_CHECKSUM 204 +struct cmos_checksum { + uint32_t tag; + uint32_t size; + /* In practice everything is byte aligned, but things are measured + * in bits to be consistent. + */ + uint32_t range_start; /* First bit that is checksummed (byte aligned) */ + uint32_t range_end; /* Last bit that is checksummed (byte aligned) */ + uint32_t location; /* First bit of the checksum (byte aligned) */ + uint32_t type; /* Checksum algorithm that is used */ +#define CHECKSUM_NONE 0 +#define CHECKSUM_PCBIOS 1 +}; + + + +#endif /* LINUXBIOS_TABLES_H */ diff --git a/modules/mac-parts.c b/modules/mac-parts.c new file mode 100644 index 0000000..277e07f --- /dev/null +++ b/modules/mac-parts.c @@ -0,0 +1,124 @@ +/* + * Creation Date: <2003/12/04 17:07:05 samuel> + * Time-stamp: <2004/01/07 19:36:09 samuel> + * + * + * + * macintosh partition support + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "mac-parts.h" +#include "modules.h" + +typedef struct { + ullong offs; + ullong size; +} macparts_info_t; + +DECLARE_NODE( macparts, INSTALL_OPEN, sizeof(macparts_info_t), "+/packages/mac-parts" ); + + +#define SEEK( pos ) ({ DPUSH(pos); call_parent(seek_xt); POP(); }) +#define READ( buf, size ) ({ PUSH((ucell)buf); PUSH(size); call_parent(read_xt); POP(); }) + +/* ( open -- flag ) */ +static void +macparts_open( macparts_info_t *di ) +{ + char *str = my_args_copy(); + xt_t seek_xt = find_parent_method("seek"); + xt_t read_xt = find_parent_method("read"); + int bs, parnum=-1; + desc_map_t dmap; + part_entry_t par; + + /* printk("macparts_open '%s'\n", str ); */ + + if( str ) { + parnum = atol(str); + if( !strlen(str) ) + parnum = 1; + free( str ); + } + if( parnum < 0 ) + parnum = 1; + + SEEK( 0 ); + if( READ(&dmap, sizeof(dmap)) != sizeof(dmap) ) + RET(0); + + /* partition maps might support multiple block sizes; in this case, + * pmPyPartStart is typically given in terms of 512 byte blocks. + */ + bs = dmap.sbBlockSize; + if( bs != 512 ) { + SEEK( 512 ); + READ( &par, sizeof(par) ); + if( par.pmSig == 0x504d /* 'PM' */ ) + bs = 512; + } + SEEK( bs ); + if( READ(&par, sizeof(par)) != sizeof(par) ) + RET(0); + if( parnum > par.pmMapBlkCnt || par.pmSig != 0x504d /* 'PM' */ ) + RET(0); + + SEEK( (bs * parnum) ); + READ( &par, sizeof(par) ); + + if( par.pmSig != 0x504d /* 'PM' */ || !par.pmPartBlkCnt ) + RET(0); + + di->offs = (llong)par.pmPyPartStart * bs; + di->size = (llong)par.pmPartBlkCnt * bs; + + PUSH( -1 ); +} + +/* ( block0 -- flag? ) */ +static void +macparts_probe( macparts_info_t *dummy ) +{ + desc_map_t *dmap = (desc_map_t*)POP(); + + if( dmap->sbSig != DESC_MAP_SIGNATURE ) + RET(0); + RET(-1); +} + +/* ( -- type offset.d size.d ) */ +static void +macparts_get_info( macparts_info_t *di ) +{ + PUSH( -1 ); /* no type */ + DPUSH( di->offs ); + DPUSH( di->size ); +} + +static void +macparts_initialize( macparts_info_t *di ) +{ + fword("register-partition-package"); +} + +NODE_METHODS( macparts ) = { + { "probe", macparts_probe }, + { "open", macparts_open }, + { "get-info", macparts_get_info }, + { NULL, macparts_initialize }, +}; + +void +macparts_init( void ) +{ + REGISTER_NODE( macparts ); +} diff --git a/modules/mac-parts.h b/modules/mac-parts.h new file mode 100644 index 0000000..4e09391 --- /dev/null +++ b/modules/mac-parts.h @@ -0,0 +1,72 @@ +/* + * Creation Date: <1999/07/06 15:45:12 samuel> + * Time-stamp: <2002/10/20 16:31:48 samuel> + * + * + * + * Headers describing the partition table + * + * Copyright (C) 1999, 2002 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_PARTITION_TABLE +#define _H_PARTITION_TABLE + +/* This information is based upon IM vol V. */ + +#define DESC_MAP_SIGNATURE 0x4552 + +typedef struct { + long ddBlock; /* first block of driver */ + short ddSize; /* driver size in blocks */ + short ddType; /* 1 & -1 for SCSI */ +} driver_entry_t; + +typedef struct { /* Block 0 of a device */ + short sbSig; /* always 0x4552 */ + short sbBlockSize; /* 512 */ + long sbBlkCount; /* #blocks on device */ + short sbDevType; /* 0 */ + short sbDevID; /* 0 */ + long sbData; /* 0 */ + short sbDrvrCount; /* #driver descriptors */ + + /* driver entries goes here */ + driver_entry_t drivers[61] __attribute__ ((packed)); + + short filler1; + long filler2; +} desc_map_t; + +typedef struct { /* Partition descriptor */ + short pmSig; /* always 0x504d 'PM' */ + short pmSigPad; /* 0 */ + ulong pmMapBlkCnt; /* #blocks in partition map */ + ulong pmPyPartStart; /* first physical block of part. */ + ulong pmPartBlkCnt; /* #blocks in partition */ + char pmPartName[32]; /* partition name */ + char pmPartType[32]; /* partition type */ + + /* these fields may or may not be used */ + ulong pmLgDataStart; + ulong pmDataCnt; + ulong pmPartStatus; + ulong pmLgBootStart; + ulong pmBootSize; + ulong pmBootLoad; + ulong pmBootLoad2; + ulong pmBootEntry; + ulong pmBootEntry2; + ulong pmBootCksum; + char pmProcessor[16]; + + char filler[376]; /* might contain extra information */ +} part_entry_t; + + +#endif /* _H_PARTITION_TABLE */ diff --git a/modules/modules.h b/modules/modules.h new file mode 100644 index 0000000..78f64fc --- /dev/null +++ b/modules/modules.h @@ -0,0 +1,27 @@ +/* + * Creation Date: <2003/12/23 00:32:12 samuel> + * Time-stamp: <2003/12/28 14:47:02 samuel> + * + * + * + * Module initialization + * + * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#ifndef _H_MODULES +#define _H_MODULES + +extern void deblocker_init( void ); +extern void disklabel_init( void ); +extern void filesystem_init( void ); +extern void macparts_init( void ); +extern void pcparts_init( void ); +extern void cmdline_init( void ); + +#endif /* _H_MODULES */ diff --git a/modules/nvram.c b/modules/nvram.c new file mode 100644 index 0000000..c050c20 --- /dev/null +++ b/modules/nvram.c @@ -0,0 +1,297 @@ +/* + * Creation Date: <2003/12/01 00:26:13 samuel> + * Time-stamp: <2004/01/07 19:59:53 samuel> + * + * + * + * medium-level NVRAM handling + * + * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "openbios/nvram.h" + +#define DEF_SYSTEM_SIZE 0xc10 + +#define NV_SIG_SYSTEM 0x70 +#define NV_SIG_FREE 0x7f + + +typedef struct { + uchar signature; + uchar checksum; + uchar len_hi; + uchar len_lo; + char name[12]; + char data[0]; +} nvpart_t; + +static struct { + char *data; + int size; + + nvpart_t *config; + int config_size; +} nvram; + + +/************************************************************************/ +/* generic */ +/************************************************************************/ + +static unsigned int +nvpart_checksum( nvpart_t* hdr ) +{ + unsigned char *p = (char*)hdr; + int i, val = p[0]; + + for( i=2; i<16; i++ ) { + val += p[i]; + if( val > 255 ) + val = (val - 256 + 1) & 0xff; + } + return val; +} + +static inline int +nvpart_size( nvpart_t *p ) +{ + return (p->len_lo | ((int)p->len_hi<<8)) * 16; +} + +static int +next_nvpart( nvpart_t **p ) +{ + nvpart_t *end = (nvpart_t*)(nvram.data + nvram.size); + int len; + + if( !*p ) { + *p = (nvpart_t*)nvram.data; + return 1; + } + + if( !(len=nvpart_size(*p)) ) { + printk("invalid nvram partition length\n"); + return -1; + } + *p = (nvpart_t*)((char*)*p + len); + if( *p < end ) + return 1; + if( *p == end ) + return 0; + return -1; +} + +static void +create_free_part( char *ptr, int size ) +{ + nvpart_t *nvp = (nvpart_t*)ptr; + memset( nvp, 0, size ); + + strncpy( nvp->name, "777777777777", sizeof(nvp->name) ); + nvp->signature = NV_SIG_FREE; + nvp->len_hi = (size /16) >> 8; + nvp->len_lo = size /16; + nvp->checksum = nvpart_checksum(nvp); +} + +static int +create_nv_part( int signature, char *name, int size ) +{ + nvpart_t *p = NULL; + int fs; + + while( next_nvpart(&p) > 0 ) { + if( p->signature != NV_SIG_FREE ) + continue; + + fs = nvpart_size( p ); + if( fs < size ) + size = fs; + p->signature = signature; + memset( p->name, 0, sizeof(p->name) ); + strncpy( p->name, name, sizeof(p->name) ); + p->len_hi = (size>>8)/16; + p->len_lo = size/16; + p->checksum = nvpart_checksum(p); + if( fs > size ) { + char *fp = (char*)p + size; + create_free_part( fp, fs-size ); + } + return size; + } + printk("create-failed\n"); + return -1; +} + +static void +zap_nvram( void ) +{ + create_free_part( nvram.data, nvram.size ); + create_nv_part( NV_SIG_SYSTEM, "common", DEF_SYSTEM_SIZE ); +} + +#if 0 +static void +show_partitions( void ) +{ + nvpart_t *p = NULL; + char buf[13]; + + while( next_nvpart(&p) > 0 ) { + memcpy( buf, p->name, sizeof(p->name) ); + buf[12] = 0; + printk("[%02x] %-13s: %03x\n", + p->signature, buf, nvpart_size(p)); + } +} +#endif + +void +update_nvram( void ) +{ + PUSH( (ucell)nvram.config->data ); + PUSH( nvram.config_size ); + fword("nvram-store-configs"); + arch_nvram_put( nvram.data ); +} + +static void +nvconf_init( void ) +{ + int once=0; + + /* initialize nvram structure completely */ + nvram.config = NULL; + nvram.config_size = 0; + + nvram.size = arch_nvram_size(); + nvram.data = malloc( nvram.size ); + arch_nvram_get( nvram.data ); + + bind_func( "update-nvram", update_nvram ); + + for( ;; ) { + nvpart_t *p = NULL; + int err; + + while( (err=next_nvpart(&p)) > 0 ) { + if( nvpart_checksum(p) != p->checksum ) { + err = -1; + break; + } + if( p->signature == NV_SIG_SYSTEM ) { + nvram.config = p; + nvram.config_size = nvpart_size(p) - 0x10; + + if( !once++ ) { + PUSH( (ucell)p->data ); + PUSH( nvram.config_size ); + fword("nvram-load-configs"); + } + } + } + if( err || !nvram.config ) { + printk("nvram error detected, zapping pram\n"); + zap_nvram(); + if( !once++ ) + fword("set-defaults"); + continue; + } + break; + } +} + + +/************************************************************************/ +/* nvram */ +/************************************************************************/ + +typedef struct { + uint mark_hi; + uint mark_lo; +} nvram_ibuf_t; + +DECLARE_NODE( nvram, INSTALL_OPEN, sizeof(nvram_ibuf_t), "Tnvram" ); + +/* ( pos_lo pos_hi -- status ) */ +static void +nvram_seek( nvram_ibuf_t *nd ) +{ + int pos_hi = POP(); + int pos_lo = POP(); + + /* printk("NVRAM: seek %08x %08x\n", pos_hi, pos_lo ); */ + nd->mark_lo = pos_lo; + nd->mark_hi = pos_hi; + + if( nd->mark_lo >= nvram.size ) { + PUSH(-1); + return; + } + + /* 0=success, -1=failure (1=legacy success) */ + PUSH(0); +} + +/* ( addr len -- actual ) */ +static void +nvram_read( nvram_ibuf_t *nd ) +{ + int len = POP(); + char *p = (char*)POP(); + int n=0; + + while( nd->mark_lo < nvram.size && n < len ) { + *p++ = nvram.data[nd->mark_lo++]; + n++; + } + PUSH(n); + /* printk("NVRAM: read %08x %x -- %x\n", (int)p, len, n); */ +} + +/* ( addr len -- actual ) */ +static void +nvram_write( nvram_ibuf_t *nd ) +{ + int len = POP(); + char *p = (char*)POP(); + int n=0; + + while( nd->mark_lo < nvram.size && n < len ) { + nvram.data[nd->mark_lo++] = *p++; + n++; + } + PUSH(n); + /* printk("NVRAM: write %08x %x -- %x\n", (int)p, len, n ); */ +} + +/* ( -- size ) */ +static void +nvram_size( nvram_ibuf_t *nd ) +{ + PUSH( nvram.size ); +} + +NODE_METHODS( nvram ) = { + { "size", (void*)nvram_size }, + { "read", (void*)nvram_read }, + { "write", (void*)nvram_write }, + { "seek", (void*)nvram_seek }, +}; + + +void +nvram_init( void ) +{ + nvconf_init(); + + REGISTER_NODE( nvram ); +} diff --git a/modules/pc-parts.c b/modules/pc-parts.c new file mode 100644 index 0000000..cf4da2f --- /dev/null +++ b/modules/pc-parts.c @@ -0,0 +1,205 @@ +/* + * pc partition support + * + * Copyright (C) 2004 Stefan Reinauer + * + * This code is based (and copied in many places) from + * mac partition support by Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/byteorder.h" +#include "modules.h" + +typedef struct { + ullong offs; + ullong size; +} pcparts_info_t; + +DECLARE_NODE( pcparts, INSTALL_OPEN, sizeof(pcparts_info_t), "+/packages/pc-parts" ); + + +#define SEEK( pos ) ({ DPUSH(pos); call_parent(seek_xt); POP(); }) +#define READ( buf, size ) ({ PUSH((ucell)buf); PUSH(size); call_parent(read_xt); POP(); }) + +/* two helper functions */ + +static inline int has_pc_part_magic(unsigned char *sect) +{ + return sect[510]==0x55 && sect[511]==0xAA; +} + +static inline int is_pc_extended_part(unsigned char type) +{ + return type==5 || type==0xf || type==0x85; +} + +/* ( open -- flag ) */ +static void +pcparts_open( pcparts_info_t *di ) +{ + char *str = my_args_copy(); + xt_t seek_xt = find_parent_method("seek"); + xt_t read_xt = find_parent_method("read"); + int bs, parnum=-1; + /* Layout of PC partition table */ + struct pc_partition { + unsigned char boot; + unsigned char head; + unsigned char sector; + unsigned char cyl; + unsigned char type; + unsigned char e_head; + unsigned char e_sector; + unsigned char e_cyl; + unsigned char start_sect[4]; /* unaligned little endian */ + unsigned char nr_sects[4]; /* ditto */ + } *p; + unsigned char buf[512]; + + /* printk("pcparts_open '%s'\n", str ); */ + + if( str ) { + parnum = atol(str); + if( !strlen(str) ) + parnum = 1; + free( str ); + } + if( parnum < 0 ) + parnum = 1; + + SEEK( 0 ); + if( READ(buf, 512) != 512 ) + RET(0); + + /* Check Magic */ + if (!has_pc_part_magic(buf)) { + printk("pc partition magic not found.\n"); + RET(0); + } + + /* get partition data */ + p = (struct pc_partition *) (buf + 0x1be); + + bs=512; + + if (parnum < 4) { + /* primary partition */ + p += parnum; + if (p->type==0 || is_pc_extended_part(p->type)) { + printk("partition %d does not exist\n", parnum+1 ); + RET( 0 ); + } + di->offs = (llong)(__le32_to_cpu(*((u32 *)p->start_sect))) * bs; + di->size = (llong)(__le32_to_cpu(*((u32 *)p->nr_sects))) * bs; + + /* printk("Primary partition at sector %x\n", + __le32_to_cpu(*((u32 *)p->start_sect))); */ + + RET( -1 ); + } else { + /* Extended partition */ + int i, cur_part; + unsigned long ext_start, cur_table; + + /* Search for the extended partition + * which contains logical partitions */ + for (i = 0; i < 4; i++) { + if (is_pc_extended_part(p[i].type)) + break; + } + + if (i >= 4) { + printk("Extended partition not found\n"); + RET( 0 ); + } + + printk("Extended partition at %d\n", i+1); + + /* Visit each logical partition labels */ + ext_start = __le32_to_cpu(*((u32 *)p[i].start_sect)); + cur_table = ext_start; + cur_part = 4; + + for (;;) { + /* printk("cur_part=%d at %x\n", cur_part, cur_table); */ + + SEEK( cur_table*bs ); + if( READ(buf, sizeof(512)) != sizeof(512) ) + RET( 0 ); + + if (!has_pc_part_magic(buf)) { + printk("Extended partition has no magic\n"); + break; + } + + p = (struct pc_partition *) (buf + 0x1be); + /* First entry is the logical partition */ + if (cur_part == parnum) { + if (p->type==0) { + printk("Partition %d is empty\n", parnum+1); + RET( 0 ); + } + di->offs = + (llong)(cur_table+__le32_to_cpu(*((u32 *)p->start_sect))) * bs; + di->size = (llong)__le32_to_cpu(*((u32 *)p->nr_sects)) * bs; + RET ( -1 ); + } + + /* Second entry is link to next partition */ + if (!is_pc_extended_part(p[1].type)) { + printk("no link\n"); + break; + } + cur_table = ext_start + __le32_to_cpu(*((u32 *)p[1].start_sect)); + + cur_part++; + } + printk("Logical partition %d does not exist\n", parnum+1); + RET( 0 ); + } + /* we should never reach this point */ +} + +/* ( block0 -- flag? ) */ +static void +pcparts_probe( pcparts_info_t *dummy ) +{ + unsigned char *buf = (unsigned char *)POP(); + + RET ( has_pc_part_magic(buf) ); +} + +/* ( -- type offset.d size.d ) */ +static void +pcparts_get_info( pcparts_info_t *di ) +{ + PUSH( -1 ); /* no type */ + DPUSH( di->offs ); + DPUSH( di->size ); +} + +static void +pcparts_initialize( pcparts_info_t *di ) +{ + fword("register-partition-package"); +} + +NODE_METHODS( pcparts ) = { + { "probe", pcparts_probe }, + { "open", pcparts_open }, + { "get-info", pcparts_get_info }, + { NULL, pcparts_initialize }, +}; + +void +pcparts_init( void ) +{ + REGISTER_NODE( pcparts ); +} diff --git a/modules/support.fs b/modules/support.fs new file mode 100644 index 0000000..b189536 --- /dev/null +++ b/modules/support.fs @@ -0,0 +1,124 @@ +\ tag: Utility functions +\ +\ deblocker / filesystem support +\ +\ Copyright (C) 2003, 2004 Samuel Rydh +\ +\ See the file "COPYING" for further information about +\ the copyright and warranty status of this work. +\ + +dev /packages + +\ ------------------------------------------------------------- +\ /packages/disk-label (partition handling) +\ ------------------------------------------------------------- + +[IFDEF] CONFIG_DISK_LABEL + +new-device + " disk-label" device-name + external + + variable part-handlers \ list with (probe-xt, phandle) elements + variable fs-handlers \ list with (fs-probe-xt, phandle) elements + + : find-part-handler ( block0 -- phandle | 0 ) + >r part-handlers + begin list-get while + ( nextlist dictptr ) + r@ over @ execute if + ( nextlist dictptr ) + na1+ @ r> rot 2drop exit + then + drop + repeat + r> drop 0 + ; + + : find-filesystem ( ih -- ph | 0 ) + >r fs-handlers + begin list-get while + ( nextlist dictptr ) + r@ over @ execute if + ( nextlist dictptr ) + na1+ @ r> rot 2drop exit + then + drop + repeat + r> drop 0 + ; + + : register-part-handler ( handler-ph -- ) + dup " probe" rot find-method + 0= abort" Missing probe method!" + ( phandle probe-xt ) + part-handlers list-add , , + ; + + : register-fs-handler ( handler-ph -- ) + dup " probe" rot find-method + 0= abort" Missing probe method!" + ( phandle probe-xt ) + fs-handlers list-add , , + ; +finish-device + +\ --------------------------------------------------------------------------- +\ methods to register partion and filesystem packages used by disk-label +\ --------------------------------------------------------------------------- + +device-end +: register-partition-package ( -- ) + " register-part-handler" " disk-label" $find-package-method ?dup if + active-package swap execute + else + ." [disk-label] internal error" cr + then +; + +: register-fs-package ( -- ) + " register-fs-handler" " disk-label" $find-package-method ?dup if + active-package swap execute + else + ." [misc-files] internal error" cr + then +; + +[THEN] +device-end + + +\ ------------------------------------------------------------- +\ command line editor (/packages/cmdline) +\ ------------------------------------------------------------- + +[IFDEF] CONFIG_CMDLINE + +dev /packages +new-device + " cmdline" device-name + + :noname + " " [active-package], open-package + ?dup if + " cmdline" rot $call-method + else + ." cmdline is missing!" cr + then + \ cmdline must close itself upon return + ; + + :noname + [ ['] (lit) , swap , ] to outer-interpreter + ; SYSTEM-initializer + + external + : prepare 0 to my-self ; + +finish-device + +[THEN] + + +device-end diff --git a/modules/video.c b/modules/video.c new file mode 100644 index 0000000..11ff718 --- /dev/null +++ b/modules/video.c @@ -0,0 +1,290 @@ +/* + * Creation Date: <2002/10/23 20:26:40 samuel> + * Time-stamp: <2004/01/07 19:39:15 samuel> + * + * + * + * Mac-on-Linux display node + * + * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/diskio.h" +#include "ofmem.h" + +static struct { + int has_video; + osi_fb_info_t fb; + ulong *pal; /* 256 elements */ +} video; + + +int +video_get_res( int *w, int *h ) +{ + if( !video.has_video ) { + *w = *h = 0; + return -1; + } + *w = video.fb.w; + *h = video.fb.h; + return 0; +} + +static void +startup_splash( void ) +{ + int fd, s, i, y, x, dx, dy; + int width, height; + char *pp, *p; + char buf[64]; + + /* only draw logo in 24-bit mode (for now) */ + if( video.fb.depth < 15 ) + return; +#ifdef CONFIG_MOL + for( i=0; i<2; i++ ) { + if( !BootHGetStrResInd("bootlogo", buf, sizeof(buf), 0, i) ) + return; + *(!i ? &width : &height) = atol(buf); + } + + if( (s=width * height * 3) > 0x20000 ) + return; + + if( (fd=open_io("pseudo:,bootlogo")) >= 0 ) { + p = malloc( s ); + if( read_io(fd, p, s) != s ) + printk("bootlogo size error\n"); + close_io( fd ); + + dx = (video.fb.w - width)/2; + dy = (video.fb.h - height)/3; + + pp = (char*)video.fb.mphys + dy * video.fb.rb + dx * (video.fb.depth >= 24 ? 4 : 2); + + for( y=0 ; y= 24 ) { + ulong *d = (ulong*)pp; + for( x=0; x>9) & 0x7c00) | ((col>>6) & 0x03e0) | ((col>>3) & 0x1f); + } + } + } + free( p ); + } +#else + /* No bootlogo support yet on other platforms */ + return; +#endif +} + +static ulong +get_color( int col_ind ) +{ + ulong col; + if( !video.has_video || col_ind < 0 || col_ind > 255 ) + return 0; + if( video.fb.depth == 8 ) + return col_ind; + col = video.pal[col_ind]; + if( video.fb.depth == 24 || video.fb.depth == 32 ) + return col; + if( video.fb.depth == 15 ) + return ((col>>9) & 0x7c00) | ((col>>6) & 0x03e0) | ((col>>3) & 0x1f); + return 0; +} + +void +draw_pixel( int x, int y, int colind ) +{ + char *p = (char*)video.fb.mphys + video.fb.rb * y; + int color, d = video.fb.depth; + + if( x < 0 || y < 0 || x >= video.fb.w || y >=video.fb.h ) + return; + color = get_color( colind ); + + if( d >= 24 ) + *((ulong*)p + x) = color; + else if( d >= 15 ) + *((short*)p + x) = color; + else + *(p + x) = color; +} + +static void +fill_rect( int col_ind, int x, int y, int w, int h ) +{ + char *pp; + ulong col = get_color(col_ind); + + if( !video.has_video || x < 0 || y < 0 || x+w > video.fb.w || y+h > video.fb.h ) + return; + + pp = (char*)video.fb.mphys + video.fb.rb * y; + for( ; h--; pp += video.fb.rb ) { + int ww = w; + if( video.fb.depth == 24 || video.fb.depth == 32 ) { + ulong *p = (ulong*)pp + x; + while( ww-- ) + *p++ = col; + } else if( video.fb.depth == 16 || video.fb.depth == 15 ) { + ushort *p = (ushort*)pp + x; + while( ww-- ) + *p++ = col; + } else { + char *p = (char*)pp + x; + while( ww-- ) + *p++ = col; + } + } +} + +static void +refresh_palette( void ) +{ +#ifdef CONFIG_MOL + if( video.fb.depth == 8 ) + OSI_RefreshPalette(); +#endif +} + +void +set_color( int ind, ulong color ) +{ + if( !video.has_video || ind < 0 || ind > 255 ) + return; + video.pal[ind] = color; + +#ifdef CONFIG_MOL + if( video.fb.depth == 8 ) + OSI_SetColor( ind, color ); +#endif +} + + +/************************************************************************/ +/* OF methods */ +/************************************************************************/ + +DECLARE_NODE( video, INSTALL_OPEN, 0, "Tdisplay" ); + +/* ( -- width height ) (?) */ +static void +video_dimensions( void ) +{ + int w, h; + (void) video_get_res( &w, &h ); + PUSH( w ); + PUSH( h ); +} + +/* ( table start count -- ) (?) */ +static void +video_set_colors( void ) +{ + int count = POP(); + int start = POP(); + uchar *p = (uchar*)POP(); + int i; + + for( i=0; i + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/toke/ChangeLog b/toke/ChangeLog new file mode 100644 index 0000000..8698b6f --- /dev/null +++ b/toke/ChangeLog @@ -0,0 +1,141 @@ +*** 0.6.10 (release) - 2005/10/15 *************************************** + + * fix hex parsing in strings. Reported by Arti Itra. + +*** 0.6.9 (release) - 2005/10/05 **************************************** + + * Bail out with an error if the maximum word count is exceeded. + * fix bug in endcase that limited fcode output size to 32k. Thanks to + Prasana Kumar for reporting this. + * Update FSF address. + +*** 0.6.8 (release) - 2005/03/10 **************************************** + + * fcode numbers have been reset to 0x800 when using the + fload directive. Fixed. + * Add makefile to compile as an extra release + +******************* 2005/01/02 ****************************************** + + * drop endian.h/mconfig.h dependency + +******************* 2004/06/19 ****************************************** + + * fix off by one error in s" + +******************* 2004/06/10 ****************************************** + + * fix big endian problem in pci header generation. + * add pci-code-revision (same as pci-revision) + +******************* 2004/04/23 ****************************************** + + * remove silly warning again + * other minor changes and bug fixes have been included + +******************* 2003/12/13 ****************************************** + + * fix emission of device class in pci headers + * add encode-file keyword + * add interpose fcode + +*** 0.6 (release) - 2003/11/28 ****************************************** + + * make lots of functions and variables static + * update email address + * handle big output files right + * clean up pci header code. + * add pci-header-end, set-rev-level for compatibility + to firmworks tokenizer. + * fix string escape handling + +******************* 2003/08/16 ****************************************** + + * fit Makefile into openbios build process (allows out of place build) + * fix address error in emit.c + +******************* 2002/07/18 ****************************************** + + * implement FCODE-VERSION1 and FCODE-VERSION3 (used by SUN's tokenizer) + * fix uneven embedded hex message for " "(00 FF FF FF FF FF FF 00)" + +******************* 2002/07/16 ****************************************** + + * implement PCI-REVISION, NOT-LAST-IMAGE + * implement FCODE-TIME and FCODE-DATE + * fix header fixup + * add dependencies to Makefile + * align to 512byte if we have a PCI header + * use 128k output buffer per default. + * rename example suffix to .fs + * add version1.fs, date.fs, pciexample.fs to examples + +******************* 2002/07/15 ****************************************** + + * fix CHAR/[CHAR] warnings. + * remove some debugging from stack.c + * some more line number fixes. + * compile with -pedantic on gcc systems + * fix header generation. + +******************* 2002/07/12 ****************************************** + + * move offs16 to scanner.c + * generate version1 header correctly and switch + to 8bit offsets when it's detected. + * let offset16 emit it's fcode# as well + * implement PCI-HEADER + + +******************* 2002/07/11 ****************************************** + + * add CHAR and [CHAR] + * change BUFFER to BUFFER: + * add H.7 renamed fcode words as macros + * add sample scsi driver package from IEEE 1275-1994 + * new function emit_token supersedes emit_fcode(lookup_token()) + +*** 0.4 (release) - 2002/05/24 ****************************************** + + * remove if..then from abort" (conditionally) + * fix linked list juggling in case..endcase constructs + +******************* 2002/05/22 ****************************************** + + * fix get_word() not to read beyound end of strings + * more adequate implementation of abort" + +******************* 2002/03/27 ****************************************** + + * add name and endif macro + * fix typo in finish-device, new-device + * use new number parsing function to handle dots. + * do proper handling of hex values embedded in strings. + * reset fcode word number counter when compiling multiple files. + +******************* 2002/03/21 ****************************************** + + * some IEEE 1275 compliance changes (forbid definitions in definitions) + * fix macros + * fix hex, octal, decimal inside colon definitions + +*** 0.2a (bugfix) - 2002/03/21 ****************************************** + + * fix off by one bug in string escape codes + * fix line number calculation + * do proper debugging output + +*** 0.2 (release) - 2002/03/20 ****************************************** + + * implemented (most of the) missing control words + * implemented next-fcode tokenizer directive + * implemented line numbers for errors and warnings. + * improved string handling. + * stop on errors by default. + * use case insensitive dictionary lookup. + * lots of debug made compile time conditional + +*** 0.1 (release) - 2002/03/04 ****************************************** + + * initial release + diff --git a/toke/Makefile b/toke/Makefile new file mode 100644 index 0000000..547a889 --- /dev/null +++ b/toke/Makefile @@ -0,0 +1,72 @@ +# +# OpenBIOS - free your system! +# ( FCode tokenizer ) +# +# This program is part of a free implementation of the IEEE 1275-1994 +# Standard for Boot (Initialization Configuration) Firmware. +# +# Copyright (C) 2001-2005 Stefan Reinauer, +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA +# + +ARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/) +TOPDIR := $(shell /bin/pwd) +BUILDDIR ?= $(TOPDIR)/obj-$(ARCH) +VPATH := $(BUILDDIR) + +include $(TOPDIR)/Rules.make + +CC = gcc +CFLAGS = -O2 -Wall -W -ansi -pedantic +# CFLAGS = -O -g -Wall -ansi -pedantic + +# CFLAGS := $(CFLAGS) -DDEBUG_SCANNER +# CFLAGS := $(CFLAGS) -DDEBUG_DSTACK + +OBJECTS= toke.o stack.o stream.o dictionary.o macros.o scanner.o emit.o + +.SUFFIXES: .c .o + +all: main toke + @cd $(BUILDDIR) && strip toke + @echo -e "\nOpenBIOS tokenizer toke build finished\n" + +# main should go to rules.make +main: + @echo -e "\nWelcome to toke, the OpenBIOS fcode tokenizer.." + @test -r $(BUILDDIR) || ( mkdir -p $(BUILDDIR); \ + echo -e "\nCreating build directory $(BUILDDIR)" ) + +toke: $(OBJECTS) + @echo -n " linking tokenizer executable... " + @cd $(BUILDDIR) && $(CC) $(CFLAGS) -o $@ $^ + @echo -e "\tok" + +clean: + @test ! -d $(BUILDDIR) && \ + echo "Architecture $(ARCH) is already clean." || \ + ( \ + echo "Cleaning up architecture $(ARCH)"; \ + rm -rf $(BUILDDIR) \ + rm forth.dict.core \ + ) + +toke.o: toke.c toke.h stack.h stream.h emit.h +dictionary.o: dictionary.c toke.h dictionary.h +emit.o: emit.c toke.h stack.h +macros.o: macros.c toke.h +scanner.o: scanner.c toke.h stack.h stream.h dictionary.h +stack.o: stack.c toke.h stack.h +stream.o: stream.c toke.h diff --git a/toke/README b/toke/README new file mode 100644 index 0000000..9c044bc --- /dev/null +++ b/toke/README @@ -0,0 +1,212 @@ +Welcome to the OpenBIOS tokenizer Toke. + +This README provides you with a short description of the tokenizer and +of how to use it. + +--------------------------------------------------------------------- + +Table of contents: + +1. What is the OpenBIOS tokenizer? +2. What is required to build the OpenBIOS tokenizer? +3. How to use the OpenBIOS tokenizer +4. Toke's Special Features not described in IEEE 1275-1994 +5. Text Strings +6. Contact + +--------------------------------------------------------------------- + +1. What is the OpenBIOS tokenizer? + + toke is a GPLed FCode tokenizer. It can tokenize (assemble) fcode + source to bytecode files as described by the IEEE 1275-1994 standard. + + This program is compliant to IEEE 1275-1994. + + Bytecode files normally contain Open Firmware drivers or other + packages for use with an Open Firmware compliant system. + + +2. What is required to build the OpenBIOS tokenizer? + + toke should build with any ANSI compliant C compiler. + + For building toke on certain platforms you might have to adjust the + Makefile. If so, please contact Stefan Reinauer + + Build toke by just enter "make". To clean up an existing build, + use "make clean" or "make distclean" + + +3. How to use the OpenBIOS tokenizer + + tokenize an fcode source file with + toke [-v|--verbose] [-i|--ignore-errors] [] + + Get help with: + toke [-h|--help] + + The file extension will be changed to .fc. If no file extension + exists, .fc will be appended. If -i is specified, toke continues + on errors, producing invalid fcode binaries. + + +4. Toke's Special Features not described in IEEE 1275-1994 + + In addition to the standard Open Firmware words, some additional + commands have been added to make life easier and for compatibility + to other, mostly commercial, fcode tokenizers. These are: + +4.1 NEXT-FCODE + + In tokenizer[ .. ]tokenizer context there is an additional control + word besides emit-byte: next-fcode. It sets the increasing fcode + number used to emit new fcode words to the specified value. Thus + allowing sparse fcode numbering and overwriting previously defined + fcode words. + + This could look like: + ------------------------------------------- + \ next emitted fcode is 0x053, 2dup. + tokenizer[ 053 next-fcode ]tokenizer + \ now define the word. + : 2dup over over ; + ------------------------------------------- + + Note: Toke is capable of creating fcode files that implement words + defined by the IEEE 1275-1994 standard itself. This is not necessarily + supported by every Open Firmware implementation. + + +4.2 FCODE-VERSION2 + + This word generates an FCode header using START1. It should be used + with FCODE-END. + + +4.3 FCODE-END + + This word creates an END0 FCode and fixes up the FCode header + information. Use this with FCODE-VERSION2 + + +4.4 PCI-HEADER + + This word creates a PCI option ROM header. PCI-HEADER expects 3 + values on the top of the stack when it is invoked: Vendor#, Device# + and Class-Code. + + These values are used for the according fields in the PCI Data + structure that is emitted by PCI-HEADER. To include these values + put them on the stack with TOKENIZER[ and ]TOKENIZER. + + +4.5 PCI-END / PCI-HEADER-END + + This word completes the PCI header created by PCI-HEADER. It fills out + the image to a multiple of 512 bytes, and sets the missing values in + the PCI header (image-length, revision). + + Example: + HEX + TOKENIZER[ 1234 5678 ABCDEF ]TOKENIZER + PCI-HEADER \ generate PCI option rom header + FCODE-VERSION2 \ generate FCode header (within PCI image) + ... + ... + FCODE-END \ terminate FCode in image + PCI-END \ complete the PCI header and image. + + +4.6 PCI-REVISION / SET-REV-LEVEL + + Use this word to change the revision field of the PCI header. Like + PCI-HEADER, PCI-REVISION takes it's value from the stack. You can + write: TOKENIZER[ 23 ]TOKENIZER PCI-REVISION + + +4.7 NOT-LAST-IMAGE + + Normally Toke assumes that a PCI image generated by PCI-HEADER is + the only ROM image in the (EEP)ROM it will be written to. With + NOT-LAST-IMAGE Toke sets a flag in the PCI header that other images + will follow in the same ROM. + + +4.8 FCODE-DATE + + FCODE-DATE creates an FCode string that contains the date of the + tokenization. This string could be used to create a device tree + property that can be inspected by drivers, etc. to check when the + image was created. The format of the string emitted by FCODE-DATE + is MM/DD.YYYY + + +4.9 FCODE-TIME + + FCODE-TIME creates an FCode string that contains the time of the + tokenization. This string could be used to create a device tree + property that can be inspected by drivers, etc. to check when the + image was created. The format of the string emitted by FCODE-TIME + is HH:MM:SS + + +4.10 ENCODE-FILE + + encode a binary file. Use as: encode-file filename + + +5. Text Strings + + From "Writing FCode": + Escape Sequences in Text Strings + + ----------------------------------------------------------- + Syntax Function + ----------------------------------------------------------- + "" quote (") + "n newline + "r carriage return + "t tab + "f formfeed + "l linefeed + "b backspace + "! bell + "^x control x, where x is any printable + character + "(hh hh) Sequence of bytes, one byte for each pair + of hex digits hh . Non-hex characters will + be ignored + + " followed by any other printable character not mentioned + above is equivalent to that character. + + "( means to start parsing pairs of hexadecimal digits as + one or more 8-bit characters in the range 0x00 through + 0xFF, delimited by a trailing ) and ignoring + non-hexadecimal digits between pairs of hexadecimal + digits. Both uppercase and lowercase hexadecimal digits are + recognized. Since non-hex characters (such as space or + comma) are ignored between "( and ), these characters make + useful delimiters. (The "makearray" tool can be used in + conjunction with this syntax to easily incorporate large + binary data fields into any FCode Program.) + + Any characters thus recognized are appended to any previous + text in the string being assembled. After the ) is + recognized, text assembly continues until a trailing + ". + + For example: + + " This is "(01 32,8e)abc"nA test! "!"! abcd""hijk"^bl" + ^^^^^^^^ ^ ^ ^ ^ ^ + 3 bytes newline 2 bells " control b + +6. Contact + + Ideas, bug reports, patches, contributions are welcome. + + Stefan Reinauer + + diff --git a/toke/Rules.make b/toke/Rules.make new file mode 100644 index 0000000..db82ed6 --- /dev/null +++ b/toke/Rules.make @@ -0,0 +1,17 @@ +# tag: Makefile rules + +VPATH := $(VPATH):. + +.S.o: + echo -n " assembling $<... " + $(CC) -c -nostdlib $(INCLUDES) $(CFLAGS) $< -o $(BUILDDIR)/$@ && \ + echo -e " \t\tok" || \ + echo -e " \t\tfailed" + +.c.o: + @echo -n " compiling $<... " + @$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILDDIR)/$@ && \ + echo -e " \t\tok" || \ + echo -e " \t\failed" + + diff --git a/toke/build.xml b/toke/build.xml new file mode 100644 index 0000000..d59e49a --- /dev/null +++ b/toke/build.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/toke/dictionary.c b/toke/dictionary.c new file mode 100644 index 0000000..112c3c2 --- /dev/null +++ b/toke/dictionary.c @@ -0,0 +1,574 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * dictionary.c - dictionary initialization and functions. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#if defined(__linux__) && ! defined(__USE_BSD) +#define __USE_BSD +#endif +#include +#include + +#include "toke.h" +#include "dictionary.h" + +typedef struct token { + u8 *name; + u16 fcode; + struct token *next; +} token_t; + +static token_t *dictionary=NULL; +static token_t *forthwords=NULL; + +static u16 lookup_token_dict(char *name, token_t *dict) +{ + token_t *curr; + + for (curr=dict; curr!=NULL; curr=curr->next) + if (!strcasecmp(name,(char *)curr->name)) + break; + + if (curr) + return curr->fcode; +#ifdef DEBUG_TOKE + printf("warning: token '%s' does not exist.\n", name); +#endif + return 0xffff; +} + +u16 lookup_token(char *name) +{ + return lookup_token_dict(name, dictionary); +} + +u16 lookup_fword(char *name) +{ + return lookup_token_dict(name, forthwords); +} + +static int add_token_dict(u16 number, char *name, token_t **dict) +{ + token_t *curr; + + curr=malloc(sizeof(token_t)); + if(!curr) { + printf("Out of memory while adding token.\n"); + exit(-ENOMEM); + } + + curr->next=*dict; + curr->fcode=number; + curr->name=(u8 *)name; + + *dict=curr; + return 0; +} + +int add_token(u16 number, char *name) +{ + return add_token_dict(number, name, &dictionary); +} + +static int add_special(u16 number, char *name) +{ + return add_token_dict(number, name, &forthwords); +} + +void init_dictionary(void) +{ + add_token( 0x000, "end0" ); + add_token( 0x010, "b(lit)" ); + add_token( 0x011, "b(')" ); + add_token( 0x012, "b(\")" ); + add_token( 0x013, "bbranch" ); + add_token( 0x014, "b?branch" ); + add_token( 0x015, "b(loop)" ); + add_token( 0x016, "b(+loop)" ); + add_token( 0x017, "b(do)" ); + add_token( 0x018, "b(?do)" ); + add_token( 0x019, "i" ); + add_token( 0x01a, "j" ); + add_token( 0x01b, "b(leave)" ); + add_token( 0x01c, "b(of)" ); + add_token( 0x01d, "execute" ); + add_token( 0x01e, "+" ); + add_token( 0x01f, "-" ); + add_token( 0x020, "*" ); + add_token( 0x021, "/" ); + add_token( 0x022, "mod" ); + add_token( 0x023, "and" ); + add_token( 0x024, "or" ); + add_token( 0x025, "xor" ); + add_token( 0x026, "invert" ); + add_token( 0x027, "lshift" ); + add_token( 0x028, "rshift" ); + add_token( 0x029, ">>a" ); + add_token( 0x02a, "/mod" ); + add_token( 0x02b, "u/mod" ); + add_token( 0x02c, "negate" ); + add_token( 0x02d, "abs" ); + add_token( 0x02e, "min" ); + add_token( 0x02f, "max" ); + add_token( 0x030, ">r" ); + add_token( 0x031, "r>" ); + add_token( 0x032, "r@" ); + add_token( 0x033, "exit" ); + add_token( 0x034, "0=" ); + add_token( 0x035, "0<>" ); + add_token( 0x036, "0<" ); + add_token( 0x037, "0<=" ); + add_token( 0x038, "0>" ); + add_token( 0x039, "0>=" ); + add_token( 0x03a, "<" ); + add_token( 0x03b, ">" ); + add_token( 0x03c, "=" ); + add_token( 0x03d, "<>" ); + add_token( 0x03e, "u>" ); + add_token( 0x03f, "u<=" ); + add_token( 0x040, "u<" ); + add_token( 0x041, "u>=" ); + add_token( 0x042, ">=" ); + add_token( 0x043, "<=" ); + add_token( 0x044, "between" ); + add_token( 0x045, "within" ); + add_token( 0x046, "drop" ); + add_token( 0x047, "dup" ); + add_token( 0x048, "over" ); + add_token( 0x049, "swap" ); + add_token( 0x04A, "rot" ); + add_token( 0x04b, "-rot" ); + add_token( 0x04c, "tuck" ); + add_token( 0x04d, "nip" ); + add_token( 0x04e, "pick" ); + add_token( 0x04f, "roll" ); + add_token( 0x050, "?dup" ); + add_token( 0x051, "depth" ); + add_token( 0x052, "2drop" ); + add_token( 0x053, "2dup" ); + add_token( 0x054, "2over" ); + add_token( 0x055, "2swap" ); + add_token( 0x056, "2rot" ); + add_token( 0x057, "2/" ); + add_token( 0x058, "u2/" ); + add_token( 0x059, "2*" ); + add_token( 0x05a, "/c" ); + add_token( 0x05b, "/w" ); + add_token( 0x05c, "/l" ); + add_token( 0x05d, "/n" ); + add_token( 0x05e, "ca+" ); + add_token( 0x05f, "wa+" ); + add_token( 0x060, "la+" ); + add_token( 0x061, "na+" ); + add_token( 0x062, "char+" ); + add_token( 0x063, "wa1+" ); + add_token( 0x064, "la1+" ); + add_token( 0x065, "cell+" ); + add_token( 0x066, "chars" ); + add_token( 0x067, "/w*" ); + add_token( 0x068, "/l*" ); + add_token( 0x069, "cells" ); + add_token( 0x06a, "on" ); + add_token( 0x06b, "off" ); + add_token( 0x06c, "+!" ); + add_token( 0x06d, "@" ); + add_token( 0x06e, "l@" ); + add_token( 0x06f, "w@" ); + add_token( 0x070, "" ); + add_token( 0x086, ">body" ); + add_token( 0x087, "fcode-revision" ); + add_token( 0x088, "span" ); + add_token( 0x089, "unloop" ); + add_token( 0x08a, "expect" ); + add_token( 0x08b, "alloc-mem" ); + add_token( 0x08c, "free-mem" ); + add_token( 0x08d, "key?" ); + add_token( 0x08e, "key" ); + add_token( 0x08f, "emit" ); + add_token( 0x090, "type" ); + add_token( 0x091, "(cr" ); + add_token( 0x092, "cr" ); + add_token( 0x093, "#out" ); + add_token( 0x094, "#line" ); + add_token( 0x095, "hold" ); + add_token( 0x096, "<#" ); + add_token( 0x097, "u#>" ); + add_token( 0x098, "sign" ); + add_token( 0x099, "u#" ); + add_token( 0x09a, "u#s" ); + add_token( 0x09b, "u." ); + add_token( 0x09c, "u.r" ); + add_token( 0x09d, "." ); + add_token( 0x09e, ".r" ); + add_token( 0x09f, ".s" ); + add_token( 0x0a0, "base" ); + add_token( 0x0a1, "convert" ); + add_token( 0x0a2, "$number" ); + add_token( 0x0a3, "digit" ); + add_token( 0x0a4, "-1" ); + add_token( 0x0a5, "0" ); + add_token( 0x0a6, "1" ); + add_token( 0x0a7, "2" ); + add_token( 0x0a8, "3" ); + add_token( 0x0a9, "bl" ); + add_token( 0x0aa, "bs" ); + add_token( 0x0ab, "bell" ); + add_token( 0x0ac, "bounds" ); + add_token( 0x0ad, "here" ); + add_token( 0x0ae, "aligned" ); + add_token( 0x0af, "wbsplit" ); + add_token( 0x0b0, "bwjoin" ); + add_token( 0x0b1, "b(resolve)" ); + add_token( 0x0b3, "set-token-table" ); + add_token( 0x0b4, "set-table" ); + add_token( 0x0b5, "new-token" ); + add_token( 0x0b6, "named-token" ); + add_token( 0x0b7, "b(:)" ); + add_token( 0x0b8, "b(value)" ); + add_token( 0x0b9, "b(variable)" ); + add_token( 0x0ba, "b(constant)" ); + add_token( 0x0bb, "b(create)" ); + add_token( 0x0bc, "b(defer)" ); + add_token( 0x0bd, "b(buffer:)" ); + add_token( 0x0be, "b(field)" ); + add_token( 0x0bf, "b(code)" ); + add_token( 0x0c0, "instance" ); + add_token( 0x0c2, "b(;)" ); + add_token( 0x0c3, "b(to)" ); + add_token( 0x0c4, "b(case)" ); + add_token( 0x0c5, "b(endcase)" ); + add_token( 0x0c6, "b(endof)" ); + add_token( 0x0c7, "#" ); + add_token( 0x0c8, "#s" ); + add_token( 0x0c9, "#>" ); + add_token( 0x0ca, "external-token" ); + add_token( 0x0cb, "$find" ); + add_token( 0x0cc, "offset16" ); + add_token( 0x0cd, "evaluate" ); + add_token( 0x0d0, "c," ); + add_token( 0x0d1, "w," ); + add_token( 0x0d2, "l," ); + add_token( 0x0d3, "," ); + add_token( 0x0d4, "um*" ); + add_token( 0x0d5, "um/mod" ); + add_token( 0x0d8, "d+" ); + add_token( 0x0d9, "d-" ); + add_token( 0x0da, "get-token" ); + add_token( 0x0db, "set-token" ); + add_token( 0x0dc, "state" ); + add_token( 0x0dd, "compile" ); + add_token( 0x0de, "behavior" ); + add_token( 0x0f0, "start0" ); + add_token( 0x0f1, "start1" ); + add_token( 0x0f2, "start2" ); + add_token( 0x0f3, "start4" ); + add_token( 0x0fc, "ferror" ); + add_token( 0x0fd, "version1" ); + add_token( 0x0fe, "4-byte-id" ); + add_token( 0x0ff, "end1" ); + add_token( 0x101, "dma-alloc" ); + add_token( 0x102, "my-address" ); + add_token( 0x103, "my-space" ); + add_token( 0x104, "memmap" ); + add_token( 0x105, "free-virtual" ); + add_token( 0x106, ">physical" ); + add_token( 0x10f, "my-params" ); + add_token( 0x110, "property" ); + add_token( 0x111, "encode-int" ); + add_token( 0x112, "encode+" ); + add_token( 0x113, "encode-phys" ); + add_token( 0x114, "encode-string" ); + add_token( 0x115, "encode-bytes" ); + add_token( 0x116, "reg" ); + add_token( 0x117, "intr" ); + add_token( 0x118, "driver" ); + add_token( 0x119, "model" ); + add_token( 0x11a, "device-type" ); + add_token( 0x11b, "parse-2int" ); + add_token( 0x11c, "is-install" ); + add_token( 0x11d, "is-remove" ); + add_token( 0x11e, "is-selftest" ); + add_token( 0x11f, "new-device" ); + add_token( 0x120, "diagnostic-mode?" ); + add_token( 0x121, "display-status" ); + add_token( 0x122, "memory-test-issue" ); + add_token( 0x123, "group-code" ); + add_token( 0x124, "mask" ); + add_token( 0x125, "get-msecs" ); + add_token( 0x126, "ms" ); + add_token( 0x127, "finish-device" ); + add_token( 0x128, "decode-phys" ); + add_token( 0x12b, "interpose" ); + add_token( 0x130, "map-low" ); + add_token( 0x131, "sbus-intr>cpu" ); + add_token( 0x150, "#lines" ); + add_token( 0x151, "#columns" ); + add_token( 0x152, "line#" ); + add_token( 0x153, "column#" ); + add_token( 0x154, "inverse?" ); + add_token( 0x155, "inverse-screen?" ); + add_token( 0x156, "frame-buffer-busy?" ); + add_token( 0x157, "draw-character" ); + add_token( 0x158, "reset-screen" ); + add_token( 0x159, "toggle-cursor" ); + add_token( 0x15a, "erase-screen" ); + add_token( 0x15b, "blink-screen" ); + add_token( 0x15c, "invert-screen" ); + add_token( 0x15d, "insert-characters" ); + add_token( 0x15e, "delete-characters" ); + add_token( 0x15f, "insert-lines" ); + add_token( 0x160, "delete-lines" ); + add_token( 0x161, "draw-logo" ); + add_token( 0x162, "frame-buffer-adr" ); + add_token( 0x163, "screen-height" ); + add_token( 0x164, "screen-width" ); + add_token( 0x165, "window-top" ); + add_token( 0x166, "window-left" ); + add_token( 0x16a, "default-font" ); + add_token( 0x16b, "set-font" ); + add_token( 0x16c, "char-height" ); + add_token( 0x16d, "char-width" ); + add_token( 0x16e, ">font" ); + add_token( 0x16f, "fontbytes" ); + add_token( 0x170, "fb1-draw-character" ); + add_token( 0x171, "fb1-reset-screen" ); + add_token( 0x172, "fb1-toggle-cursor" ); + add_token( 0x173, "fb1-erase-screen" ); + add_token( 0x174, "fb1-blink-screen" ); + add_token( 0x175, "fb1-invert-screen" ); + add_token( 0x176, "fb1-insert-characters" ); + add_token( 0x177, "fb1-delete-characters" ); + add_token( 0x178, "fb1-insert-lines" ); + add_token( 0x179, "fb1-delete-lines" ); + add_token( 0x17a, "fb1-draw-logo" ); + add_token( 0x17b, "fb1-install" ); + add_token( 0x17c, "fb1-slide-up" ); + add_token( 0x180, "fb8-draw-character" ); + add_token( 0x181, "fb8-reset-screen" ); + add_token( 0x182, "fb8-toggle-cursor" ); + add_token( 0x183, "fb8-erase-screen" ); + add_token( 0x184, "fb8-blink-screen" ); + add_token( 0x185, "fb8-invert-screen" ); + add_token( 0x186, "fb8-insert-characters" ); + add_token( 0x187, "fb8-delete-characters" ); + add_token( 0x188, "fb8-insert-lines" ); + add_token( 0x189, "fb8-delete-lines" ); + add_token( 0x18a, "fb8-draw-logo" ); + add_token( 0x18b, "fb8-install" ); + add_token( 0x1a0, "return-buffer" ); + add_token( 0x1a1, "xmit-packet" ); + add_token( 0x1a2, "poll-packet" ); + add_token( 0x1a4, "mac-address" ); + add_token( 0x201, "device-name" ); + add_token( 0x202, "my-args" ); + add_token( 0x203, "my-self" ); + add_token( 0x204, "find-package" ); + add_token( 0x205, "open-package" ); + add_token( 0x206, "close-package" ); + add_token( 0x207, "find-method" ); + add_token( 0x208, "call-package" ); + add_token( 0x209, "$call-parent" ); + add_token( 0x20a, "my-package" ); + add_token( 0x20b, "ihandle>phandle" ); + add_token( 0x20d, "my-unit" ); + add_token( 0x20e, "$call-method" ); + add_token( 0x20f, "$open-package" ); + add_token( 0x210, "processor-type" ); + add_token( 0x211, "firmware-version" ); + add_token( 0x212, "fcode-version" ); + add_token( 0x213, "alarm" ); + add_token( 0x214, "(is-user-word)" ); + add_token( 0x215, "suspend-fcode" ); + add_token( 0x216, "abort" ); + add_token( 0x217, "catch" ); + add_token( 0x218, "throw" ); + add_token( 0x219, "user-abort" ); + add_token( 0x21a, "get-my-property" ); + add_token( 0x21b, "decode-int" ); + add_token( 0x21c, "decode-string" ); + add_token( 0x21d, "get-inherited-property" ); + add_token( 0x21e, "delete-property" ); + add_token( 0x21f, "get-package-property" ); + add_token( 0x220, "cpeek" ); + add_token( 0x221, "wpeek" ); + add_token( 0x222, "lpeek" ); + add_token( 0x223, "cpoke" ); + add_token( 0x224, "wpoke" ); + add_token( 0x225, "lpoke" ); + add_token( 0x226, "lwflip" ); + add_token( 0x227, "lbflip" ); + add_token( 0x228, "lbflips" ); + add_token( 0x229, "adr-mask" ); + add_token( 0x230, "rb@" ); + add_token( 0x231, "rb!" ); + add_token( 0x232, "rw@" ); + add_token( 0x233, "rw!" ); + add_token( 0x234, "rl@" ); + add_token( 0x235, "rl!" ); + add_token( 0x236, "wbflips" ); + add_token( 0x237, "lwflips" ); + add_token( 0x238, "probe" ); + add_token( 0x239, "probe-virtual" ); + add_token( 0x23b, "child" ); + add_token( 0x23c, "peer" ); + add_token( 0x23d, "next-property" ); + add_token( 0x23e, "byte-load" ); + add_token( 0x23f, "set-args" ); + add_token( 0x240, "left-parse-string" ); + + /* FCodes from 64bit extension addendum */ + add_token( 0x22e, "rx@" ); + add_token( 0x22f, "rx!" ); + add_token( 0x241, "bxjoin" ); + add_token( 0x242, " + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#define COLON 0x01 +#define SEMICOLON 0x02 +#define TOKENIZE 0x03 +#define AGAIN 0x04 +#define ALIAS 0x05 +#define GETTOKEN 0x06 +#define ASCII 0x07 +#define BEGIN 0x08 +#define BUFFER 0x09 +#define CASE 0x0a +#define CONST 0x0b +#define CONTROL 0x0c +#define CREATE 0x0d +#define DECIMAL 0x0e +#define DEFER 0x0f +#define CDO 0x10 +#define DO 0x11 +#define ELSE 0x12 +#define ENDCASE 0x13 +#define ENDOF 0x14 +#define EXTERNAL 0x15 +#define FIELD 0x16 +#define HEADERLESS 0x17 +#define HEADERS 0x18 +#define HEX 0x19 +#define IF 0x1a +#define CLEAVE 0x1b +#define LEAVE 0x1c +#define CLOOP 0x1d +#define LOOP 0x1e +#define OCTAL 0x1f +#define OF 0x20 +#define REPEAT 0x21 +#define THEN 0x22 +#define TO 0x23 +#define UNTIL 0x24 +#define VALUE 0x25 +#define VARIABLE 0x26 +#define WHILE 0x27 +#define OFFSET16 0x28 +#define BEGINTOK 0x29 +#define EMITBYTE 0x2a +#define ENDTOK 0x2b +#define FLOAD 0x2c +#define STRING 0x2d +#define PSTRING 0x2e +#define PBSTRING 0x2f +#define SSTRING 0x30 +#define RECURSIVE 0x31 +#define HEXVAL 0x32 +#define DECVAL 0x33 +#define OCTVAL 0x34 + +#define END0 0xdb +#define END1 0xdc +#define CHAR 0xdd +#define CCHAR 0xde +#define ABORTTXT 0xdf + +#define NEXTFCODE 0xef + +#define ENCODEFILE 0xf0 + +#define FCODE_V1 0xf1 +#define FCODE_V3 0xf2 +#define NOTLAST 0xf3 +#define PCIREV 0xf4 +#define PCIHDR 0xf5 +#define PCIEND 0xf6 +#define START0 0xf7 +#define START1 0xf8 +#define START2 0xf9 +#define START4 0xfa +#define VERSION1 0xfb +#define FCODE_TIME 0xfc +#define FCODE_DATE 0xfd +#define FCODE_V2 0xfe +#define FCODE_END 0xff diff --git a/toke/emit.c b/toke/emit.c new file mode 100644 index 0000000..f51d49b --- /dev/null +++ b/toke/emit.c @@ -0,0 +1,306 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * emit.c - fcode emitter. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include "toke.h" +#include "stack.h" +#include "emit.h" + +extern bool offs16; +extern int verbose; +extern u8 *ostart, *opc, *oend; + +/* PCI data */ +extern u16 pci_vpd, pci_revision; +extern bool pci_is_last_image; + +/* header pointers */ +extern u8 *fcode_hdr; +extern u8 *pci_hdr; + +extern bool haveend; + +u16 lookup_token(char *name); + +static bool little_endian(void) +{ + static short one=1; + return *(char *)&one==1; +} + +int emit_byte(u8 data) +{ + u8 *newout; + int newsize; + + if(opc==oend) { + /* need more output space */ + newsize = (oend - ostart) * 2; + printf("Increasing output buffer to %d bytes.\n", newsize); + if ((newout=realloc(ostart, newsize)) == NULL) { + printf("toke: could not allocate %d bytes for output buffer\n", newsize); + exit(-1); + } + + /* move pointers */ + opc=newout+(opc-ostart); + ostart=newout; + oend=ostart+newsize; + } + + *opc=data; + opc++; + + return 0; +} + +int emit_fcode(u16 tok) +{ + if ((tok>>8)) + emit_byte(tok>>8); + + emit_byte(tok&0xff); + + return 0; +} + +int emit_token(const char *name) +{ + return emit_fcode(lookup_token((char *)name)); +} + +int emit_num32(u32 num) +{ + emit_byte(num>>24); + emit_byte((num>>16)&0xff); + emit_byte((num>>8)&0xff); + emit_byte(num&0xff); + + return 0; +} + +int emit_num16(u16 num) +{ + emit_byte(num>>8); + emit_byte(num&0xff); + + return 0; +} + +int emit_offset(s16 offs) +{ + if (offs16) + emit_num16(offs); + else + emit_byte(offs); + + return 0; +} + +s16 receive_offset(void) +{ + s16 offs=0; + + if (offs16) { + offs=((*opc)<<8)|(*(opc+1)); + } else + offs=(*opc); + + return offs; +} + +int emit_string(u8 *string, unsigned int cnt) +{ + unsigned int i=0; + + if (cnt>255) { + printf("string too long."); + exit(1); + } + emit_byte(cnt); + for (i=0; i>8); + /* device id */ + emit_byte(did&0xff); emit_byte(did>>8); + /* vital product data */ + emit_byte(0x00); emit_byte(0x00); + /* length of pci data structure */ + emit_byte(0x18); emit_byte(0x00); + /* PCI data structure revision */ + emit_byte(0x00); + + if (little_endian()) { + /* reg level programming */ + emit_byte(classid & 0xff); + /* class code */ + emit_byte((classid>>8)&0xff); + emit_byte((classid>>16)&0xff); + } else { + /* class code */ + emit_byte((classid>>8)&0xff); + emit_byte((classid>>16)&0xff); + /* reg level programming */ + emit_byte(classid & 0xff); + } + + /* size of image - to be filled later */ + emit_byte(0x00); emit_byte(0x00); + /* revision level */ + emit_byte(0x00); emit_byte(0x00); + /* code type = open firmware */ + emit_byte(0x01); + emit_byte(0x80); + /* 2 bytes of padding */ + emit_byte(0x00); emit_byte(0x00); + + return 0; +} + + +int finish_pcihdr(void) +{ + u8 *tpc; + u32 imgsize=opc-ostart, imgblocks; + int padding; + + if(!pci_hdr) + { + printf("error: trying to fix up unknown pci header\n"); + return -1; + } + + /* fix up vpd */ + tpc=opc; + opc=pci_hdr+36; + emit_byte(pci_vpd&0xff); emit_byte(pci_vpd>>8); + + /* fix up image size */ + opc=pci_hdr+44; + imgblocks=(imgsize+511)>>9; /* size is in 512byte blocks */ + emit_byte(imgblocks&0xff); emit_byte(imgblocks>>8); + + /* fix up revision */ + emit_byte(pci_revision&0xff); emit_byte(pci_revision>>8); + + /* fix up last image flag */ + opc++; + emit_byte(pci_is_last_image?0x80:0x00); + opc=tpc; + + /* align to 512bytes */ + padding=((imgsize+511)&0xfffffe00)-imgsize; + printf("Adding %d bytes of zero padding to PCI image.\n",padding); + while (padding--) + emit_byte(0); + + pci_hdr=NULL; + return 0; +} + +void finish_headers(void) +{ + if (fcode_hdr) finish_fcodehdr(); + if (pci_hdr) finish_pcihdr(); +} + diff --git a/toke/emit.h b/toke/emit.h new file mode 100644 index 0000000..be2d3f8 --- /dev/null +++ b/toke/emit.h @@ -0,0 +1,44 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * emit.h - prototypes for fcode emitters + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#ifndef _H_EMIT +#define _H_EMIT + +int emit_byte(u8 data); +int emit_fcode(u16 tok); +int emit_token(const char *name); +int emit_num32(u32 num); +int emit_num16(u16 num); +int emit_offset(s16 offs); +s16 receive_offset(void); +int emit_string(u8 *string, unsigned int cnt); +int emit_fcodehdr(void); +int finish_fcodehdr(void); +int emit_pcihdr(u16 vid, u16 did, u32 classid); +int finish_pcihdr(void); +void finish_headers(void); + +#endif /* _H_EMIT */ diff --git a/toke/examples/case.fs b/toke/examples/case.fs new file mode 100644 index 0000000..b16c4b9 --- /dev/null +++ b/toke/examples/case.fs @@ -0,0 +1,14 @@ +\ This example tests the capability of tokenizing case..endcase +\ expressions. If the output is "choice 2" everything worked ok. + +fcode-version2 + +2 case + 1 of " choice 1" type endof + 2 of " choice 2" type endof + 3 of " choice 3" type endof +endcase +cr + +fcode-end + diff --git a/toke/examples/date.fs b/toke/examples/date.fs new file mode 100644 index 0000000..8d0b28f --- /dev/null +++ b/toke/examples/date.fs @@ -0,0 +1,9 @@ +\ this example demonstrates the use of FCODE-TIME and FCODE-DATE + +fcode-version2 + ." This program was tokenized on " + fcode-date type + ." at " + fcode-time type +fcode-end + diff --git a/toke/examples/display.fs b/toke/examples/display.fs new file mode 100644 index 0000000..1cf0c79 --- /dev/null +++ b/toke/examples/display.fs @@ -0,0 +1,33 @@ +\ Basic display device driver +\ This version doesn't use the graphics accelerator because of conflicts +\ with the window system's use of same. + +fcode-version2 + +hex + +" INTL,cgsix" name +" INTL,501-xxxx" model + +h# 20.0000 constant dac-offset h# 10 constant /dac +h# 30.0000 constant fhc-offset h# 10 constant /fhc +h# 30.1800 constant thc-offset h# 20 constant /thc +h# 70.0000 constant fbc-offset h# 10 constant /fbc +h# 70.1000 constant tec-offset h# 10 constant /tec +h# 80.0000 constant fb-offset h# 10.0000 constant /frame + +: >reg-spec ( offset size -- encoded-reg ) + >r 0 my-address d+ my-space encode-phys 0 encode-int encode+ + r> encode-int encode+ +; + +0 0 >reg-spec \ Configuration space registers +dac-offset /dac >reg-spec encode+ +fhc-offset /fhc >reg-spec encode+ +thc-offset /thc >reg-spec encode+ +fbc-offset /fbc >reg-spec encode+ +tec-offset /tec >reg-spec encode+ +fb-offset /frame >reg-spec encode+ +" reg" property + +fcode-end diff --git a/toke/examples/fcdisp.fs b/toke/examples/fcdisp.fs new file mode 100644 index 0000000..80c8a7e --- /dev/null +++ b/toke/examples/fcdisp.fs @@ -0,0 +1,72 @@ +\ This file has been created with codegen's ccfcode + +fcode-version2 +headers + +\ C runtime +variable $frame 0 $frame ! + " dev /pci" evaluate + ( asm ) new-device + ( asm ) +\ function screen_open +: screen_open recursive + 24 $frame @ >r alloc-mem $frame ! + " "(61737369676E65642D616464726573736573)" get-my-property ( asm ) if + " "(63616E6E6F742066696E642061737369676E65642D6164647265737365732070726F70657274790A)" type + abort then + + begin decode-int ( asm ) dup $frame @ 8 + ( physhi ) l! drop + decode-int ( asm ) dup $frame @ 16 + ( physmid ) l! drop + decode-int ( asm ) dup $frame @ 20 + ( physlo ) l! drop + decode-int ( asm ) dup $frame @ ( sizehi ) l! drop + decode-int ( asm ) dup $frame @ 4 + ( sizelo ) l! drop + dup ( top ) ( asm ) 0 > 1 and 0<> if $frame @ 8 + ( physhi ) l@ 24 >>a 7 and 2 <> 1 and then while repeat + 2drop + ( asm ) + 4 " "(636F6E6669672D6C40)" $call-parent ( asm ) + ( pop ) ( asm ) + 24 $frame @ swap free-mem r> $frame ! exit dup $frame @ 12 + ( cfg ) l! drop + 4 $frame @ 12 + ( cfg ) l@ 65535 and 1 or 2 or " "(636F6E6669672D6C21)" $call-parent ( asm ) + $frame @ 8 + ( physhi ) l@ $frame @ 16 + ( physmid ) l@ $frame @ 20 + ( physlo ) l@ 480 640 * " "(6D61702D696E)" $call-parent ( asm ) + ( pop ) ( asm ) + 24 $frame @ swap free-mem r> $frame ! exit to frame-buffer-adr ( asm ) + default-font ( asm ) + set-font ( asm ) + 640 480 80 25 fb8-install ( asm ) + 24 $frame @ swap free-mem r> $frame ! + ; \ end screen_open + +\ function screen_close +: screen_close recursive + 4 $frame @ >r alloc-mem $frame ! + 4 " "(636F6E6669672D6C40)" $call-parent ( asm ) + ( pop ) ( asm ) + 4 $frame @ swap free-mem r> $frame ! exit dup $frame @ ( cfg ) l! drop + 4 $frame @ ( cfg ) l@ 65528 and " "(636F6E6669672D6C21)" $call-parent ( asm ) + frame-buffer-adr ( asm ) 480 640 * " "(6D61702D6F7574)" $call-parent ( asm ) + 4 $frame @ swap free-mem r> $frame ! + ; \ end screen_close + +\ function screen_selftest +: screen_selftest recursive + " "(73637265656E2073656C66746573740A)" type + 0 exit + ; \ end screen_selftest + +\ function main +: main recursive + " "(73637265656E)" device-name ( asm ) + " "(646973706C6179)" device-type ( asm ) + " "(6D616B652D70726F70657274696573)" evaluate + " "()" " "(69736F363432392D313938332D636F6C6F7273)" property + 0 1 0 8 reg + ['] screen_open is-install ( asm ) + ['] screen_close is-remove ( asm ) + ['] screen_selftest is-selftest ( asm ) + finish-device + ( asm ) + ; \ end main + +main + +fcode-end diff --git a/toke/examples/fract.fs b/toke/examples/fract.fs new file mode 100644 index 0000000..5c1d1c0 --- /dev/null +++ b/toke/examples/fract.fs @@ -0,0 +1,32 @@ +\ This example even fits in a signature ;-) + +\ hex 4666 dup negate do i 4000 dup 2* negate do 2a 0 dup 2dup 1e 0 do +\ 2swap * d >>a 4 pick + -rot - j + dup dup * e >>a rot dup dup * e >>a +\ rot swap 2dup + 10000 > if 3drop 2drop 20 0 dup 2dup leave then loop +\ 2drop 2drop type 268 +loop cr drop 5de +loop + +fcode-version2 + +hex 4666 dup negate +do + i 4000 dup 2* negate + do + 2a 0 dup 2dup 1e 0 + do + 2swap * d >>a 4 pick + + -rot - j + + dup dup * e >>a rot + dup dup * e >>a rot + swap + 2dup + 10000 > if + 3drop 2drop 20 0 dup 2dup leave + then + loop + 2drop 2drop + emit + 268 +loop + cr drop +5de +loop + +fcode-end + diff --git a/toke/examples/pciexample.fs b/toke/examples/pciexample.fs new file mode 100644 index 0000000..5ad0ead --- /dev/null +++ b/toke/examples/pciexample.fs @@ -0,0 +1,10 @@ +hex +tokenizer[ 1011 0019 200 23 ]tokenizer ( -- vid did classid revision ) + +pci-revision \ this has to be called somewhere before pci-end + +pci-header + fcode-version2 + " pci driver sample." type + fcode-end +pci-end diff --git a/toke/examples/primes.fs b/toke/examples/primes.fs new file mode 100644 index 0000000..42bbbcc --- /dev/null +++ b/toke/examples/primes.fs @@ -0,0 +1,68 @@ +\ primes.4th + +fcode-version2 + +\ Example code for kForth +\ Copyright (c) 1998 Creative Consulting for Research and Education +\ +\ This program is free software; you may redistribute it under the terms of +\ the GNU General Public License. This program has absolutely no warranty. + + +\ Test for a prime number. Return the largest divisor (< n ) +\ and a flag indicating whether the number is prime or not. + +: ?prime ( n -- m flag | is n a prime number? ) +\ if flag is false (0), m is the largest divisor of n + abs + dup 3 > \ is n > 3 ? + if + dup 2 /mod + swap 0= + if \ is n divisible by 2 ? + nip false + else + 1- \ check for divisibility starting + begin \ with n/2 - 1 and counting down + 2dup mod + over 1 > + and + while + 1- + repeat + nip + dup 1 <= + then + else + drop 1 true + then +; + +: test_prime ( n -- | test for prime number and display result ) + ?prime + if + ." is a prime number" drop + else + ." is NOT prime. Its largest divisor is " . + then + cr +; + +: list_primes ( n -- | list all the prime numbers from 1 to n ) + abs + dup 0> + if + 1+ 1 do + i ?prime + if i . cr then + drop + loop + else + drop + then +; + +10000 list_primes + +fcode-end + diff --git a/toke/examples/scsi-sample/README.sample b/toke/examples/scsi-sample/README.sample new file mode 100644 index 0000000..7f7ab94 --- /dev/null +++ b/toke/examples/scsi-sample/README.sample @@ -0,0 +1,8 @@ + +This driver is taken from the IEEE 1275-1994 specs. +Changes from the errata draft #4 are included and +filename suffixes are changed to .fs (was: .fth) + +To tokenize this driver, do + + $ toke ./overall.fs diff --git a/toke/examples/scsi-sample/hacom.fs b/toke/examples/scsi-sample/hacom.fs new file mode 100644 index 0000000..ae99956 --- /dev/null +++ b/toke/examples/scsi-sample/hacom.fs @@ -0,0 +1,330 @@ +\ Common code for SCSI host adapter drivers + +\ The following code is intended to be independent of the details of the +\ SCSI hardware implementation. It is loaded after the hardware-dependent +\ file that defines execute-command, set-address, open-hardware, etc. + +headers + +-1 value inq-buf \ Address of inquiry data buffer +-1 value sense-buf \ Holds extended error information + +0 value #retries ( -- n ) \ number of times to retry SCSI transaction + +\ Classifies the sense condition as either okay (0), retryable (1), +\ or non-retryable (-1) + +: classify-sense ( -- 0 | 1 | -1 ) + sense-buf + + \ Make sure we understand the error class code. + dup c@ h# 7f and h# 70 <> if drop -1 exit then + + \ Check for filemark, end-of-media, or illegal block length. + dup 2+ c@ h# e0 and if drop -1 exit then + + 2 + c@ h# f and ( sense-key ) + + \ no_sense(0) and recoverable(1) are okay. + dup 1 <= if drop 0 exit then ( sense-key ) + + \ not-ready(2) and attention(6) are retryable. + dup 2 = swap 6 = or if 1 else -1 then +; + +0 value open-count + +external + +\ The SCSI device node defines an address space for its children. That +\ address space is of the form "target#,unit#". target# and unit# are +\ both integers. parse-2int converts a text string (e.g., "3,4") into +\ a pair of binary integers. + +: decode-unit ( addr len -- unit# target# ) parse-2int ; + +: open ( -- okay? ) + open-count if + reopen-hardware dup if open-count 1+ to open-count then + exit + else + open-hardware dup if + 1 to open-count + 100 dma-alloc to sense-buf + 100 dma-alloc to inq-buf + then + then +; +: close ( -- ) + open-count 1- to open-count + open-count if + reclose-hardware + else + close-hardware + inq-buf 100 dma-free + sense-buf 100 dma-free + then +; + + +headers + +create sense-cmd 3 c, 0 c, 0 c, 0 c, ff c, 0 c, + +: get-sense ( -- ) \ Issue REQUEST SENSE, which is not supposed to fail. + sense-buf ff true sense-cmd 6 execute-command 0= if drop then +; + +\ Give the device a little time to recover before retrying the command. +: delay-retry ( -- ) 1000 0 do loop ; + +0 value statbyte \ Local variable used by retry? + +\ RETRY? is used by RETRY-COMMAND to determine whether or not to retry the +\ command, considering the following factors: +\ - Success or failure of the command at the hardware level (failure at +\ this level is usually fatal, except in the case of an incoming bus reset) +\ - The value of the status byte returned by the command +\ - The condition indicated by the sense bytes +\ - The number of previous retries +\ +\ The input arguments are as returned by "scsi-exec". +\ On output, the top of the stack is true if the command is to be retried, +\ otherwise the top of the stack is false and the results that should be +\ returned by retry-command are underneath it; those results indicate the type +\ of error that occurred. + +: retry? ( hw-result | statbyte 0 -- true | [[sensebuf] f-hw] error? false ) + case + 0 of to statbyte endof \ No hardware error; continue checking. + 1 of true exit endof \ Retry after incoming bus reset. + ( hw-result ) true false exit \ Other hardware errors are fatal. + endcase + + statbyte 0= if false false exit then \ If successful, return "no-error". + + statbyte 2 and if \ "Check Condition", so get extended status. + get-sense classify-sense case ( -1|0|1 ) + \ If the sense information says "no sense", return "no-error". + 0 of false false exit endof + + \ If the error is fatal, return "sense-buf,valid,statbyte". + -1 of sense-buf false statbyte false exit endof + endcase + + \ Otherwise, the error was retryable. However, if we have + \ have already retried the specified number of times, don't + \ retry again; instead return sense buffer and status. + #retries 0= if sense-buf false statbyte false exit then + then + + \ Don't retry if vendor-unique, reserved, intermediate, or + \ "condition met/good" bits are set. Return "no-sense,status". + statbyte h# f5 and if true statbyte false exit then + + \ Don't retry if we have already retried the specified number + \ of times. Return "no-sense,status". + #retries 0= if true statbyte false exit then + \ Otherwise, it was either a busy or a retryable check condition, + \ so we retry. + true +; + +\ RETRY-COMMAND executes a SCSI command. If a check condition is indicated, +\ performs a "get-sense" command. If the sense bytes indicate a non-fatal +\ condition (e.g., power-on reset occurred, not ready yet, or recoverable +\ error), the command is retried until the condition either goes away or +\ changes to a fatal error. +\ +\ The command is retried until +\ a) The command succeeds, or +\ b) The select fails, or dma fails, or +\ c) The sense bytes indicate an error that we can't retry at this level, or +\ d) The number of retries is exceeded. +\ #retries is number of times to retry (0: don't retry, -1: retry forever) +\ +\ sensebuf is the address of the sense buffer; it is present only +\ if f-hw is 0 and error? is nonzero. The length of the sense buffer +\ is 8 bytes plus the value in byte 7 of the sense buffer. +\ +\ f-hw is nonzero if there is a hardware error -- dma fails, select fails, +\ etc. -- or if the status byte was neither 0 (okay) nor 2 (check condition). +\ +\ error? is nonzero if there is a transaction error. If error? is 0, +\ f-hw and sensebuf are not returned. +\ +\ If sensebuf is returned, the contents are valid until the next call to +\ retry-command. sensebuf becomes inaccessable when this package is closed. +\ +\ dma-dir is necessary because it is not always possible to infer the DMA +\ direction from the command. + +\ Local variables used by retry-command? + +0 instance value dbuf \ Data transfer buffer +0 instance value dlen \ Expected length of data transfer +0 instance value direction-in \ Direction for data transfer + +-1 instance value cbuf \ Command base address + 0 instance value clen \ Actual length of this command + +external + +: retry-command ( dma-buf dma-len dma-dir cmdbuf cmdlen #retries -- ... ) + ( ... -- [[sensebuf] f-hw] error? ) + to #retries to clen to cbuf to direction-in to dlen to dbuf + + begin + dbuf dlen direction-in cbuf clen execute-command ( hwerr | stat 0 ) + retry? + while + #retries 1- to #retries + delay-retry + repeat +; + +headers + +\ Collapses the complete error information returned by retry-command into +\ a single error/no-error flag. + +: error? ( false | true true | sensebuf false true -- error? ) + dup if swap 0= if nip then then +; + +external + +\ Simplified "retry-command" routine for commands with no data transfer phase +\ and simple error checking requirements. + +: no-data-command ( cmdbuf -- error? ) + >r 0 0 true r> 6 -1 retry-command error? +; + +\ short-data-command executes a command with the following characteristics: +\ a) The data direction is incoming +\ b) The data length is less than 256 bytes + +\ The host adapter driver is responsible for supplying the DMA data +\ buffer; if the command succeeds, the buffer address is returned. +\ The buffer contents become invalid when another SCSI command is +\ executed, or when the driver is closed. + +: short-data-command ( data-len cmdbuf cmdlen -- true | buffer false ) + >r >r inq-buf swap true r> r> -1 retry-command ( retry-cmd-results ) + error? dup 0= if inq-buf swap then +; + +headers + +\ Here begins the implementation of "show-children", a word that +\ is intended to be executed interactively, showing the user the +\ devices that are attached to the SCSI bus. + +\ Tool for storing a big-endian 24-bit number at an unaligned address +: 3c! ( n addr -- ) >r lbsplit drop r@ c! r@ 1+ c! r> 2+ c! ; + + +\ Command block template for Inquiry command + +create inquiry-cmd h# 12 c, 0 c, 0 c, 0 c, ff c, 0 c, + +: inquiry ( -- error? ) + \ 8 retries should be more than enough; inquiry commands aren't + \ supposed to respond with "check condition". + + inq-buf ff true inquiry-cmd 6 8 retry-command error? +; + +\ Returns true if the target number "select-id" responds to the inquiry +\ command. +: probe-target ( select-id -- present? ) + 0 swap set-address inquiry 0= +; + + +\ Reads the indicated byte from the Inquiry data buffer. + +: inq@ ( offset -- value ) inq-buf + c@ ; + +: .scsi1-inquiry ( -- ) inq-buf 5 ca+ 4 inq@ fa min type ; +: .scsi2-inquiry ( -- ) inq-buf 8 ca+ d# 28 type ; + +\ Displays the results of an Inquiry command to the indicated device. + +: show-lun ( unit target -- ) + over swap set-address ( unit ) + inquiry if drop exit then ( unit ) + 0 inq@ h# 7f = if drop exit then ( unit ) + ." Unit " . ." " ( ) + 1 inq@ h# 80 and if ." Removable " then ( ) + + 0 inq@ case ( ) + 0 of ." Disk " endof + 1 of ." Tape " endof + 2 of ." Printer " endof + 3 of ." Processor " endof + 4 of ." WORM " endof + 5 of ." Read Only device" endof + ( default ) ." Device type " dup .h + endcase ( ) + + 1 inq@ h# 7f and ?dup if ." Qualifier " .h then + + 4 spaces + 3 inq@ 0f and 2 = if .scsi2-inquiry else .scsi1-inquiry then + cr +; + + +external + +\ Searches for devices on the SCSI bus, displaying the Inquiry information +\ for each device that responds. + +: show-children ( -- ) + open 0= if ." Can't open SCSI host adapter" cr exit then + + 8 0 do + i probe-target if + ." Target " i . cr + 8 0 do i j show-lun loop + then + loop + + close +; + +headers +\ The Diagnose command is useful for generic SCSI devices. +\ It executes both "test-unit-ready" and "send-diagnostic" +\ commands, decoding the error status information they return. + +create test-unit-rdy-cmd 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, +create send-diagnostic-cmd h# 1d c, 4 c, 0 c, 0 c, 0 c, 0 c, + +: send-diagnostic ( -- error? ) send-diagnostic-cmd no-data-command ; + +external + +: diagnose ( -- error? ) + 0 0 true test-unit-rdy-cmd 6 -1 ( dma$ dir cmd$ #retries ) + retry-command if ( [ sensebuf ] hardware-error? ) + ." Test unit ready failed - " ( [ sensebuf ] hardware-error? ) + + if ( ) + ." hardware error (no such device?)" cr ( ) + else ( sensebuf ) + ." extended status = " cr ( sensebuf ) + base @ >r hex ( sensebuf ) + 8 bounds ?do i 3 u.r loop cr ( ) + r> base ! + then + true + else + send-diagnostic ( fail? ) + then +; + +headers + diff --git a/toke/examples/scsi-sample/overall.fs b/toke/examples/scsi-sample/overall.fs new file mode 100644 index 0000000..5d2f61f --- /dev/null +++ b/toke/examples/scsi-sample/overall.fs @@ -0,0 +1,42 @@ +\ FCode driver for hypothetical SCSI host adapter + +hex +" XYZI,scsi" name \ Name of device node +" XYZI,12346-01" model \ Manufacturer's model number +" scsi-2" device-type \ Device implements SCSI-2 method set +3 0 intr \ Device interrupts on level 3, no vector + +external + +\ These routines may be called by the children of this device. +\ This card has no local buffer memory for the SCSI device, so it +\ depends on its parent to supply DMA memory. For a device with +\ local buffer memory, these routines would probably allocate from +\ that local memory. + +: dma-alloc ( n -- vaddr ) " dma-alloc" $call-parent ; +: dma-free ( vaddr n -- ) " dma-free" $call-parent ; +: dma-sync ( vaddr devaddr n -- ) " dma-sync" $call-parent ; +: dma-map-in ( vaddr n cache? -- devaddr ) " dma-map-in" $call-parent ; +: dma-map-out ( vaddr devaddr n -- ) " dma-map-out" $call-parent ; +: max-transfer ( -- n ) + " max-transfer" ['] $call-parent catch if 2drop h# 7fff.ffff then + \ The device imposes no size limitations of its own; if it did, those + \ limitations could be described here, perhaps by executing: + \ my-max-transfer min +; + +fload scsiha.fs + +fload hacom.fs + + new-device + fload scsidisk.fs \ scsidisk.fs also loads scsicom.fs + finish-device + + new-device + fload scsitape.fs \ scsitape.fs also loads scsicom.fs + finish-device + +fcode-end + diff --git a/toke/examples/scsi-sample/scsicom.fs b/toke/examples/scsi-sample/scsicom.fs new file mode 100644 index 0000000..21c2cab --- /dev/null +++ b/toke/examples/scsi-sample/scsicom.fs @@ -0,0 +1,72 @@ +\ This file contains some words that are useful for both +\ SCSI disk and SCSI tape device drivers. + +\ The SCSI disk and SCSI tape packages need to export dma-alloc and dma-free +\ methods so the deblocker can allocate DMA-capable buffer memory. + +external +: dma-alloc ( n -- vaddr ) " dma-alloc" $call-parent ; +: dma-free ( vaddr n -- ) " dma-free" $call-parent ; +headers + +: parent-max-transfer ( -- n ) " max-transfer" $call-parent ; + +\ Calls the parent device's "retry-command" method. The parent device is +\ assumed to be a driver for a SCSI host adapter (device-type = "scsi"). + +: retry-command ( dma-addr dma-len dma-dir cmd-addr cmd-len #retries -- ... ) + ( ... -- false ) \ No error + ( ... -- true true ) \ Hardware error + ( ... -- sensebuf false true ) \ Fatal error with extended status + " retry-command" $call-parent +; + +\ Simplified command execution routines for common simple command forms + +: no-data-command ( cmdbuf -- error? ) " no-data-command" $call-parent ; + +: short-data-command ( data-len cmdbuf cmdlen -- true | buffer false ) + " short-data-command" $call-parent +; + +\ Some tools for reading and writing 2-, 3-, and 4-byte numbers to and from +\ SCSI command and data buffers. The ones defined below are used both in +\ the SCSI disk and the SCSI tape packages. Other variations that are +\ used only by one of the packages are defined in the package where they +\ are used. + +: +c! ( n addr -- addr' ) tuck c! 1+ ; +: 3c! ( n addr -- ) >r lbsplit drop r> +c! +c! c! ; + +: -c@ ( addr -- n addr' ) dup c@ swap 1- ; +: 3c@ ( addr -- n ) 2 + -c@ -c@ c@ 0 bljoin ; +: 4c@ ( addr -- n ) 3 + -c@ -c@ -c@ c@ bljoin ; + +\ "Scratch" command buffer useful for construction of read and write commands + +create cmdbuf 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, +: cb! ( byte index -- ) cmdbuf + c! ; \ Write byte to command buffer + +\ The deblocker converts a block/record-oriented interface to a byte-oriented +\ interface, using internal buffering. Disk and tape devices are usually +\ block- or record-oriented, but the OBP external interface is byte-oriented, +\ in order to be independent of particular device block sizes. + +0 instance value deblocker +: init-deblocker ( -- okay? ) + " " " deblocker" $open-package to deblocker + deblocker if + true + else + ." Can't open deblocker package" cr false + then +; + +headerless +: selftest ( -- error? ) + my-unit " set-address" $call-parent + " diagnose" $call-parent +; + +headers + diff --git a/toke/examples/scsi-sample/scsidisk.fs b/toke/examples/scsi-sample/scsidisk.fs new file mode 100644 index 0000000..21e08d1 --- /dev/null +++ b/toke/examples/scsi-sample/scsidisk.fs @@ -0,0 +1,156 @@ +\ SCSI disk package implementing a "block" device-type interface + +" sd" encode-string " name" property +" block" device-type + +fload scsicom.fs \ Utility routines for SCSI commands + +hex + +\ 0 means no timeout +: set-timeout ( msecs -- ) " set-timeout" $call-parent ; + +0 instance value offset-low \ Offset to start of partition +0 instance value offset-high + +0 instance value label-package + +\ Sets offset-low and offset-high, reflecting the starting location of the +\ partition specified by the "my-args" string. + +: init-label-package ( -- okay? ) + 0 to offset-high 0 to offset-low + my-args " disk-label" $open-package to label-package + label-package if + 0 0 " offset" label-package $call-method to offset-high to offset-low + true + else + ." Can't open disk label package" cr false + then +; + +\ Ensures that the disk is spinning, but doesn't wait forever. + +create sstart-cmd h# 1b c, 1 c, 0 c, 0 c, 1 c, 0 c, + +: timed-spin ( -- error? ) + d# 15000 set-timeout + sstart-cmd no-data-command + 0 set-timeout +; + +0 instance value /block \ Device native block size + +create mode-sense-cmd h# 1a c, 0 c, 0 c, 0 c, d# 12 c, 0 c, +create read-capacity-cmd h# 25 c, 0 c, 0 c, 0 c, d# 12 c, 0 c, + 0 c, 0 c, 0 c, 0 c, + +: read-block-size ( -- n ) \ Ask device about its block size. + \ First try "mode sense" - data returned in bytes 9,10,11. + + d# 12 mode-sense-cmd 6 short-data-command if 0 else 9 + 3c@ then + + ?dup if exit then + + \ Failing that, try "read capacity" - data returned in bytes 4,5,6,7. + + 8 read-capacity-cmd 0a short-data-command if 0 else 4 + 4c@ then + + ?dup if exit then + + d# 512 \ Default to 512 if the device won't tell us. +; + +external + + +\ Return device block size; cache it the first time we find the information. +\ This method is called by the deblocker. +: block-size ( -- n ) + /block if /block exit then \ Don't ask if we already know. + read-block-size dup to /block +; + +headers + +\ Read or write "#blks" blocks starting at "block#" into memory at "addr" +\ Input? is true for reading or false for writing. +\ Command is 8 for reading or h# a for writing. +\ We use the 6-byte forms of the disk read and write commands. + +: 2c! ( n addr -- ) >r lbsplit 2drop r> +c! c! ; +: 4c! ( n addr -- ) >r lbsplit r> +c! +c! +c! c! ; + +: r/w-blocks ( addr block# #blks input? command -- actual# ) + cmdbuf d# 10 erase + 2over h# 100 u> + swap h# 200000 u>= or if \ Use 10-byte form ( addr block# #blks dir cmd ) + h# 20 or 0 cb! \ 28 (read) or 2a (write) ( addr block# #blks dir ) + -rot swap ( addr dir #blks block# ) + cmdbuf 2 + 4c! ( addr dir #blks ) + dup cmdbuf 7 + 2c! + d# 10 ( addr dir #blks cmd-len ) + else \ Use 6-byte form ( addr block# #blks dir cmd ) + 0 cb! ( addr block# #blks dir ) + -rot swap ( addr dir #blks block# ) + cmdbuf 1+ 3c! ( addr dir #blks ) + dup 4 cb! ( addr dir #blks ) + 6 ( addr dir #blks cmd-len ) + then + tuck >r >r ( addr input? #blks ) ( R: #blks cmd-len ) + /block * swap cmdbuf r> -1 ( addr #bytes input? cmd cmd-len #retries ) + retry-command if ( [ sensebuf ] hw? ) + 0= if drop then r> drop 0 + else ( ) + r> + then ( actual# ) +; + +external + +\ These three methods are called by the deblocker. + +: max-transfer ( -- n ) parent-max-transfer ; +: read-blocks ( addr block# #blocks -- #read ) true d# 8 r/w-blocks ; +: write-blocks ( addr block# #blocks -- #written ) false d# 10 r/w-blocks ; + +\ Methods used by external clients + +: open ( -- flag ) + my-unit " set-address" $call-parent + + \ It might be a good idea to do an inquiry here to determine the + \ device configuration, checking the result to see if the device + \ really is a disk. + + \ Make sure the disk is spinning. + + timed-spin if false exit then + + block-size to /block + + init-deblocker 0= if false exit then + + init-label-package 0= if + deblocker close-package false exit + then + + true +; + +: close ( -- ) + label-package close-package + deblocker close-package +; + +: seek ( offset.low offset.high -- okay? ) + offset-low offset-high x+ " seek" deblocker $call-method +; + +: read ( addr len -- actual-len ) " read" deblocker $call-method ; +: write ( addr len -- actual-len ) " write" deblocker $call-method ; +: load ( addr -- size ) " load" label-package $call-method ; + +headers + + diff --git a/toke/examples/scsi-sample/scsiha.fs b/toke/examples/scsi-sample/scsiha.fs new file mode 100644 index 0000000..b32851e --- /dev/null +++ b/toke/examples/scsi-sample/scsiha.fs @@ -0,0 +1,200 @@ +\ Example FCode driver for a hypothetical SCSI bus interface device + +hex + +\ The following structure defines the registers for the SCSI device. +\ This hypothetical device is designed for ease of programming. It +\ has a separate register for each function (no bit packing). All +\ registers are both readable and writeable. The device has a random- +\ access buffer large enough for a maximum-length SCSI command block. + +\ To execute a SCSI command with this device, write the appropriate +\ information into the registers named ">cmd-adr" through ">input?", write +\ a 1 to the ">start" register, and wait for the ">start" register to +\ change to 0. Then read the ">phase" register to determine whether or +\ not the command completed all phases (">phase" reports 0 on success, +\ h# fd for incoming reset, h# ff for other hardware error). +\ If so, ">status" contains the SCSI status byte, and ">message-in" +\ contains the command-complete message byte. + +struct ( scsi-registers ) + 0c field >cmd-adr \ Up to 12 command bytes + 4 field >cmd-len \ Length of command block + + 4 field >data-adr \ Base address of DMA data area + 4 field >data-len \ Length of data area + + 1 field >host-selectid \ Host's selection ID + 1 field >target-selectid \ Target's selection ID + 1 field >input? \ 1 for data output; 0 for data input + 1 field >message-out \ Outgoing message byte + + 1 field >start \ Write 1 to start. Reads as 0 when done. + 1 field >phase \ Reports the last transaction phase + 1 field >status \ Returned status byte + 1 field >message-in \ Incoming message byte + + 1 field >intena \ Write 1 to enable interrupts. + 1 field >reset-bus \ Write 1 to reset the SCSI bus. + 1 field >reset-board \ Write 1 to reset the board. +constant /scsi-regs + + +\ Now that we have a symbolic name for the size of the register block, +\ we can declare the "reg" property. + +\ Registers begin at offset 800000 and continue for "/scsi-regs" bytes. + +my-address 80.0000 + my-space /scsi-regs reg + + +-1 instance value regs \ Virtual base address of device registers + +0 instance value my-id \ host adapter's selection ID +0 instance value his-id \ target's selection ID +0 instance value his-lun \ target's unit number + +\ Map device registers + +: map ( -- ) + my-address 80.0000 + my-space /scsi-regs ( addr-low addr-high size ) + " map-in" $call-parent to regs ( ) +; + +: unmap ( -- ) + regs /scsi-regs " map-out" $call-parent -1 to regs +; + +create reset-done-time 0 , +create resetting false , + +\ 5 seconds appears to be about the right length of time to wait after +\ a reset, considering a variety of disparate devices. +d# 5000 value scsi-reset-delay + +: reset-wait ( -- ) + resetting @ if + begin get-msecs reset-done-time @ - 0>= until + resetting off + then +; + +: reset-scsi-bus ( -- ) + 1 regs >reset-board rb! \ Reset the controller board. + 0 regs >intena rb! \ Turn off interrupts. + 1 regs >reset-bus rb! \ Reset the SCSI bus. + + \ After resetting the SCSI bus, we have to give the target devices + \ some time to initialize their microcode. Otherwise the first command + \ may hang, as with some older controllers. We note the time when it + \ is okay to access the bus (now plus some delay), and "execute-command" + \ will delay until that time is reached, if necessary. + \ This allows us to overlap the delay with other work in many cases. + get-msecs scsi-reset-delay + reset-done-time ! resetting on +; + +0 value scsi-time \ Maximum command time in milliseconds +0 value time-limit \ Ending time for command + +: set-timeout ( msecs -- ) to scsi-time ; + +0 value devaddr + +\ Returns true if select failed +: (exec) ( dma-adr,len dir cmd-adr,len -- hwresult ) + reset-wait \ Delay until any prior reset operation is done. + + his-lun h# 80 or regs >message-out rb! \ Set unit number; no disconnect. + my-id regs >host-selectid rb! \ Set the selection IDs. + his-id regs >target-selectid rb! + + \ Write the command block into the host adapter's command register + dup 0 ?do ( data-adr,len dir cmd-adr,len ) + over i + c@ ( data-adr,len dir cmd-adr,len cmd-byte ) + regs >cmd-adr i ca+ rb! ( data-adr,len dir cmd-adr,len ) + loop ( data-adr,len dir cmd-adr,len ) + + regs >cmd-len rl! drop ( data-adr,len dir ) + + \ Set the data transfer parameters. + + ( .. dir ) regs >input? rb! ( data-adr,len ) \ Direction + ( .. len ) regs >data-len rl! ( data-adr ) \ Length + ( .. adr ) regs >data-adr rl! ( ) \ DMA Address + + \ Now we're ready to execute the command. + + 1 regs >start rb! \ Tell board to start the command. + + get-msecs scsi-time + to time-limit \ Set the time limit. + + begin regs >start rb@ while \ Wait until command finished. + scsi-time if \ If timeout is enabled, and + get-msecs time-limit - 0>= if \ the time-limit has been reached, + reset-scsi-bus true exit \ reset the bus and return error. + then + then + + repeat + + \ Nonzero phase means that the command didn't finish. + + regs >phase rb@ +; + + +\ Returns true if select failed +: execute-command ( data-adr,len dir cmd-adr,len -- hwresult | statbyte false) + \ Temporarily put dir and cmd-adr,len on the return stack to get them + \ out of the way so we can work on the DMA data buffer. + + >r >r >r ( data-adr,len ) + + dup if ( data-adr,len ) + + \ If the data transfer has a nonzero length, we have to map it in. + + 2dup false dma-map-in ( data-adr,len dma ) + 2dup swap r> r> r> ( data-adr,len dma dma,len dir cmd-adr,len) + + (exec) ( data-adr,len phys hwres) + + >r swap dma-map-out r> ( hwresult ) + else ( data-adr,len ) + r> r> r> (exec) ( hwresult ) + then ( hwresult ) + + ?dup 0= if ( hwresult | ) + regs >status rb@ false \ Command finished; return status byte and false. + then ( hwresult | statbyte 0 ) +; + +external + +: reset ( -- ) map reset-scsi-bus unmap ; +reset \ Reset the SCSI bus when we are probed. + +: open-hardware ( -- okay? ) + map + 7 to my-id + \ Should perform a quick "sanity check" selftest here, + \ returning true if the test succeeds. + true +; +: reopen-hardware ( -- okay? ) true ; + +: close-hardware ( -- ) unmap ; +: reclose-hardware ( -- ) ; + +: selftest ( -- 0 | error-code ) + \ Perform reasonably extensive selftest here, displaying + \ a message and returning an error code if the + \ test fails and returning 0 if the test succeeds. + 0 +; +: set-address ( unit target -- ) + to his-id to his-lun +; + + + diff --git a/toke/examples/scsi-sample/scsitape.fs b/toke/examples/scsi-sample/scsitape.fs new file mode 100644 index 0000000..ed27779 --- /dev/null +++ b/toke/examples/scsi-sample/scsitape.fs @@ -0,0 +1,296 @@ +\ SCSI tape package implementing a "byte" device-type interface. +\ Supports both fixed-length-record and variable-length-record tape devices. + +" st" encode-string " name" property +" byte" device-type + +fload scsicom.fs \ Utility routines for SCSI commands + +hex + +external + +false instance value at-eof? \ Turned on when read-blocks hits file mark. + +headers + +false instance value fixed-len? \ True if the device has fixed-length blocks. +false instance value written? \ True if the tape has been written. + +0 instance value /tapeblock \ Max length for variable-length records; + \ actual length for fixed-length records. + +create write-eof-cmd h# 10 c, 1 c, 0 c, 0 c, 1 c, 0 c, + +external + +\ Writes a file mark. + +: write-eof ( -- error? ) write-eof-cmd no-data-command ; + +headers + + +\ Writes a file mark if the tape has been written since the last seek +\ or rewind or write-eof. + +: ?write-eof ( -- ) + written? if + false to written? + write-eof if ." Can't write file mark." cr then + then +; + +create rewind-cmd 1 c, 1 c, 0 c, 0 c, 0 c, 0 c, + +: rewind ( -- error? ) \ Rewinds the tape. + ?write-eof + false to at-eof? + rewind-cmd no-data-command +; + +create skip-files-cmd h# 11 c, 1 c, 0 c, 0 c, 0 c, 0 c, + +: skip-files ( n -- error? ) \ Skips n file marks. + ?write-eof + false to at-eof? ( n ) + skip-files-cmd 2 + 3c! ( ) + skip-files-cmd no-data-command ( error? ) +; + +\ Asks the device its record length. +\ Also determines fixed or variable length. + +create block-limit-cmd 5 c, 0 c, 0 c, 0 c, 0 c, 0 c, + +: 2c@ ( addr -- n ) 1 + -c@ c@ bwjoin ; + +: get-record-length ( -- ) + 6 block-limit-cmd 6 short-data-command if + d# 512 true ( blocksize fixed-len ) + else ( buffer ) + dup 1 + 3c@ swap 4 + 2c@ ( max-len min-len ) + over = ( blocksize fixed-len? ) + then ( blocksize fixed-len? ) + to fixed-len? ( blocksize ) + + dup parent-max-transfer u> if ( blocksize ) + drop parent-max-transfer ( blocksize' ) + then ( blocksize ) + + to /tapeblock ( ) +; + +true instance value first-install? \ Used for rewind-on-first-open. +\ Words to decode various interesting fields in the extended status buffer. +\ Used by actual-#blocks. + +\ Incorrect length +: ili? ( statbuf -- flag ) 2 + c@ h# 20 and 0<> ; + +\ End of Media, End of File, or Blank Check + +: eof? ( statbuf -- flag ) + dup 2 + c@ h# c0 and 0<> swap 3 + c@ h# f and 8 = or +; + + +\ Difference between requested count and actual count + +: residue ( statbuf -- residue ) 3 + 4c@ ; + + +0 instance value #requested \ Local variable for r/w-some and actual-#blocks + +\ Decodes the status information returned by the SCSI command to +\ determine the number of blocks actually tranferred. + +: actual-#blocks ( [[xstatbuf] hw-err? ] status -- #xfered flag ) + if \ Error ( true | xstatbuf false ) + if \ Hardware error; none tranferred ( ) + 0 false ( 0 false ) + else \ Decode status buffer ( xstatbuf ) + >r #requested ( #requested ) ( r: xstatbuf ) + r@ ili? r@ eof? or if ( #requested ) ( r: xstatbuf + r@ residue - ( #xfered ) ( r: xstatbuf + then ( #xfered ) ( r: xstatbuf + r> eof? ( #xfered flag ) + then + else \ no error, #request = #xfered ( ) + #requested false ( #xfered flag ) + then + to at-eof? +; + + +\ Reads or writes at most "#blks" blocks, returning the actual number +\ of blocks transferred, and an error indicator that is true if either a +\ fatal error occurs or the end of a tape file is reached. + +: r/w-some ( addr #blks input? cmd -- actual# error? ) + 0 cb! swap ( addr dir #blks ) + fixed-len? if ( addr dir #blks ) + + \ If the tape has fixed-length records, multiply the + \ requested number of blocks by the record size. + + dup to #requested ( addr dir #blks ) + dup /tapeblock * swap 1 ( addr dir #bytes cmd-cnt 1=fixed-len ) + + else \ variable length ( addr dir #bytes ) + + \ If the tape has variable length records, transfer one record. + + drop /tapeblock ( addr dir #bytes ) + dup to #requested ( addr dir #bytes ) + dup 0 ( addr dir #bytes cmd-cnt 0=variable-len ) + + then ( addr dir #bytes cmd-cnt byte1 ) + + 1 cb! cmdbuf 2 + 3c! ( addr dir #bytes ) + swap cmdbuf 6 -1 ( dma-addr,len dir cmd-addr,len #retries) + retry-command actual-#blocks ( actual# ) +; + +\ Discard (for read) or flush (for write) any bytes that are buffered by +\ the deblocker. + +: flush-deblocker ( -- ) + deblocker close-package init-deblocker drop +; + +external + + +\ The deblocker package calls max-transfer to determine an appropriate +\ internal buffer size. + +: max-transfer ( -- n ) + fixed-len? if + \ Use the largest multiple of /tapeblock that is <= parent-max-transfer. + parent-max-transfer /tapeblock / /tapeblock * + else + /tapeblock + then +; + +\ The deblocker package calls block-size to determine an appropriate +\ granularity for accesses. + +: block-size ( -- n ) + fixed-len? if /tapeblock else 1 then +; + +\ The deblocker uses read-blocks and write-blocks to access tape records. + +\ The assumption of sequential access is guaranteed because this code is only +\ called from the deblocker. Since the SCSI tape package implements its +\ own "seek" method, the deblocker seek method is never called, and the +\ deblocker's internal position only changes sequentially. + +: read-blocks ( addr block# #blocks -- #read ) + nip ( addr #blocks ) \ Sequential access + + \ Don't read past a file mark + at-eof? if 2drop 0 exit then ( addr #blocks ) + + true 8 r/w-some ( #read ) +; + +: write-blocks ( addr block# #blocks -- #read ) + nip ( addr #blocks ) \ Sequential access + true to written? ( addr #blocks ) + false h# a r/w-some ( #written ) +; + +\ Methods used by external clients + +: read ( addr len -- actual-len ) " read" deblocker $call-method ; + +: write ( addr len -- actual-len ) + " write" deblocker $call-method ( actual-len ) + flush-deblocker \ Make the tape structure reflect the write pattern +; + +: open ( -- okay? ) + my-unit " set-address" $call-parent + + \ It might be a good idea to do an inquiry here to determine the + \ device configuration, checking the result to see if the device + \ really is a tape. + + first-install? if + rewind if + ." Can't rewind tape" cr + false exit + then + false to first-install? + then + + get-record-length + + init-deblocker ( okay? ) +; + +: close ( -- ) + deblocker close-package + ?write-eof +; + +0 value buf +h# 200 constant /buf + +\ It would be better to keep track of the current file number and +\ just seek forward if the requested file number/position is greater +\ than the current file number/position. Taking care of end-of-file +\ conditions would be tricky though. + +: seek ( byte# file# -- error? ) + + flush-deblocker ( byte# file# ) + + rewind if 2drop true exit then ( byte# file# ) + + ?dup if ( byte# file# ) + skip-files if drop true exit then ( byte# ) + then ( byte# ) + + ?dup if ( byte# ) + /buf alloc-mem to buf + begin dup 0> while ( #remaining ) + buf over /buf min read ( #remaining #read ) + dup 0= if 2drop true exit then ( #remaining #read ) + - ( #remaining' ) + repeat ( 0 ) + drop ( ) + buf /buf free-mem ( ) + then ( ) + + false ( no-error ) +; + +: load ( loadaddr -- size ) + my-args dup if ( loadaddr addr len ) + $number if ( loadaddr ) + ." Invalid tape file number" cr ( loadaddr ) + drop 0 exit ( 0 ) + then ( loadaddr n ) + else ( loadaddr addr 0 ) + nip ( loadaddr 0 ) + then ( loadaddr file# ) + + 0 swap seek if ( loadaddr ) + ." Can't select the requested tape file" cr + 0 exit + then ( loadaddr ) + + \ Try to read the entire tape file. We ask for a huge size + \ (almost 2 Gbytes), and let the deblocker take care of + \ breaking it up into manageable chunks. The operation + \ will cease when a file mark is reached. + + h# 70000000 read ( size ) +; + +headers + diff --git a/toke/examples/simple.fs b/toke/examples/simple.fs new file mode 100644 index 0000000..00274d7 --- /dev/null +++ b/toke/examples/simple.fs @@ -0,0 +1,18 @@ +\ this is an fcode test file. + +fcode-version2 + +: gray ( n1 -- n2 ) + dup begin + 2/ swap over xor swap + while repeat + ; + +: macrotest + dup dup >> 1+ 1+ accept + ; + +\ another comment. + +fcode-end + diff --git a/toke/examples/version1.fs b/toke/examples/version1.fs new file mode 100644 index 0000000..eff449b --- /dev/null +++ b/toke/examples/version1.fs @@ -0,0 +1,18 @@ +version1 + +dup dup + +1 case +1 of " foo" endof +3 of " bar" endof +4 of " blubb" endof +endcase +offset16 +1 case +1 of " foo" endof +3 of " bar" endof +4 of " blubb" endof +endcase + + +fcode-end diff --git a/toke/examples/world.fs b/toke/examples/world.fs new file mode 100644 index 0000000..0bb52d2 --- /dev/null +++ b/toke/examples/world.fs @@ -0,0 +1,15 @@ +fcode-version2 +headers + +external +\ main and only function +: world + " Hello World!"(0A)"(0A)Forth is alife."(0A)" type + 0 exit + ; + +headers + +world + +fcode-end diff --git a/toke/macros.c b/toke/macros.c new file mode 100644 index 0000000..92d2933 --- /dev/null +++ b/toke/macros.c @@ -0,0 +1,138 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * macros.c - macro initialization and functions. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 by Stefan Reinauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#if defined(__linux__) && ! defined(__USE_BSD) +#define __USE_BSD +#endif +#include +#include + +#include "toke.h" + +typedef struct macro { + u8 *name; + u8 *alias; + struct macro *next; +} macro_t; + +static macro_t *macros=NULL; + +char *lookup_macro(char *name) +{ + macro_t *curr; + + for (curr=macros; curr!=NULL; curr=curr->next) + if (!strcasecmp(name,(char *)curr->name)) + break; + + return curr?(char *)curr->alias:NULL; +} + +int add_macro(char *name, char *alias) +{ + macro_t *curr; + + curr=malloc(sizeof(macro_t)); + if(!curr) { + printf("Out of memory while adding macro.\n"); + exit(-ENOMEM); + } + + curr->next=macros; + curr->name=(u8 *)name; + curr->alias=(u8 *)alias; + + macros=curr; + return 0; +} + +void init_macros(void) +{ + add_macro( "eval", "evaluate"); + add_macro( "(.)", "dup abs <# u#s swap sign u#>"); + add_macro( "<<", "lshift"); + add_macro( ">>", "rshift"); + add_macro( "?", "@ ."); + add_macro( "1+", "1 +"); + add_macro( "1-", "1 -"); + add_macro( "2+", "2 +"); + add_macro( "2-", "2 -"); + /* add_macro( "abort\"", "-2 throw"); */ + add_macro( "accept", "span @ -rot expect span @ swap span !"); + add_macro( "allot", "0 max 0 ?do 0 c, loop"); + add_macro( "blank", "bl fill"); + add_macro( "/c*", "chars"); + add_macro( "ca1+", "char+"); + add_macro( "carret", "h# d"); + add_macro( ".d", "base @ swap h# a base ! . base !"); + add_macro( "decode-bytes", ">r over r@ + swap r@ - rot r>"); + add_macro( "3drop", "drop 2drop"); + add_macro( "3dup", "2 pick 2 pick 2 pick"); + add_macro( "erase", "0 fill"); + add_macro( "false", "0"); + add_macro( ".h", "base @ swap h# 10 base ! . base !"); + add_macro( "linefeed", "h# a"); + add_macro( "/n*", "cells"); + add_macro( "na1+", "cell+"); + add_macro( "not", "invert"); + add_macro( "s.", "(.) type space"); + add_macro( "space", "bl emit"); + add_macro( "spaces", "0 max 0 ?do space loop"); + add_macro( "struct", "0"); + add_macro( "true", "-1"); + add_macro( "(u.)", "<# u#s u#>"); + + /* H.7 FCode name changes */ + add_macro( "decode-2int", "parse-2int"); + add_macro( "delete-attribute", "delete-property"); + add_macro( "get-inherited-attribute", "get-inherited-property"); + add_macro( "get-my-attribute", "get-my-property"); + add_macro( "get-package-attribute", "get-package-property"); + add_macro( "attribute", "property"); + add_macro( "flip", "wbflip"); + add_macro( "is", "to"); + add_macro( "lflips", "lwflips"); + add_macro( "map-sbus", "map-low"); + add_macro( "u*x", "um*"); + add_macro( "version", "fcode-revision"); + add_macro( "wflips", "wbflips"); + add_macro( "x+", "d+"); + add_macro( "x-", "d-"); + add_macro( "xdr+", "encode+"); + add_macro( "xdrbytes", "encode-bytes"); + add_macro( "xdrint", "encode-int"); + add_macro( "xdrphys", "encode-phys"); + add_macro( "xdrstring", "encode-string"); + add_macro( "xdrtoint", "decode-int"); + add_macro( "xdrtostring", "decode-string"); + add_macro( "xu/mod", "um/mod"); + + /* non standard but often used macros */ + add_macro( "name", "device-name"); + add_macro( "endif", "then"); +} diff --git a/toke/scanner.c b/toke/scanner.c new file mode 100644 index 0000000..0acd6ca --- /dev/null +++ b/toke/scanner.c @@ -0,0 +1,1169 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * scanner.c - simple scanner for forth files. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 by Stefan Reinauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include +#ifdef __GLIBC__ +#define __USE_XOPEN_EXTENDED +#endif +#include +#include +#include + +#include "toke.h" +#include "stack.h" +#include "stream.h" +#include "emit.h" +#include "dictionary.h" + +#define ERROR do { if (!noerrors) exit(-1); } while (0) + +extern u8 *start, *pc, *end, *opc, *ostart; +extern int verbose, noerrors; + +u8 *statbuf=NULL; +u16 nextfcode; +u8 base=0x0a; + +/* header pointers */ +u8 *fcode_hdr=NULL; +u8 *pci_hdr=NULL; + +/* pci data */ +bool pci_is_last_image=TRUE; +bool pci_want_header=FALSE; +u16 pci_revision=0x0001; +u16 pci_vpd=0x0000; + +bool offs16=TRUE; +static bool intok=FALSE, incolon=FALSE; +bool haveend=FALSE; + +static u8 *skipws(u8 *str) +{ + while (str && (*str=='\t' || *str==' ' || *str=='\n' )) { + if (*str=='\n') + lineno++; + str++; + } + + return str; +} + +static u8 *firstchar(u8 needle, u8 *str) +{ + while (str && *str!=needle) { + if (*str=='\n') + lineno++; + str++; + } + + return str; +} + +static unsigned long get_word(void) +{ + size_t len; + u8 *str; + + pc=skipws(pc); + if (pc>=end) + return 0; + + str=pc; + while (str && *str && *str!='\n' && *str!='\t' && *str!=' ') + str++; + + len=(size_t)(str-pc); + if (len>1023) { + printf("%s:%d: error: buffer overflow.\n", iname, lineno); + ERROR; + } + + memcpy(statbuf, pc, len); + statbuf[len]=0; + +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: read token '%s', length=%ld\n", + iname, lineno, statbuf, len); +#endif + pc+=len; + return len; +} + +static unsigned long get_until(char needle) +{ + u8 *safe; + unsigned long len; + + safe=pc; + pc=firstchar(needle,safe); + if (pc>=end) + return 0; + + len=(unsigned long)pc-(unsigned long)safe; + if (len>1023) { + printf("%s:%d: error: buffer overflow\n", iname, lineno); + ERROR; + } + + memcpy(statbuf, safe, len); + statbuf[len]=0; + return len; +} + +static long parse_number(u8 *start, u8 **endptr, int lbase) +{ + long val = 0; + int negative = 0, curr; + u8 *nptr=start; + + curr = *nptr; + if (curr == '-') { + negative=1; + nptr++; + } + + for (curr = *nptr; (curr = *nptr); nptr++) { + if ( curr == '.' ) + continue; + if ( curr >= '0' && curr <= '9') + curr -= '0'; + else if (curr >= 'a' && curr <= 'f') + curr += 10 - 'a'; + else if (curr >= 'A' && curr <= 'F') + curr += 10 - 'A'; + else + break; + + if (curr >= lbase) + break; + + val *= lbase; + val += curr; + } + +#ifdef DEBUG_SCANNER + if (curr) + printf( "%s:%d: warning: couldn't parse number '%s' (%d/%d)\n", + iname, lineno, start,curr,lbase); +#endif + + if (endptr) + *endptr=nptr; + + if (negative) + return -val; + return val; +} + +static u8 *get_sequence(u8 *walk) +{ + u8 val, pval[3]; + + pc++; /* skip the ( */ +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: hex field:", iname, lineno); +#endif + pval[1]=0; pval[2]=0; + + for(;;) { + while (!isxdigit(*pc) && (*pc) != ')') + pc++; + + pval[0]=*pc; + if (pval[0]==')') + break; + + pc++; /* this cannot be a \n */ + + pval[1]=*pc; + if ( *pc!=')' && *pc++=='\n' ) + lineno++; + + val=parse_number(pval, NULL, 16); + *(walk++)=val; +#ifdef DEBUG_SCANNER + printf(" %02x",val); +#endif + } +#ifdef DEBUG_SCANNER + printf("\n"); +#endif + + return walk; +} + +static unsigned long get_string(void) +{ + u8 *walk; + unsigned long len; + bool run=1; + u8 c, val; + + walk=statbuf; + while (run) { + switch ((c=*pc)) { + case '\\': + switch ((c=*(++pc))) { + case 'n': + /* newline */ + *(walk++)='\n'; + break; + case 't': + /* tab */ + *(walk++)='\t'; + break; + default: + val=parse_number(pc, &pc, base); +#ifdef DEBUG_SCANNER + if (verbose) + printf( "%s:%d: debug: escape code " + "0x%x\n",iname, lineno, val); +#endif + *(walk++)=val; + } + break; + case '\"': + pc++; /* skip the " */ + + /* printf("switching: %c\n",*pc); */ + switch(*pc) { + case '(': + walk=get_sequence(walk); + break; + case '"': + *(walk++)='"'; + pc++; + break; + case 'n': + *(walk++)='\n'; + pc++; + break; + case 'r': + *(walk++)='\r'; + pc++; + break; + case 't': + *(walk++)='\t'; + pc++; + break; + case 'f': + *(walk++)='\f'; + pc++; + break; + case 'l': + *(walk++)='\n'; + pc++; + break; + case 'b': + *(walk++)=0x08; + pc++; + break; + case '!': + *(walk++)=0x07; + pc++; + break; + case '^': + pc++; + c=toupper(*(pc++)); + *(walk++)=c-'A'; + break; + case '\n': + lineno++; + case ' ': + case '\t': + run=0; + break; + default: + *(walk++)=*(pc++); + break; + } + break; + default: + *(walk++)=c; + } + if (*pc++=='\n') lineno++; + } + + *(walk++)=0; + + if (pc>=end) + return 0; + + len=(unsigned long)walk-(unsigned long)statbuf; + if (len>1023) { + printf("%s:%d: error: buffer overflow\n", iname, lineno); + ERROR; + } +#ifdef DEBUG_SCANNER + if (verbose) + printf("%s:%d: debug: scanned string: '%s'\n", + iname, lineno, statbuf); +#endif + + return len>255?255:len; +} + +static int get_number(long *result) +{ + u8 lbase, *until; + long val; + + lbase=intok?0x10:base; + val=parse_number(statbuf,&until, lbase); + +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: parsing number: base 0x%x, val 0x%lx, " + "processed %ld of %ld bytes\n", iname, lineno, + lbase, val,(size_t)(until-statbuf), strlen((char *)statbuf)); +#endif + + if (until==(statbuf+strlen((char *)statbuf))) { + *result=val; + return 0; + } + + return -1; +} + +void init_scanner(void) +{ + statbuf=malloc(1024); + if (!statbuf) { + printf ("no memory.\n"); + exit(-1); + } +} + +void exit_scanner(void) +{ + free(statbuf); +} + +#define FLAG_EXTERNAL 0x01 +#define FLAG_HEADERS 0x02 +char *name, *alias; +int flags=0; + +static int create_word(void) +{ + unsigned long wlen; + + if (incolon) { + printf("%s:%d: error: creating words not allowed " + "in colon definition.\n", iname, lineno); + ERROR; + } + + if(nextfcode > 0xfff) { + printf("%s:%d: error: maximum number of fcode words " + "reached.\n", iname, lineno); + ERROR; + } + + wlen=get_word(); + name=strdup((char *)statbuf); + +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: defined new word %s, fcode no 0x%x\n", + iname, lineno, name, nextfcode); +#endif + add_token(nextfcode, name); + if (flags) { + if (flags&FLAG_EXTERNAL) + emit_token("external-token"); + else + emit_token("named-token"); + emit_string((u8 *)name, wlen); + } else + emit_token("new-token"); + + emit_fcode(nextfcode); + nextfcode++; + + return 0; +} + +static void encode_file( const char *filename ) +{ + FILE *f; + size_t s; + int i=0; + + if( !(f=fopen(filename,"rb")) ) { + printf("%s:%d: opening '%s':\n", iname, lineno, filename ); + ERROR; + return; + } + while( (s=fread(statbuf, 1, 255, f)) ) { + emit_token("b(\")"); + emit_string(statbuf, s); + emit_token("encode-bytes"); + if( i++ ) + emit_token("encode+"); + } + fclose( f ); +} + + +static void handle_internal(u16 tok) +{ + unsigned long wlen; + long offs1,offs2; + u16 itok; + +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: tokenizing control word '%s'\n", + iname, lineno, statbuf); +#endif + switch (tok) { + case BEGIN: + emit_token("b(resolve)"); + offs1=(unsigned long)opc; + opc=(u8 *)offs2; + offs2=offs1-(unsigned long)opc; + emit_offset(offs2); + opc=(u8 *)offs1; + break; + + case CASE: + emit_token("b(case)"); + dpush(0); + break; + + case ENDCASE: + /* first emit endcase, then calculate offsets. */ + emit_token("b(endcase)"); + + offs1=(unsigned long)opc; + + offs2=dpop(); + while (offs2) { + u16 tmp; + + opc=(u8 *)(ostart+offs2); + + /* we're using an fcode offset to temporarily + * store our linked list. At this point we take + * the signed fcode offset as unsigned as we know + * that the offset will always be >0. This code + * is still broken for any case statement that + * occurs after the fcode bytecode grows larger + * than 64kB + */ + tmp=receive_offset(); + + offs2=(unsigned long)offs1-(unsigned long)opc; + +#if defined(DEBUG_SCANNER) + printf ("%s:%d: debug: endcase offset 0x%lx\n", + iname,lineno, (unsigned long)offs2); +#endif + emit_offset(offs2); + offs2=tmp; + } + opc=(u8 *)offs1; + break; + + case OF: + emit_token("b(of)"); + dpush((unsigned long)(opc-ostart)); + emit_offset(0); + break; + + case ENDOF: + offs1=dpop(); + emit_token("b(endof)"); + + offs2=dpop(); + dpush((unsigned long)(opc-ostart)); + emit_offset(offs2); + + offs2=(unsigned long)(opc-ostart); + opc=(u8 *)(ostart+offs1); + offs1=offs2-offs1; + emit_offset(offs1); + + opc=(u8 *)(ostart+offs2); + break; + + case HEADERLESS: + flags=0; + break; + + case HEADERS: + flags=FLAG_HEADERS; + break; + + case DECIMAL: + /* in a definition this is expanded as macro "10 base !" */ + if (incolon) { + emit_token("b(lit)"); + emit_num32(0x0a); + emit_token("base"); + emit_token("!"); + } else + base=10; + break; + + case HEX: + if (incolon) { + emit_token("b(lit)"); + emit_num32(0x10); + emit_token("base"); + emit_token("!"); + } else + base=16; + break; + + case OCTAL: + if (incolon) { + emit_token("b(lit)"); + emit_num32(0x08); + emit_token("base"); + emit_token("!"); + } else + base=8; + break; + + case OFFSET16: + if (!offs16) + printf("%s:%d: switching to " + "16bit offsets.\n", iname, lineno); + emit_token("offset16"); + offs16=TRUE; + break; + + case IF: + emit_token("b?branch"); + dpush((unsigned long)opc); + emit_offset(0); + break; + + case CLEAVE: + case LEAVE: + emit_token("b(leave)"); + break; + + case LOOP: + emit_token("b(loop)"); + offs1=dpop(); + offs2=offs1-(unsigned long)opc; + emit_offset(offs2); + offs1=(unsigned long)opc; + opc=(u8 *)dpop(); + offs2=offs1-(unsigned long)opc; + emit_offset(offs2); + opc=(u8 *)offs1; + break; + + case CLOOP: + emit_token("b(+loop)"); + offs1=dpop(); + offs2=offs1-(unsigned long)opc; + emit_offset(offs2); + offs1=(unsigned long)opc; + opc=(u8 *)dpop(); + offs2=offs1-(unsigned long)opc; + emit_offset(offs2); + opc=(u8 *)offs1; + break; + + case GETTOKEN: + emit_token("b(')"); + wlen=get_word(); + itok=lookup_token((char *)statbuf); + if (itok==0xffff) { + printf("%s:%d: error: no such word '%s' in [']\n", + iname, lineno, statbuf); + ERROR; + } + /* FIXME check size, u16 or token */ + emit_fcode(itok); + break; + + case ASCII: + wlen=get_word(); + emit_token("b(lit)"); + emit_num32(statbuf[0]); + break; + + case CHAR: + if (incolon) + printf("%s:%d: warning: CHAR cannot be used inside " + "of a colon definition.\n", iname, lineno); + wlen=get_word(); + emit_token("b(lit)"); + emit_num32(statbuf[0]); + break; + + case CCHAR: + wlen=get_word(); + emit_token("b(lit)"); + emit_num32(statbuf[0]); + break; + + case UNTIL: + emit_token("b?branch"); + emit_offset(dpop()-(unsigned long)opc); + break; + + case WHILE: + emit_token("b?branch"); + dpush((unsigned long)opc); + emit_offset(0); + break; + + case REPEAT: + emit_token("bbranch"); + offs2=dpop(); + offs1=dpop(); + offs1-=(unsigned long)opc; + emit_offset(offs1); + + emit_token("b(>resolve)"); + offs1=(unsigned long)opc; + opc=(u8 *)offs2; + emit_offset(offs1-offs2); + opc=(u8 *)offs1; + break; + + case THEN: + emit_token("b(>resolve)"); + offs1=(unsigned long)opc; + opc=(u8 *)dpop(); + offs2=offs1-(unsigned long)opc; + emit_offset(offs2); + opc=(u8 *)offs1; + break; + + case TO: + emit_token("b(to)"); + break; + + case FLOAD: + { + u8 *oldstart, *oldpc, *oldend; + char *oldiname; + int oldlineno; + + wlen=get_word(); + + oldstart=start; oldpc=pc; oldend=end; + oldiname=iname; oldlineno=lineno; + + init_stream((char *)statbuf); + tokenize(); + close_stream(); + + iname=oldiname; lineno=oldlineno; + end=oldend; pc=oldpc; start=oldstart; + } + break; + + case STRING: + if (*pc++=='\n') lineno++; + wlen=get_string(); + emit_token("b(\")"); + emit_string(statbuf,wlen-1); + break; + + case PSTRING: + if (*pc++=='\n') lineno++; + wlen=get_string(); + emit_token("b(\")"); + emit_string(statbuf,wlen-1); + emit_token("type"); + break; + + case PBSTRING: + if (*pc++=='\n') lineno++; + get_until(')'); + emit_token("b(\")"); + emit_string(statbuf,strlen((char *)statbuf)-1); + emit_token("type"); + break; + + case SSTRING: + if (*pc++=='\n') lineno++; + get_until('"'); + emit_token("b(\")"); + emit_string(statbuf,strlen((char *)statbuf)-1); + pc++; /* skip " */ + break; + + case HEXVAL: + { + u8 basecpy=base; + long val; + + base=0x10; + wlen=get_word(); + if (!get_number(&val)) { + emit_token("b(lit)"); + emit_num32(val); + } else { + printf("%s:%d: warning: illegal value in h#" + " ignored\n", iname, lineno); + } + base=basecpy; + } + break; + + case DECVAL: + { + u8 basecpy=base; + long val; + + base=0x0a; + wlen=get_word(); + if (!get_number(&val)) { + emit_token("b(lit)"); + emit_num32(val); + } else { + printf("%s:%d: warning: illegal value in d#" + " ignored\n", iname, lineno); + } + + base=basecpy; + } + break; + + case OCTVAL: + { + u8 basecpy=base; + long val; + + base=0x08; + wlen=get_word(); + if (!get_number(&val)) { + emit_token("b(lit)"); + emit_num32(val); + } else { + printf("%s:%d: warning: illegal value in o#" + " ignored\n", iname, lineno); + } + + base=basecpy; + } + break; + case BEGINTOK: + intok=TRUE; + break; + + case EMITBYTE: + if (intok) + emit_byte(dpop()); + else + printf ("%s:%d: warning: emit-byte outside tokenizer" + " scope\n", iname, lineno); + break; + + case NEXTFCODE: + if (intok) + nextfcode=dpop(); + else + printf("%s:%d: warning: next-fcode outside tokenizer" + " scope\n", iname, lineno); + break; + + case ENDTOK: + intok=FALSE; + break; + + case VERSION1: + case FCODE_V1: + printf("%s:%d: using version1 header\n", iname, lineno); + emit_token("version1"); + fcode_hdr=opc; + emit_fcodehdr(); + offs16=FALSE; + break; + + case START1: + case FCODE_V2: + case FCODE_V3: /* Full IEEE 1275 */ + emit_token("start1"); + fcode_hdr=opc; + emit_fcodehdr(); + offs16=TRUE; + break; + + case START0: + printf ("%s:%d: warning: spread of 0 not supported.", + iname, lineno); + emit_token("start0"); + fcode_hdr=opc; + emit_fcodehdr(); + offs16=TRUE; + break; + + case START2: + printf ("%s:%d: warning: spread of 2 not supported.", + iname, lineno); + emit_token("start2"); + fcode_hdr=opc; + emit_fcodehdr(); + offs16=TRUE; + break; + + case START4: + printf ("%s:%d: warning: spread of 4 not supported.", + iname, lineno); + emit_token("start4"); + fcode_hdr=opc; + emit_fcodehdr(); + offs16=TRUE; + break; + + case END0: + case FCODE_END: + haveend=TRUE; + emit_token("end0"); + break; + + case END1: + haveend=TRUE; + emit_token("end1"); + break; + + case RECURSIVE: + break; + + case PCIHDR: + { + u32 classid=dpop(); + u16 did=dpop(); + u16 vid=dpop(); + + pci_hdr=opc; + emit_pcihdr(vid, did, classid); + + printf("%s:%d: PCI header vendor id=0x%04x, " + "device id=0x%04x, class=%06x\n", + iname, lineno, vid, did, classid); + } + break; + + case PCIEND: + if (!pci_hdr) { + printf("%s:%d: error: pci-header-end/pci-end " + "without pci-header\n", iname, lineno); + ERROR; + } + finish_pcihdr(); + break; + + case PCIREV: + pci_revision=dpop(); + printf("%s:%d: PCI header revision=0x%04x\n", + iname, lineno, pci_revision); + break; + + case NOTLAST: + pci_is_last_image=FALSE; + printf("%s:%d: PCI header not last image!\n", + iname, lineno); + break; + + case ABORTTXT: + /* ABORT" is not to be used in FCODE drivers + * but Apple drivers do use it. Therefore we + * allow it. We push the specified string to + * the stack, do -2 THROW and hope that THROW + * will correctly unwind the stack. + */ + + printf("%s:%d: warning: ABORT\" in fcode not defined by " + "IEEE 1275-1994.\n", iname, lineno); + if (*pc++=='\n') lineno++; + wlen=get_string(); + +#ifdef BREAK_COMPLIANCE + /* IF */ + emit_token("b?branch"); + + dpush((unsigned long)opc); + emit_offset(0); +#endif + emit_token("b(\")"); + emit_string(statbuf,wlen-1); +#ifdef BREAK_COMPLIANCE + emit_token("type"); +#endif + emit_token("-2"); + emit_token("throw"); +#ifdef BREAK_COMPLIANCE + /* THEN */ + emit_token("b(>resolve)"); + offs1=(unsigned long)opc; + opc=(u8 *)dpop(); + offs2=offs1-(unsigned long)opc; + emit_offset(offs2); + opc=(u8 *)offs1; +#endif + break; + + case FCODE_DATE: + { + time_t tt; + char fcode_date[11]; + + tt=time(NULL); + strftime(fcode_date, 11, "%m/%d.%Y", + localtime(&tt)); + emit_token("b(\")"); + emit_string((u8 *)fcode_date,10); + } + break; + + case FCODE_TIME: + { + time_t tt; + char fcode_time[9]; + + tt=time(NULL); + strftime(fcode_time, 9, "%H:%M:%S", + localtime(&tt)); + emit_token("b(\")"); + emit_string((u8 *)fcode_time,8); + } + break; + + case ENCODEFILE: + wlen=get_word(); + encode_file( (char*)statbuf ); + break; + + default: + printf("%s:%d: error: Unimplemented control word '%s'\n", + iname, lineno, statbuf); + ERROR; + } +} + +void tokenize(void) +{ + unsigned long wlen; + u16 tok; + u8 *mac; + long val; + + while ((wlen=get_word())!=0) { + + /* Filter comments */ + switch (statbuf[0]) { + case '\\': + pc-=wlen; + get_until('\n'); + continue; + + case '(': + /* only a ws encapsulated '(' is a stack comment */ + if (statbuf[1]) + break; + + pc-=wlen; + get_until(')'); + if (*pc++=='\n') lineno++; +#ifdef DEBUG_SCANNER + printf ("%s:%d: debug: stack diagram: %s)\n", + iname, lineno, statbuf); +#endif + continue; + } + + /* Check whether a macro with given name exists */ + + mac=(u8 *)lookup_macro((char *)statbuf); + if(mac) { + u8 *oldstart, *oldpc, *oldend; +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: macro %s folds out to sequence" + " '%s'\n", iname, lineno, statbuf, mac); +#endif + oldstart=start; oldpc=pc; oldend=end; + start=pc=end=mac; + end+=strlen((char *)mac); + + tokenize(); + + end=oldend; pc=oldpc; start=oldstart; + + continue; + } + + /* Check whether it's a non-fcode forth construct */ + + tok=lookup_fword((char *)statbuf); + if (tok!=0xffff) { +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: matched internal opcode 0x%04x\n", + iname, lineno, tok); +#endif + handle_internal(tok); +#ifdef DEBUG_SCANNER + if (verbose) + printf("%s:%d: debug: '%s' done.\n", + iname,lineno,statbuf); +#endif + continue; + } + + /* Check whether it's one of the defined fcode words */ + + tok=lookup_token((char *)statbuf); + if (tok!=0xffff) { +#ifdef DEBUG_SCANNER + printf("%s:%d: debug: matched fcode no 0x%04x\n", + iname, lineno, tok); +#endif + emit_fcode(tok); + continue; + } + + /* It's not a word or macro - is it a number? */ + + if (!get_number(&val)) { + if (intok) + dpush(val); + else { + emit_fcode(lookup_token("b(lit)")); + emit_num32(val); + } + continue; + } + + /* could not identify - bail out. */ + + printf("%s:%d: error: word '%s' is not in dictionary.\n", + iname, lineno, statbuf); + ERROR; + } +} + diff --git a/toke/stack.c b/toke/stack.c new file mode 100644 index 0000000..4bd20f4 --- /dev/null +++ b/toke/stack.c @@ -0,0 +1,116 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * stack.c - data and return stack handling for fcode tokenizer. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 by Stefan Reinauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include + +#include "toke.h" +#include "stack.h" + + +#define GUARD_STACK +#define EXIT_STACKERR + +#ifdef GLOBALSTACK +#define STATIC static +#else +#define STATIC +#endif +STATIC long *dstack,*startdstack,*enddstack; +#undef STATIC + +/* internal stack functions */ + +int init_stack(void) +{ + startdstack=enddstack=malloc(MAX_ELEMENTS*sizeof(long)); + enddstack+=MAX_ELEMENTS; + dstack=enddstack; + return 0; +} + +#ifdef GLOBALSTACK + +#ifdef GUARD_STACK +static void stackerror(int stat) +{ + printf ("FATAL: stack %sflow\n", + (stat)?"under":"over" ); +#ifdef EXIT_STACKERR + exit(-1); +#endif +} +#endif + +void dpush(long data) +{ +#ifdef DEBUG_DSTACK + printf("dpush: sp=%p, data=0x%lx, ", dstack, data); +#endif + *(--dstack)=data; +#ifdef GUARD_STACK + if (dstackenddstack) stackerror(1); +#endif + return val; +} + +long dget(void) +{ + return *(dstack); +} +#endif + +/* Stack helper functions */ + +u8 *get_stackstring(void) +{ + long size; + u8 *fstring, *retstring; + + size=dpop(); + fstring=(u8 *)dpop(); + + retstring=malloc(size+1); + strncpy((char *)retstring, (const char *)fstring, size); + retstring[size]=0; + + return retstring; +} + + diff --git a/toke/stack.h b/toke/stack.h new file mode 100644 index 0000000..9aa5c53 --- /dev/null +++ b/toke/stack.h @@ -0,0 +1,46 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * stack.h - prototypes and defines for handling the stacks. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#ifdef ANSI_ONLY +#define GLOBALSTACK +#endif + +#define MAX_ELEMENTS 1024 + +#ifdef GLOBALSTACK +void dpush(long data); +long dpop(void); +long dget(void); +#else +extern long *dstack,*startdstack; +static inline void dpush(long data) { *(--dstack)=data; } +static inline long dpop(void) { return (long)*(dstack++); } +static inline long dget(void) { return *(dstack); } +#endif + +int init_stack(void); +u8 *get_stackstring(void); + diff --git a/toke/stream.c b/toke/stream.c new file mode 100644 index 0000000..094e2d8 --- /dev/null +++ b/toke/stream.c @@ -0,0 +1,165 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * stream.c - source program streaming from file. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 by Stefan Reinauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#ifdef __GLIBC__ +#define __USE_XOPEN_EXTENDED +#endif +#include +#include + +#include "toke.h" +#include "stream.h" + +#define OUTPUT_SIZE 131072 + +extern bool offs16; +extern u16 nextfcode; + +u8 *start, *pc, *end; +char *iname; + +/* output pointers */ +u8 *ostart, *opc, *oend, *oname; +static unsigned int ilen; + +unsigned int lineno; + +int init_stream( const char *name) +{ + FILE *infile; + unsigned int i; + + struct stat finfo; + + if (stat(name,&finfo)) + return -1; + + ilen=finfo.st_size; + start=malloc(ilen+1); + if (!start) + return -1; + + infile=fopen(name,"r"); + if (!infile) + return -1; + + if (fread(start, ilen, 1, infile)!=1) { + free(start); + return -1; + } + + fclose(infile); + + /* no zeroes within the file. */ + for (i=0; i> 7) & 0x0a; + } + start[ilen]=0; + + pc=start; + end=pc+ilen; + + iname=strdup(name); + + lineno=1; + + return 0; + +} + +int init_output( const char *in_name, const char *out_name ) +{ + const char *ext; + unsigned int len; /* should this be size_t? */ + + /* preparing output */ + + if( out_name ) + oname = (u8 *)strdup( out_name ); + else { + ext=strrchr(in_name, '.'); + len=ext ? (ext-in_name) : (unsigned int)strlen(in_name) ; + oname=malloc(len+4); + memcpy(oname, in_name, len); + oname[len] = 0; + strcat((char *)oname, ".fc"); + } + + /* output buffer size. this is 128k per default now, but we + * could reallocate if we run out. KISS for now. + */ + ostart=malloc(OUTPUT_SIZE); + if (!ostart) { + free(oname); + free(start); + return -1; + } + + opc=oend=ostart; + oend+=OUTPUT_SIZE; + + /* We're beginning a new output file, so we have to + * start our own fcode numbers at 0x800 again. + */ + nextfcode=0x800; + + return 0; +} + +int close_stream(void) +{ + free(start); + free(iname); + return 0; +} + +int close_output(void) +{ + FILE *outfile; + unsigned int len; + + len=(unsigned long)opc-(unsigned long)ostart; + + outfile=fopen((char *)oname,"w"); + if (!outfile) { + printf("toke: error opening output file.\n"); + return -1; + } + + if(fwrite(ostart, len, 1, outfile)!=1) + printf ("toke: error while writing output.\n"); + + fclose(outfile); + + printf("toke: wrote %d bytes to bytecode file '%s'\n", len, oname); + + free(oname); + return 0; +} + diff --git a/toke/stream.h b/toke/stream.h new file mode 100644 index 0000000..010c7fc --- /dev/null +++ b/toke/stream.h @@ -0,0 +1,38 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * stream.h - prototypes for streaming functions. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#ifndef _H_STREAM +#define _H_STREAM + +int init_stream( const char *name ); +int close_stream(void); +int init_output( const char *inname, const char *outname ); +int close_output(void); + +extern unsigned int lineno; +extern char *iname; + +#endif /* _H_STREAM */ diff --git a/toke/toke.c b/toke/toke.c new file mode 100644 index 0000000..b6b590f --- /dev/null +++ b/toke/toke.c @@ -0,0 +1,148 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * toke.c - main tokenizer loop and parameter parsing. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 by Stefan Reinauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#ifdef __GLIBC__ +#define _GNU_SOURCE +#include +#endif + +#include "toke.h" +#include "stream.h" +#include "stack.h" +#include "emit.h" + +#define TOKE_VERSION "0.6.10" + +int verbose=0; +int noerrors=0; + +static void print_copyright(void) +{ + printf( "Welcome to toke - OpenBIOS tokenizer v%s\nCopyright (c)" + " 2001-2005 by Stefan Reinauer \n" + "This program is free software; you may redistribute it " + "under the terms of\nthe GNU General Public License. This " + "program has absolutely no warranty.\n\n", TOKE_VERSION); +} + +static void usage(char *name) +{ + printf("usage: %s [-v] [-i] [-o target] \n\n",name); + printf(" -v|--verbose print debug messages\n"); + printf(" -i|--ignore-errors don't bail out after an error\n"); + printf(" -h|--help print this help message\n\n"); + +} + +int main(int argc, char **argv) +{ + const char *optstring="vhio:?"; + char *outputname = NULL; + int c; + + while (1) { +#ifdef __GLIBC__ + int option_index = 0; + static struct option long_options[] = { + { "verbose", 0, 0, 'v' }, + { "ignore-errors", 0, 0, 'i' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long (argc, argv, optstring, + long_options, &option_index); +#else + c = getopt (argc, argv, optstring); +#endif + if (c == -1) + break; + + switch (c) { + case 'v': + verbose=1; + break; + case 'o': + outputname = optarg; + break; + case 'i': + noerrors=1; + break; + case 'h': + case '?': + print_copyright(); + usage(argv[0]); + return 0; + default: + print_copyright(); + printf ("%s: unknown options.\n",argv[0]); + usage(argv[0]); + return 1; + } + } + + if (verbose) + print_copyright(); + + if (optind >= argc) { + print_copyright(); + printf ("%s: filename missing.\n",argv[0]); + usage(argv[0]); + return 1; + } + + init_stack(); + init_dictionary(); + init_macros(); + init_scanner(); + + while (optind < argc) { + if (init_stream(argv[optind])) { + printf ("%s: warning: could not open file \"%s\"\n", + argv[0], argv[optind]); + optind++; + continue; + } + init_output(argv[optind], outputname); + + tokenize(); + finish_headers(); + + close_output(); + close_stream(); + + optind++; + } + + exit_scanner(); + return 0; +} + diff --git a/toke/toke.h b/toke/toke.h new file mode 100644 index 0000000..16450d1 --- /dev/null +++ b/toke/toke.h @@ -0,0 +1,53 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * toke.h - tokenizer base macros. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#ifndef _H_TOKE +#define _H_TOKE + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int +#define s16 short +#define bool int +#define TRUE (-1) +#define FALSE (0) +#define ANSI_ONLY + +extern void init_scanner( void ); +extern void exit_scanner( void ); + +extern void init_dictionary( void ); +extern void init_macros( void ); +extern void tokenize( void ); + +extern u16 lookup_token(char *name); +extern u16 lookup_fword(char *name); +extern char *lookup_macro(char *name); +extern int add_token(u16 number, char *name); + +extern int add_macro(char *name, char *alias); + +#endif /* _H_TOKE */ diff --git a/utils/README b/utils/README new file mode 100644 index 0000000..1cfea45 --- /dev/null +++ b/utils/README @@ -0,0 +1,52 @@ +Here you find utilities useful for development and debugging of Open +Firmware systems. + +ofclient +-------- + +Sample OpenFirmware client. Can be booted directly from OpenFirmware +and demonstrates how an operating system can use the OpenFirmware +client interface. This example should work on PPC and x86 without +changes. + +romheaders +---------- +Romheaders is a small utility that dumps PCI expansion rom header +information in human readable form. It knows about Images with +multiple platform support and prints platform dependant information +for x86 and open firmware roms. + + +detok +----- +Detok is a GPLed FCode detokenizer. It can detokenize (disassemble) +fcode bytecode files as described by the IEEE 1275-1994 standard. This +program aims towards IEEE 1275-1994 compliancy, but there is no +warranty that it is actually compliant. bytecode files normally +contain Open Firmware drivers or other packages for use with an Open +Firmware compliant system. +See http://www.openbios.org/development/detok.html for more +information. + +devbios +------- +This is a kernel driver for different kind of (Flash)BIOSs that are +available in today's x86, ia64 (Itantium) or Alpha based hardware. + +fccc +---- +initial, incomplete implementation of an C to forth compiler. + + +dist +---- +rpm specfile and debian files for packing openbios with various +distributions. Changes/addons from distributors are explicitly +welcome. + + + + + + + diff --git a/utils/detok/COPYING b/utils/detok/COPYING new file mode 100644 index 0000000..8a6932a --- /dev/null +++ b/utils/detok/COPYING @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/utils/detok/ChangeLog b/utils/detok/ChangeLog new file mode 100644 index 0000000..7930d9c --- /dev/null +++ b/utils/detok/ChangeLog @@ -0,0 +1,75 @@ +*** 0.6.1 - 2005/03/10 ************************************************** + + * fix bug in output of strings. Strings were cut off when 0 bytes + occured, in a C manner. Now detok prints correct forth strings. + Thanks to Arti Itra for reporting this. + * free string after printing it. + +*********** 2003/12/14 ************************************************** + + * add interpose fcode + +*** 0.6 - 2003/11/24 **************************************************** + + * minor modifications + * release version 0.6 + +*********** 2003/08/16 ************************************************** + + * fit Makefile into openbios build process (allows out of place build) + +*********** 2002/07/12 ************************************************** + + * fix version1 headers. + +*** 0.5.2 - 2002/05/24 ************************************************** + + * fix detokenizing case..endcase expressions. + * update usage() and README to show all possible options + +*** 0.5.1 - 2002/03/30 ************************************************** + + * Tim Barrett : add prototypes for getopt()/optind to + detok.c as there seem to be some systems with an insane unistd.h. + * output fcode number, in case we have an unnamed fcode. + * make detok more silent per default. + * put DEBUG_ defines to Makefile (there's only one anyways). + +*** 0.5 - 2002/02/27 **************************************************** + + * change indent size to 4 + * added line numbers for debugging. + * added file offset output for debugging + * added checksum calculation + * input files.are buffered now. + * repair pretty print of strings. + * added 64bit extensions + * fix position decode at end of file. + +*** 0.3 - 2002/02/26 **************************************************** + + * removed autogenerator (create-array, supported.h and fcode-table.raw) + * organized dictionary as linked list. + * initialize dictionary during runtime. + +*** 0.2.3 - 2001/12/02 ************************************************** + + * ansi compilation fixes + * typos in fcode-table.raw fixed. + * removed debugging output. + +*** 0.2.2 - 2001/10/04 ************************************************** + + * fixed wrong indentation for loops. + * branch direction used for indentation. + * new option -a, --all to decode a file after end0 occured. + * fixed buffer overflow bug in get_string() + +*** 0.2.1 - 2001/09/10 ************************************************** + + * start0-4 are no exceptional cases but normal fcode words now + +*** 0.2 (release) - 2001/09/09 ****************************************** + + * initial release + diff --git a/utils/detok/Makefile b/utils/detok/Makefile new file mode 100644 index 0000000..a63ced9 --- /dev/null +++ b/utils/detok/Makefile @@ -0,0 +1,68 @@ +# +# OpenBIOS - free your system! +# ( detokenizer ) +# +# This program is part of a free implementation of the IEEE 1275-1994 +# Standard for Boot (Initialization Configuration) Firmware. +# +# Copyright (C) 2001-2005 Stefan Reinauer, +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA +# + +ARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/ -e "s/Power Macintosh/ppc/") +TOPDIR := $(shell /bin/pwd) +BUILDDIR ?= $(TOPDIR)/obj-$(ARCH) + +VPATH := $(BUILDDIR) + + +include $(TOPDIR)/Rules.make + + +CC = gcc +CFLAGS = -O2 -Wall -ansi + +# For debugging the indentation code of detok, define DEBUG_INDENT +#CFLAGS := $(CFLAGS) -DDEBUG_INDENT + +all: main detok + @echo -e "\nOpenBIOS detokenizer detok build finished\n" + +main: + @echo -e "\nWelcome to the OpenBIOS detokenizer.." + @test -r $(BUILDDIR) || ( mkdir -p $(BUILDDIR); \ + echo -e "\nCreating build directory $(BUILDDIR)" ) + +detok: detok.o dictionary.o decode.o stream.o + @echo -en "\nLinking fcode detokenizer detok..." + @cd $(BUILDDIR) && ( $(CC) $(CFLAGS) $^ -o $@; strip detok ) + @echo -e "\tok" + +clean: + @test ! -d $(BUILDDIR) && \ + echo "Architecture $(ARCH) is already clean." || \ + ( \ + echo "Cleaning up architecture $(ARCH)"; \ + rm -rf $(BUILDDIR) \ + rm forth.dict.core \ + ) + +distclean: clean + rm -f detok + +detok.o: detok.h stream.h detok.c +stream.o: detok.h stream.c +decode.o: detok.h stream.h decode.c Makefile +dictionary.o: detok.h dictionary.c diff --git a/utils/detok/README b/utils/detok/README new file mode 100644 index 0000000..edf55aa --- /dev/null +++ b/utils/detok/README @@ -0,0 +1,80 @@ +Welcome to the OpenBIOS detokenizer README. + +----------------------------------------------------------- + +Table of Contents: + +1. What is the OpenBIOS detokenizer? +2. What is required to build the OpenBIOS detokenizer? +3. How to use the OpenBIOS detokenizer +4. Contact + +----------------------------------------------------------- + +1. What is the OpenBIOS detokenizer? + + detok is a GPLed FCode detokenizer. It can detokenize (disassemble) + fcode bytecode files as described by the IEEE 1275-1994 standard. + This program aims towards IEEE 1275-1994 compliance, but there is no + warranty that it is actually compliant. Bytecode files, such as used + with detok, normally contain Open Firmware drivers or other packages + for use with an Open Firmware compliant system. + + +2. What is required to build the OpenBIOS detokenizer? + + detok should build with any ANSI compliant C compiler, although + currently only Linux on i386/alpha/ia64 are tested. To build detok + on other platforms you might have to adjust the Makefile. + To build detok, just enter "make". To clean up an existing build, + use "make clean" or "make distclean". + + +3. How to use the OpenBIOS detokenizer + + detok has a couple of options that can be used for detokenizing + fcode binaries. To use detok, use the following syntax: + + $ detok [OPTION]... [FCODE-FILE]... + + The following options are available: + + -v, --verbose print fcode numbers + -a, --all don't stop at end0 + -n, --linenumbers print line numbers + -o, --offsets print byte offsets + -h, --help print this help text + + Please note: Long options are not available on all systems. + + Example: + + $ detok -ov world.fc + Welcome to the OpenBIOS detokenizer v0.6.1 + detok Copyright(c) 2001-2005 by Stefan Reinauer. + Written by Stefan Reinauer, + This program is free software; you may redistribute it under the terms of + the GNU General Public License. This program has absolutely no warranty. + + 0: start1 [0x0f1] + 1: format: 0x08 + 2: checksum: 0x0fc1 (Ok) + 4: len: 0x39 (57 bytes) + 8: external-token [0x0ca] world 0x800 + 17: b(:) [0x0b7] + 18: b(") [0x012] "Hello World!" 0x0a 0x0a"Forth is alife." 0x0a + 50: type [0x090] + 51: 0 [0x0a5] + 52: exit [0x033] + 53: b(;) [0x0c2] + 54: world [0x800] + 56: end0 [0x000] + 57: \ detokenizing finished after 57 of 57 bytes. + + +4. Contact + + Any ideas, bug reports, patches, contributions, discussion is + welcome. + + Stefan Reinauer diff --git a/utils/detok/Rules.make b/utils/detok/Rules.make new file mode 100644 index 0000000..db82ed6 --- /dev/null +++ b/utils/detok/Rules.make @@ -0,0 +1,17 @@ +# tag: Makefile rules + +VPATH := $(VPATH):. + +.S.o: + echo -n " assembling $<... " + $(CC) -c -nostdlib $(INCLUDES) $(CFLAGS) $< -o $(BUILDDIR)/$@ && \ + echo -e " \t\tok" || \ + echo -e " \t\tfailed" + +.c.o: + @echo -n " compiling $<... " + @$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILDDIR)/$@ && \ + echo -e " \t\tok" || \ + echo -e " \t\failed" + + diff --git a/utils/detok/decode.c b/utils/detok/decode.c new file mode 100644 index 0000000..1fee2b3 --- /dev/null +++ b/utils/detok/decode.c @@ -0,0 +1,332 @@ +/* + * OpenBIOS - free your system! + * ( detokenizer ) + * + * decode.c - contains output wrappers for fcode words. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include + +#include "detok.h" +#include "stream.h" + +/* Dictionary function prototypes */ +char *lookup_token(u16 number); +int add_token(u16 number, char *name); + +extern u16 fcode; + +bool offs16=TRUE; +int indent, verbose=0, decode_all=0, linenumbers=0, linenum; +u32 fclen; + +static u8 *unnamed=(u8 *)"(unnamed-fcode)"; + +void pretty_string(u8 *string) +{ + u8 c; + unsigned int i; + bool qopen=TRUE; + + printf("\" "); + + for (i=1; i<1+(unsigned int)string[0]; i++) { + c=string[i]; + if (isprint(c)) { + if (!qopen) { + printf(" )"); + qopen=TRUE; + } + printf("%c",c); + } else { + if (qopen) { + printf("\"("); + qopen=FALSE; + } + printf(" %02x",c); + } + } + if (!qopen) + printf(" )"); + printf("\""); +} + +static void decode_indent(void) +{ + int i; +#ifdef DEBUG_INDENT + if (indent<0) { + printf("detok: error in indentation code.\n"); + indent=0; + } +#endif + for (i=0; i=0) + indent++; + else + indent--; +} + +static void decode_two(void) +{ + u16 token; + + output_token(); + token=get_token(); + decode_default(); +} + +static void decode_start(void) +{ + u8 fcformat; + u16 fcchecksum, checksum=0; + long pos; + u32 i; + + decode_default(); + + decode_lines(); + fcformat=get_num8(); + printf(" format: 0x%02x\n", fcformat); + + decode_lines(); + fcchecksum=get_num16(); + /* missing: check for checksum correctness. */ + + fclen=get_num32(); /* skip len */ + pos=get_streampos(); + + for (i=0; iresolve) */ + case 0x0c5: /* b(endcase) */ + decode_default(); + indent--; + break; + case 0x015: /* b(loop) */ + case 0x016: /* b(+loop) */ + case 0x0c6: /* b(endof) */ + decode_offset(); + indent--; + break; + case 0x017: /* b(do) */ + case 0x018: /* b/?do) */ + case 0x01c: /* b(of) */ + decode_offset(); + indent++; + break; + case 0x011: /* b(') */ + case 0x0c3: /* b(to) */ + decode_two(); + break; + case 0x0f0: /* start0 */ + case 0x0f1: /* start1 */ + case 0x0f2: /* start2 */ + case 0x0f3: /* start4 */ + decode_start(); + break; + case 0x0fd: /* version1 */ + decode_start(); + offs16=FALSE; + break; + default: + decode_default(); + } +} + +int detokenize(void) +{ + u16 token; + + if (linenumbers) + linenum=1; + + do { + decode_lines(); + decode_indent(); + token=get_token(); + decode_token(token); + } while ((token||decode_all) && ((get_streampos()-1)<=fclen)); + + decode_lines(); + printf ("\\ detokenizing finished after %d of %d bytes.\n", + get_streampos(), fclen ); + + return 0; +} diff --git a/utils/detok/detok.c b/utils/detok/detok.c new file mode 100644 index 0000000..1507a38 --- /dev/null +++ b/utils/detok/detok.c @@ -0,0 +1,158 @@ +/* + * OpenBIOS - free your system! + * ( detokenizer ) + * + * detok.c parameter parsing and main detokenizer loop. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include +#include +#ifdef __GLIBC__ +#define _GNU_SOURCE +#include +#else +/* Some systems seem to have an incomplete unistd.h. + * We need to define getopt() and optind for them. + */ +extern int optind; +int getopt(int argc, char * const argv[], const char *optstring); +#endif + +#include "detok.h" +#include "stream.h" + +#define DETOK_VERSION "0.6.1" + +/* prototypes for dictionary handling */ +void init_dictionary(void); +void decode_token(u16 token); +/* prototype for detokenizer function */ +int detokenize(void); + +extern unsigned int decode_all, verbose, linenumbers; + +void print_copyright(void) +{ + printf( "Welcome to the OpenBIOS detokenizer v%s\ndetok Copyright" + "(c) 2001-2005 by Stefan Reinauer.\nWritten by Stefan " + "Reinauer, \n" "This program is " + "free software; you may redistribute it under the terms of\n" + "the GNU General Public License. This program has absolutely" + " no warranty.\n\n" ,DETOK_VERSION); +} + +void usage(char *name) +{ + printf( "usage: %s [OPTION]... [FCODE-FILE]...\n\n" + " -v, --verbose print fcode numbers\n" + " -a, --all don't stop at end0\n" + " -n, --linenumbers print line numbers\n" + " -o, --offsets print byte offsets\n" + " -h, --help print this help text\n\n", name); +} + +int main(int argc, char **argv) +{ + int c; + const char *optstring="vhano?"; + + while (1) { +#ifdef __GLIBC__ + int option_index = 0; + static struct option long_options[] = { + { "verbose", 0, 0, 'v' }, + { "help", 0, 0, 'h' }, + { "all", 0, 0, 'a' }, + { "linenumbers", 0, 0, 'n' }, + { "offsets", 0, 0, 'o' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long (argc, argv, optstring, + long_options, &option_index); +#else + c = getopt (argc, argv, optstring); +#endif + if (c == -1) + break; + + switch (c) { + case 'v': + verbose=1; + break; + case 'a': + decode_all=1; + break; + case 'n': + linenumbers|=1; + break; + case 'o': + linenumbers|=2; + break; + case 'h': + case '?': + print_copyright(); + usage(argv[0]); + return 0; + default: + print_copyright(); + printf ("%s: unknown option.\n",argv[0]); + usage(argv[0]); + return 1; + } + } + + if (verbose) + print_copyright(); + + if (linenumbers>2) + printf("Line numbers will be disabled in favour of offsets.\n"); + + if (optind >= argc) { + print_copyright(); + printf ("%s: filename missing.\n",argv[0]); + usage(argv[0]); + return 1; + } + + init_dictionary(); + + while (optind < argc) { + + if (init_stream(argv[optind])) { + printf ("Could not open file \"%s\".\n",argv[optind]); + optind++; + continue; + } + detokenize(); + close_stream(); + + optind++; + } + + printf("\n"); + + return 0; +} + diff --git a/utils/detok/detok.h b/utils/detok/detok.h new file mode 100644 index 0000000..17c2b16 --- /dev/null +++ b/utils/detok/detok.h @@ -0,0 +1,33 @@ +/* + * OpenBIOS - free your system! + * ( detokenizer ) + * + * detok.h - detokenizer base macros. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int +#define s16 short +#define bool int +#define TRUE (-1) +#define FALSE (0) diff --git a/utils/detok/dictionary.c b/utils/detok/dictionary.c new file mode 100644 index 0000000..46eff92 --- /dev/null +++ b/utils/detok/dictionary.c @@ -0,0 +1,460 @@ +/* + * OpenBIOS - free your system! + * ( detokenizer ) + * + * dictionary.c - dictionary initialization and functions. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include + +#include "detok.h" + +typedef struct token { + u8 *name; + u16 fcode; + struct token *next; +} token_t; + +static char *fcerror="ferror"; +token_t *dictionary=NULL; + +char *lookup_token(u16 number) +{ + token_t *curr; + + for (curr=dictionary; curr!=NULL; curr=curr->next) + if (curr->fcode==number) + break; + + if (curr) + return curr->name; + + return fcerror; +} + +int add_token(u16 number, char *name) +{ + token_t *curr; + + curr=malloc(sizeof(token_t)); + if(!curr) { + printf("Out of memory while adding token.\n"); + exit(-ENOMEM); + } + + curr->next=dictionary; + curr->fcode=number; + curr->name=name; + + dictionary=curr; + return 0; +} + +void init_dictionary(void) +{ + add_token( 0x000, "end0" ); + add_token( 0x010, "b(lit)" ); + add_token( 0x011, "b(')" ); + add_token( 0x012, "b(\")" ); + add_token( 0x013, "bbranch" ); + add_token( 0x014, "b?branch" ); + add_token( 0x015, "b(loop)" ); + add_token( 0x016, "b(+loop)" ); + add_token( 0x017, "b(do)" ); + add_token( 0x018, "b(?do)" ); + add_token( 0x019, "i" ); + add_token( 0x01a, "j" ); + add_token( 0x01b, "b(leave)" ); + add_token( 0x01c, "b(of)" ); + add_token( 0x01d, "execute" ); + add_token( 0x01e, "+" ); + add_token( 0x01f, "-" ); + add_token( 0x020, "*" ); + add_token( 0x021, "/" ); + add_token( 0x022, "mod" ); + add_token( 0x023, "and" ); + add_token( 0x024, "or" ); + add_token( 0x025, "xor" ); + add_token( 0x026, "invert" ); + add_token( 0x027, "lshift" ); + add_token( 0x028, "rshift" ); + add_token( 0x029, ">>a" ); + add_token( 0x02a, "/mod" ); + add_token( 0x02b, "u/mod" ); + add_token( 0x02c, "negate" ); + add_token( 0x02d, "abs" ); + add_token( 0x02e, "min" ); + add_token( 0x02f, "max" ); + add_token( 0x030, ">r" ); + add_token( 0x031, "r>" ); + add_token( 0x032, "r@" ); + add_token( 0x033, "exit" ); + add_token( 0x034, "0=" ); + add_token( 0x035, "0<>" ); + add_token( 0x036, "0<" ); + add_token( 0x037, "0<=" ); + add_token( 0x038, "0>" ); + add_token( 0x039, "0>=" ); + add_token( 0x03a, "<" ); + add_token( 0x03b, ">" ); + add_token( 0x03c, "=" ); + add_token( 0x03d, "<>" ); + add_token( 0x03e, "u>" ); + add_token( 0x03f, "u<=" ); + add_token( 0x040, "u<" ); + add_token( 0x041, "u>=" ); + add_token( 0x042, ">=" ); + add_token( 0x043, "<=" ); + add_token( 0x044, "between" ); + add_token( 0x045, "within" ); + add_token( 0x046, "drop" ); + add_token( 0x047, "dup" ); + add_token( 0x048, "over" ); + add_token( 0x049, "swap" ); + add_token( 0x04A, "rot" ); + add_token( 0x04b, "-rot" ); + add_token( 0x04c, "tuck" ); + add_token( 0x04d, "nip" ); + add_token( 0x04e, "pick" ); + add_token( 0x04f, "roll" ); + add_token( 0x050, "?dup" ); + add_token( 0x051, "depth" ); + add_token( 0x052, "2drop" ); + add_token( 0x053, "2dup" ); + add_token( 0x054, "2over" ); + add_token( 0x055, "2swap" ); + add_token( 0x056, "2rot" ); + add_token( 0x057, "2/" ); + add_token( 0x058, "u2/" ); + add_token( 0x059, "2*" ); + add_token( 0x05a, "/c" ); + add_token( 0x05b, "/w" ); + add_token( 0x05c, "/l" ); + add_token( 0x05d, "/n" ); + add_token( 0x05e, "ca+" ); + add_token( 0x05f, "wa+" ); + add_token( 0x060, "la+" ); + add_token( 0x061, "na+" ); + add_token( 0x062, "char+" ); + add_token( 0x063, "wa1+" ); + add_token( 0x064, "la1+" ); + add_token( 0x065, "cell+" ); + add_token( 0x066, "chars" ); + add_token( 0x067, "/w*" ); + add_token( 0x068, "/l*" ); + add_token( 0x069, "cells" ); + add_token( 0x06a, "on" ); + add_token( 0x06b, "off" ); + add_token( 0x06c, "+!" ); + add_token( 0x06d, "@" ); + add_token( 0x06e, "l@" ); + add_token( 0x06f, "w@" ); + add_token( 0x070, "" ); + add_token( 0x086, ">body" ); + add_token( 0x087, "fcode-revision" ); + add_token( 0x088, "span" ); + add_token( 0x089, "unloop" ); + add_token( 0x08a, "expect" ); + add_token( 0x08b, "alloc-mem" ); + add_token( 0x08c, "free-mem" ); + add_token( 0x08d, "key?" ); + add_token( 0x08e, "key" ); + add_token( 0x08f, "emit" ); + add_token( 0x090, "type" ); + add_token( 0x091, "(cr" ); + add_token( 0x092, "cr" ); + add_token( 0x093, "#out" ); + add_token( 0x094, "#line" ); + add_token( 0x095, "hold" ); + add_token( 0x096, "<#" ); + add_token( 0x097, "u#>" ); + add_token( 0x098, "sign" ); + add_token( 0x099, "u#" ); + add_token( 0x09a, "u#s" ); + add_token( 0x09b, "u." ); + add_token( 0x09c, "u.r" ); + add_token( 0x09d, "." ); + add_token( 0x09e, ".r" ); + add_token( 0x09f, ".s" ); + add_token( 0x0a0, "base" ); + add_token( 0x0a1, "convert" ); + add_token( 0x0a2, "$number" ); + add_token( 0x0a3, "digit" ); + add_token( 0x0a4, "-1" ); + add_token( 0x0a5, "0" ); + add_token( 0x0a6, "1" ); + add_token( 0x0a7, "2" ); + add_token( 0x0a8, "3" ); + add_token( 0x0a9, "bl" ); + add_token( 0x0aa, "bs" ); + add_token( 0x0ab, "bell" ); + add_token( 0x0ac, "bounds" ); + add_token( 0x0ad, "here" ); + add_token( 0x0ae, "aligned" ); + add_token( 0x0af, "wbsplit" ); + add_token( 0x0b0, "bwjoin" ); + add_token( 0x0b1, "b(resolve)" ); + add_token( 0x0b3, "set-token-table" ); + add_token( 0x0b4, "set-table" ); + add_token( 0x0b5, "new-token" ); + add_token( 0x0b6, "named-token" ); + add_token( 0x0b7, "b(:)" ); + add_token( 0x0b8, "b(value)" ); + add_token( 0x0b9, "b(variable)" ); + add_token( 0x0ba, "b(constant)" ); + add_token( 0x0bb, "b(create)" ); + add_token( 0x0bc, "b(defer)" ); + add_token( 0x0bd, "b(buffer:)" ); + add_token( 0x0be, "b(field)" ); + add_token( 0x0bf, "b(code)" ); + add_token( 0x0c0, "instance" ); + add_token( 0x0c2, "b(;)" ); + add_token( 0x0c3, "b(to)" ); + add_token( 0x0c4, "b(case)" ); + add_token( 0x0c5, "b(endcase)" ); + add_token( 0x0c6, "b(endof)" ); + add_token( 0x0c7, "#" ); + add_token( 0x0c8, "#s" ); + add_token( 0x0c9, "#>" ); + add_token( 0x0ca, "external-token" ); + add_token( 0x0cb, "$find" ); + add_token( 0x0cc, "offset16" ); + add_token( 0x0cd, "evaluate" ); + add_token( 0x0d0, "c," ); + add_token( 0x0d1, "w," ); + add_token( 0x0d2, "l," ); + add_token( 0x0d3, "," ); + add_token( 0x0d4, "um*" ); + add_token( 0x0d5, "um/mod" ); + add_token( 0x0d8, "d+" ); + add_token( 0x0d9, "d-" ); + add_token( 0x0da, "get-token" ); + add_token( 0x0db, "set-token" ); + add_token( 0x0dc, "state" ); + add_token( 0x0dd, "compile" ); + add_token( 0x0de, "behavior" ); + add_token( 0x0f0, "start0" ); + add_token( 0x0f1, "start1" ); + add_token( 0x0f2, "start2" ); + add_token( 0x0f3, "start4" ); + add_token( 0x0fc, "ferror" ); + add_token( 0x0fd, "version1" ); + add_token( 0x0fe, "4-byte-id" ); + add_token( 0x0ff, "end1" ); + add_token( 0x101, "dma-alloc" ); + add_token( 0x102, "my-address" ); + add_token( 0x103, "my-space" ); + add_token( 0x104, "memmap" ); + add_token( 0x105, "free-virtual" ); + add_token( 0x106, ">physical" ); + add_token( 0x10f, "my-params" ); + add_token( 0x110, "property" ); + add_token( 0x111, "encode-int" ); + add_token( 0x112, "encode+" ); + add_token( 0x113, "encode-phys" ); + add_token( 0x114, "encode-string" ); + add_token( 0x115, "encode-bytes" ); + add_token( 0x116, "reg" ); + add_token( 0x117, "intr" ); + add_token( 0x118, "driver" ); + add_token( 0x119, "model" ); + add_token( 0x11a, "device-type" ); + add_token( 0x11b, "parse-2int" ); + add_token( 0x11c, "is-install" ); + add_token( 0x11d, "is-remove" ); + add_token( 0x11e, "is-selftest" ); + add_token( 0x11f, "new-device" ); + add_token( 0x120, "diagnostic-mode?" ); + add_token( 0x121, "display-status" ); + add_token( 0x122, "memory-test-issue" ); + add_token( 0x123, "group-code" ); + add_token( 0x124, "mask" ); + add_token( 0x125, "get-msecs" ); + add_token( 0x126, "ms" ); + add_token( 0x127, "finish-device" ); + add_token( 0x128, "decode-phys" ); + add_token( 0x12b, "interpose" ); + add_token( 0x130, "map-low" ); + add_token( 0x131, "sbus-intr>cpu" ); + add_token( 0x150, "#lines" ); + add_token( 0x151, "#columns" ); + add_token( 0x152, "line#" ); + add_token( 0x153, "column#" ); + add_token( 0x154, "inverse?" ); + add_token( 0x155, "inverse-screen?" ); + add_token( 0x156, "frame-buffer-busy?" ); + add_token( 0x157, "draw-character" ); + add_token( 0x158, "reset-screen" ); + add_token( 0x159, "toggle-cursor" ); + add_token( 0x15a, "erase-screen" ); + add_token( 0x15b, "blink-screen" ); + add_token( 0x15c, "invert-screen" ); + add_token( 0x15d, "insert-characters" ); + add_token( 0x15e, "delete-characters" ); + add_token( 0x15f, "insert-lines" ); + add_token( 0x160, "delete-lines" ); + add_token( 0x161, "draw-logo" ); + add_token( 0x162, "frame-buffer-adr" ); + add_token( 0x163, "screen-height" ); + add_token( 0x164, "screen-width" ); + add_token( 0x165, "window-top" ); + add_token( 0x166, "window-left" ); + add_token( 0x16a, "default-font" ); + add_token( 0x16b, "set-font" ); + add_token( 0x16c, "char-height" ); + add_token( 0x16d, "char-width" ); + add_token( 0x16e, ">font" ); + add_token( 0x16f, "fontbytes" ); + add_token( 0x170, "fb1-draw-character" ); + add_token( 0x171, "fb1-reset-screen" ); + add_token( 0x172, "fb1-toggle-cursor" ); + add_token( 0x173, "fb1-erase-screen" ); + add_token( 0x174, "fb1-blink-screen" ); + add_token( 0x175, "fb1-invert-screen" ); + add_token( 0x176, "fb1-insert-characters" ); + add_token( 0x177, "fb1-delete-characters" ); + add_token( 0x178, "fb1-insert-lines" ); + add_token( 0x179, "fb1-delete-lines" ); + add_token( 0x17a, "fb1-draw-logo" ); + add_token( 0x17b, "fb1-install" ); + add_token( 0x17c, "fb1-slide-up" ); + add_token( 0x180, "fb8-draw-character" ); + add_token( 0x181, "fb8-reset-screen" ); + add_token( 0x182, "fb8-toggle-cursor" ); + add_token( 0x183, "fb8-erase-screen" ); + add_token( 0x184, "fb8-blink-screen" ); + add_token( 0x185, "fb8-invert-screen" ); + add_token( 0x186, "fb8-insert-characters" ); + add_token( 0x187, "fb8-delete-characters" ); + add_token( 0x188, "fb8-insert-lines" ); + add_token( 0x189, "fb8-delete-lines" ); + add_token( 0x18a, "fb8-draw-logo" ); + add_token( 0x18b, "fb8-install" ); + add_token( 0x1a0, "return-buffer" ); + add_token( 0x1a1, "xmit-packet" ); + add_token( 0x1a2, "poll-packet" ); + add_token( 0x1a4, "mac-address" ); + add_token( 0x201, "device-name" ); + add_token( 0x202, "my-args" ); + add_token( 0x203, "my-self" ); + add_token( 0x204, "find-package" ); + add_token( 0x205, "open-package" ); + add_token( 0x206, "close-package" ); + add_token( 0x207, "find-method" ); + add_token( 0x208, "call-package" ); + add_token( 0x209, "$call-parent" ); + add_token( 0x20a, "my-package" ); + add_token( 0x20b, "ihandle>phandle" ); + add_token( 0x20d, "my-unit" ); + add_token( 0x20e, "$call-method" ); + add_token( 0x20f, "$open-package" ); + add_token( 0x210, "processor-type" ); + add_token( 0x211, "firmware-version" ); + add_token( 0x212, "fcode-version" ); + add_token( 0x213, "alarm" ); + add_token( 0x214, "(is-user-word)" ); + add_token( 0x215, "suspend-fcode" ); + add_token( 0x216, "abort" ); + add_token( 0x217, "catch" ); + add_token( 0x218, "throw" ); + add_token( 0x219, "user-abort" ); + add_token( 0x21a, "get-my-property" ); + add_token( 0x21b, "decode-int" ); + add_token( 0x21c, "decode-string" ); + add_token( 0x21d, "get-inherited-property" ); + add_token( 0x21e, "delete-property" ); + add_token( 0x21f, "get-package-property" ); + add_token( 0x220, "cpeek" ); + add_token( 0x221, "wpeek" ); + add_token( 0x222, "lpeek" ); + add_token( 0x223, "cpoke" ); + add_token( 0x224, "wpoke" ); + add_token( 0x225, "lpoke" ); + add_token( 0x226, "lwflip" ); + add_token( 0x227, "lbflip" ); + add_token( 0x228, "lbflips" ); + add_token( 0x229, "adr-mask" ); + add_token( 0x230, "rb@" ); + add_token( 0x231, "rb!" ); + add_token( 0x232, "rw@" ); + add_token( 0x233, "rw!" ); + add_token( 0x234, "rl@" ); + add_token( 0x235, "rl!" ); + add_token( 0x236, "wbflips" ); + add_token( 0x237, "lwflips" ); + add_token( 0x238, "probe" ); + add_token( 0x239, "probe-virtual" ); + add_token( 0x23b, "child" ); + add_token( 0x23c, "peer" ); + add_token( 0x23d, "next-property" ); + add_token( 0x23e, "byte-load" ); + add_token( 0x23f, "set-args" ); + add_token( 0x240, "left-parse-string" ); + + /* FCodes from 64bit extension addendum */ + add_token( 0x22e, "rx@" ); + add_token( 0x22f, "rx!" ); + add_token( 0x241, "bxjoin" ); + add_token( 0x242, " + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#include + +#include "detok.h" + +extern bool offs16; +extern u32 fcpos; + +u16 fcode; +u8 inbyte; + +static u8 *indata, *pc, *max; + +int init_stream(char *name) +{ + FILE *infile; + struct stat finfo; + + if (stat(name,&finfo)) + return -1; + + indata=malloc(finfo.st_size); + if (!indata) + return -1; + + infile=fopen(name,"r"); + if (!infile) + return -1; + + if (fread(indata, finfo.st_size, 1, infile)!=1) { + free(indata); + return -1; + } + + fclose(infile); + + pc=indata; + max=pc+finfo.st_size; + + return 0; +} + +int close_stream(void) +{ + free(indata); + return 0; +} + +int get_streampos(void) +{ + return (int)((long)pc-(long)indata); +} + +void set_streampos(long pos) +{ + pc=indata+pos; +} + +static int get_byte(void) +{ + inbyte=*pc; + pc++; + + if (pc>max) { + printf ("\nUnexpected end of file.\n"); + return 0; + } + + return 1; +} + +u16 get_token(void) +{ + u16 tok; + get_byte(); + tok=inbyte; + if (tok != 0x00 && tok < 0x10) { + get_byte(); + tok<<=8; + tok|=inbyte; + } + fcode=tok; + return tok; +} + +u32 get_num32(void) +{ + u32 ret; + + get_byte(); + ret=inbyte<<24; + get_byte(); + ret|=(inbyte<<16); + get_byte(); + ret|=(inbyte<<8); + get_byte(); + ret|=inbyte; + + return ret; +} + +u16 get_num16(void) +{ + u16 ret; + + get_byte(); + ret=inbyte<<8; + get_byte(); + ret|=inbyte; + + return ret; +} + +u8 get_num8(void) +{ + get_byte(); + return(inbyte); +} + +u16 get_offset(void) +{ + if (offs16) + return (get_num16()); + + return (get_num8()); +} + + +int scnt=0; +u8 *get_string(void) +{ + u8 *data; + u8 size; + unsigned int i; + + get_byte(); + size=inbyte; + + scnt++; + + data=malloc(size+2); + if (!data) printf ("No more memory.\n"); + data[0]=size; + + for (i=1; i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +int init_stream(char *name); +int close_stream(void); + +int get_streampos(void); +void set_streampos(long pos); + +u16 get_token(void); +u8 get_num8(void); +u16 get_num16(void); +u32 get_num32(void); +u16 get_offset(void); +u8 *get_string(void); + diff --git a/utils/devbios/COPYING b/utils/devbios/COPYING new file mode 100644 index 0000000..486e638 --- /dev/null +++ b/utils/devbios/COPYING @@ -0,0 +1,353 @@ + + NOTE! The GPL below is copyrighted by the Free Software + Foundation, but the instance of code that it refers to (/dev/bios + driver)is copyrighted by me and others who actually wrote it. + + Also note that the only valid version of the GPL as far as this driver + is concerned is _this_ particular version of the license (ie v2, not + v2.2 or v3.x or whatever), unless explicitly otherwise stated. + + Stefan Reinauer + +---------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/utils/devbios/CREDITS b/utils/devbios/CREDITS new file mode 100644 index 0000000..cd64267 --- /dev/null +++ b/utils/devbios/CREDITS @@ -0,0 +1,4 @@ + +Thanks to Michael Gibson from eSeSiX for donating a cs5530 +based thin client for porting /dev/bios. + diff --git a/utils/devbios/ChangeLog b/utils/devbios/ChangeLog new file mode 100644 index 0000000..979c0a9 --- /dev/null +++ b/utils/devbios/ChangeLog @@ -0,0 +1,275 @@ +ChangeLog for /dev/bios + +** 2004/03/31 ******************************************************** + + * Added fix from Alex Beregszaszi to remove global *bios + +** 2004/03/05 ******************************************************** + + * fix compiling for 2.6 kernels. + +** 03/06/04 ********************************************************** + + * add SST49LF080A + * small 2.5 fix. + +** 02/06/10 ********************************************************** + + * some changes to detect pci cards firmware. + * pci cards firmware can be read even if flashing is not possible. + This is a new feature and might cause problems on some systems. + +** 02/04/16 ********************************************************** + + * reorganize Makefile, include .config from kernel. + * platform fixes for clean compilation. + +** 02/04/12 ********************************************************** + + * proprietary x86-64 support. + * change ruffian probe address + +** 02/03/28 ********************************************************** + + * proper implementation of system firmware detection on LX164 Alphas + * partly include jedec command cleanup patch from Pierrick Hascoet + + +** 02/03/11 ********************************************************** + + * only probe 512k on CS5530(A) + * add EON EN29F002 chips. + +** 02/02/22 ********************************************************** + + * rewrite major parts of bridge probing to make driver more generic. + * add Ali chipset support + * Saner iounmap() of flash devices. + +** 02/02/18 * 0.3.2 ************************************************** + + * change cs5530 driver to map high rom range instead of low one + and don't use positive decode. + * remove ruffian flag. Alpha (164LX/UX) almost works with pc code. + * don't rely on register defaults in intel 8xx driver. + * updated pci device list. more entries, join amd and via entry. + * fix error handling in chipset detection. + * add support for Reliance/ServerWorks chipsets + * enable 1M 512k on intel 4x0 chips where it's possible + * cleanup proc file handling + +** 02/02/17 ********************************************************** + + * rewrote chipset initialisation skeleton. + * fix pci bios (un)mapping. + * experimental support for AlphaPC 164UX (Ruffian) + (probes at 0xfffffffffffc0000 instead of 0xfffffc87C0000000 + * initial code for FWH mode chips + * Fix Toggle-Until-Ready code. + +** 02/02/16 ********************************************************** + + * iounmapping fixed. no more address space wasted. + * /proc/bios shows physical address now. dmesg shows + physical address and virtual memory area and offset. + +** 02/02/13 ********************************************************** + + * added i820/i830 chipset support + * added AMD 751/760MP(X) support + * added support for Itanium and 84460GX chipset + * added experimental support for some flash chips (ST, Intel, + Winbond) + * use spinlocks instead of hard cli() + +** 02/02/11 ********************************************************** + + * added GPL licence tag + * remove low bios area access tweaking for intel drivers + * speed up SST 39SF020 write + * fix compilation for 2.5 kernels + +** 02/02/05 ********************************************************** + + * added support for cs5530 (nsc/cyrix mediagx) chipset + * reorganized shadow/wp handling + * probe for 2mb high memory area instead of 256k only + +** 01/08/01 * 0.3.1 ************************************************** + + * compiles and works with Linux kernel 2.4 + * rewrote flash chip probing + * always use ioremap now + * flash chips above 128k should work transparent + * Support for newer VIA chipsets + +** 00/10/15 * 0.3.0pre1 ********************************************** + + * added patch from Eric Estabrook + * support for 256k flash chips on intel 430/440 chipsets and via vp3 + * split up source into several files + * Changes for Ruffian AXP machines. Does not work (yet). + +** 99/07/29 * 0.2.101 ************************************************ + + * Oh well.. 11 months? Impossible. I am a lazy guy. Implemented + some support for VIA Apollo VP3. Don't know whether it works, since + I don't have one. + +** 98/09/06 ********************************************************** + +patches by prumpf@jcsbs.lanobis.de: + * The pointer to bios_release in bios.c was on the flush pointer's + position. This caused Oopses. + * When bios_read was called with a file position after the actual end + of bios, it tried to read non-existant memory positions due to size + being unsigned (it isn't anymore) , causing spontaneous reboots on + my system + +** 98/08/22 ********************************************************** + + * Well,.. The diskless spectacle (0.2.100) was caused by a little bug + in in handling Intel PCI chipsets. Works now. + * Threw out the chipset_backout stuff. the PCI chipset handling should + always leave the machine in the same state it was before. ALWAYS. + +** 98/08/18 * 0.2.100 ************************************************ + + * Threw out the mem_type stuff. There are more important things than + this. + * Argh! After flashing fine on an Intel 28F001BT, the computer kept + hanging in an endless loop and refused writing the emergency boot + block to the end :-( There's some work until 0.3 is ready. + Implemented a timeout so that the system will not hang forever if + the flashchip behaves unexpected. + * Removed x86 probing in a loop. I think it never found anything else + but the system bios and *maybe* the graphics adapter bios. On the + other hand, it reconfigures some networking cards to silence. + Bad thing on diskless Linux boxes :) + +** 98/08/15 ********************************************************** + + * added some changes for intel to compile without warnings.. + +** 98/08/02 ********************************************************** + + * What a boring job! Checked some dozen of flash chip entries today + and added a lot of new ones. I bet it gets hard to find anything + this driver does not know. + +** 98/07/28 ********************************************************** + + * Yeah! Atmel Chips finally work.. These Atmel guys are really weird. + * Testing last instead of first written byte now, when polling for the + end of a write access. + +** 98/07/28 ********************************************************** + + * Well, I am definitely spending too much time in IRC, but detecting + PCI cards' bioses works now (at least for me) + * Thrown out some obsolete stuff. + * Declared PCI and Flash reading/writing __inline__. Don't know, + whether this is a good idea. But let's try it for a while. + * Aaaargh! Some major mistakes in handling whether a flash has to + be erased before programming. FIXED! + * Even worse. An endless loop made it into writing in 0.2.99. Sorry! + I had no chance to test writing on an intel board with that release. + At least my warning, not to write, made sense. + * Intel flashchips are supported now!! It's at least tested on my + Alpha AXP LX164 Board (1MByte i28f008 chip) But all Intel flash chips + seem to work in the same way. + * Atmel 64kByte flash chips supported. + +** 98/07/27 ********************************************************** + + * Split up flash_probe in 2 parts to be able to expand probing on + PCI bioses and others correctly. + * Turned around 1st and 2nd probing codes. This is funny, Atmel + Flashroms give some wrong numbers if they are probed with the + 0x80/0x60 way. I only hope that no flashchips react on the + 0x90 method with wrong values. + +** 98/07/19 * V0.2.99 ************************************************ + + * Reading the flashchip works now on Alpha AXP (at least on my LX164 + Board) + Writing ought to work, too, but Intel Flashchips are not supported + yet. This should be done until 0.3.0. + NOTE: I have no idea whether this driver still works on intel + boards or not. There have been too many changes. Please try, but + do not flash with this release of the driver. + * Minor Changes and fixes. Naming scheme changed a bit. This version + might work on James Mastros' machine again ?!? + +** 98/07/11 ********************************************************** + + * Started porting stuff to Alpha AXP architecture to continue testing + the flashing routines. We have a lot of tests next week, so I + won't get much stuff done.. + Porting to AXP seems to be much more work than I thought. It may + take some time until the next version is released. + * Moved major number again. This time we have an official major + number for /dev/bios. Thanks to Hans Peter Anvin. + (Well, we have this one since May 1st, sorry for the delay) + +** 98/06/26 * V0.2.95 ************************************************ + + * added all Manufacturer IDs from the JEDEC standards publication. + * sorry for not having released a new version since months, but + my x86 machine died and I have no chance to do any testing right + now. I guess I must get a new Intel box, as Alpha AXP are all + delivered with the same Intel flash chips. + +** 98/04/30 * V0.2.9 ************************************************* + + * removed ioctls. They have been really unneccesary and did not fit + into the new driver layout. + * cleaned up the code. Hey, it should be readable again. + * Moved device minors from 10+ to 0+ + * Rewrote most of the documentation + * changed intel shadowing routines. Now original values are saved + and shadowing is turned off for 0xc0000 to 0xdffff, too (This + was needed to support 2MBit system bios flash chips. Thanks again + to Matthew Harrell for intensive testing. + * Removed dirty hacks from bios_read_proc() + * Added some fields to struct flashdevice to support all ROM types, + not only flash roms. Probing for other types still missing. + * Implemented probing for some strange Winbond chips (0x80/0x20). + +** 98/04/27 * V0.2.8 ************************************************* + + *** Attention *** This version has a lot of changes since + 0.2.7, so be very careful, when testing. Things may + be broken that used to work. + + * Rewrote big parts of the driver to (theoretically) support + multiple flash chips and/or ROM areas. + * Tried to implement support for 2MBit System BIOS chips, but + I have no idea, whether it works. I don't have one. + * added some more OPTi, SiS and VIA PCI chipsets to chipset list. + They have no function yet, though. + * Some weird computers have an ISA bridge, but don't have it declared + as one. Now probing for known ISA bridge IDs. (Thanks to Matthew + Harrell for reporting this.) + * Added some new flashchip IDs and made some old ones work. + +** 98/04/24 * V0.2.7 ************************************************* + + * rewrote shadowing and wp functions to use a pci_functions structure + This makes it very easy to include new PCI chipsets. + * function chipset_init() detects PCI chipset. + * modversions support. Thanks to Matthew Harrell. + * moved PCI bridge detection to chipset_init() + +** 98/04/23 * V0.2.6 ************************************************* + + * repaired flashchip_ready_toggle and flashchip_ready_poll. + * Set WRITE_DELAY to 300 as it should be (works now) + * NOTE: These two changes make the operation of /dev/bios + theoretically correct, and by that quite secure. + +********************************************************************** + +There was no ChangeLog for versions prior to 0.2.6 + +Stefan Reinauer, diff --git a/utils/devbios/Makefile b/utils/devbios/Makefile new file mode 100644 index 0000000..b6f7611 --- /dev/null +++ b/utils/devbios/Makefile @@ -0,0 +1,22 @@ +# comment this if you don't want debugging information +CFLAGS += -DDEBUG + +TARGET = bios.o +OBJS = bios_core.o flashchips.o pcisets.o \ + filesystem.o procfs.o programming.o + +obj-m := $(TARGET) +bios-objs := $(OBJS) + +all: module comp + +clean: + -rm -f $(TARGET) $(OBJS) comp *.o bios.ko + -rm -rf .*.cmd .tmp_versions +module: + make -C /usr/src/linux SUBDIRS=`pwd` modules + +comp: comp.c + $(CC) comp.c -O2 -o comp + strip comp + diff --git a/utils/devbios/Makefile.24 b/utils/devbios/Makefile.24 new file mode 100644 index 0000000..85717c4 --- /dev/null +++ b/utils/devbios/Makefile.24 @@ -0,0 +1,81 @@ +CC = gcc +LD = ld + +KERNEL = /usr/src/linux +#KERNEL = /lib/modules/`uname -r`/build + +ARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) + +ifeq ($(KERNEL)/.config,$(wildcard $(KERNEL)/.config)) +include $(KERNEL)/.config +endif + +CFLAGS = -D__KERNEL__ -I${KERNEL}/include -Wall \ + -Wstrict-prototypes -Wno-trigraphs -O2 \ + -fomit-frame-pointer -fno-common \ + -fno-strict-aliasing -pipe -DMODULE + +# comment this if you don't want debugging information +CFLAGS += -DDEBUG + +# see if we need module versions +ifdef CONFIG_MODVERSIONS +CFLAGS += -DMODVERSIONS +endif + +ifeq ($(ARCH),alpha) +CFLAGS += -mno-fp-regs -ffixed-8 -mcpu=ev5 -Wa,-mev6 +LDFLAGS = -m elf64alpha +endif + +ifeq ($(ARCH),sparc64) +CFLAGS += -mno-fpu -mtune=ultrasparc -mmedlow -ffixed-g4 \ + -fcall-used-g5 -fcall-used-g7 +LDFLAGS = -m elf_sparc64 +endif + +ifeq ($(ARCH),i386) +CFLAGS += -mpreferred-stack-boundary=2 -march=i586 +LDFLAGS = -m elf_i386 +endif + +ifeq ($(ARCH), x86_64) +CFLAGS += -mno-red-zone -mcmodel=kernel -fno-reorder-blocks \ + -finline-limit=2000 -fno-strength-reduce +LDFLAGS = -m elf_x86_64 +endif + +ifeq ($(ARCH),ia64) +CFLAGS += -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ + -falign-functions=32 +LDFLAGS = -m elf64_ia64 +endif + +.SUFFIXES: .o .c .h + +TARGET = bios.o +OBJS = bios_core.o flashchips.o pcisets.o \ + filesystem.o procfs.o programming.o + +all: $(TARGET) comp + +$(TARGET): $(OBJS) + $(LD) $(LDFLAGS) -r -o $(TARGET) $(OBJS) + +clean: + -rm -f $(TARGET) $(OBJS) comp *.o + +.c.o: + $(CC) $(INCLUDES) -c $(INCDIRS) $(CFLAGS) $(X_CFLAGS) $(DEBUGFLAGS) $*.c -o $@ + +comp: comp.c + $(CC) comp.c -O2 -o comp + strip comp + +bios_core.o: bios_core.c bios.h pcisets.h flashchips.h programming.h +filesystem.o: filesystem.c bios.h pcisets.h flashchips.h programming.h +flashchips.o: flashchips.c bios.h flashchips.h +pcisets.o: pcisets.c bios.h pcisets.h flashchips.h programming.h +procfs.o: procfs.c bios.h pcisets.h flashchips.h programming.h +programming.o: programming.c bios.h pcisets.h flashchips.h programming.h + diff --git a/utils/devbios/README.bios b/utils/devbios/README.bios new file mode 100644 index 0000000..63c6997 --- /dev/null +++ b/utils/devbios/README.bios @@ -0,0 +1,237 @@ +/dev/bios documentation 2002/02/19 + +Table of contents +------------------ + + 1. What is /dev/bios? + 2. What hardware/software do I need to run /dev/bios? + 3. Where to get the latest release of /dev/bios + 4. How to get /dev/bios work + 5. Writing to the devices + 6. About PCI chipsets (ix86 only) + 7. About APM Powermanagement (ix86 only) + 8. About different flashchips. + 9. Hints for BIOS flashing + +If you want better information on this driver, read the ChangeLog, +mail me or read the source, Luke :-) + +1. What is /dev/bios? +---------------------- + +This is a kernel driver for different kinds of (Flash)BIOSs that are +available in today's hardware. + +There are well known BIOSs for + - System BIOS (resides at 0xe0000 on Intel PCs) + - graphics hardware + - SCSI host adapters + - networking interfaces with 'BOOT ROM' + - ... + +While in former times these BIOSs were implemented by using ROM or +EPROM (both can't be updated without opening your computer) today's +PC hardware is often delivered with so called FLASH ROMs. These +can simply be updated by software. This driver has the approach to +make Linux read and write flash roms. + +One word before you read ahead: This is still alpha software and +writing to your flash roms may destroy them. So if you notice anything +strange, don't even think about going on, but write some mail to: + + Stefan Reinauer + +Please note that I am not responsible in any way for what you +do with this code or for what this code does with your computer. + +2. What hardware/software do I need to run /dev/bios? +------------------------------------------------------ + +Currently this driver supports ix86 (mainly Pentium, +PPro, PII/III, Athlon, but some 486s), Itanium and Alpha +architecture. +It supports all flash chips from 32k to 2M (theoretically). +Minimum kernel version is v2.2.x, but it's wise to use a +2.4.x kernel. + +3. Where to get the latest release of /dev/bios? +------------------------------------------------- + +/dev/bios was recently integrated into the OpenBIOS CVS +tree for easier maintainance. General information can be +found on the /dev/bios status page: +http://www.freiburg.linux.de/OpenBIOS/status/devbios.html +Latest releases of /dev/bios can be found at the download page: +http://www.freiburg.linux.de/OpenBIOS/dev/download.html +Latest development trees of /dev/bios can be found in the +OpenBIOS CVS. For information how to access it, go to +http://www.freiburg.linux.de/OpenBIOS/dev/cvs.html + +4. How do I get /dev/bios work +------------------------------- + +Create the system bios device with + + mknod /dev/bios c 104 0 + +Now you can add devices for the other BIOSs (often known as option +roms) in your Computer, i.e. like this: + + mknod /dev/gfxbios c 104 1 + mknod /dev/hddbios c 104 2 + mknod /dev/netbios c 104 3 + +The order of the devices may vary on your computer, maybe you even don't +have a flash bios on your network card or on your scsi host adapter. You will +have to decide this after playing around a bit. + +Now you have to compile and insert the kernel driver module: + + cd devbios + make clean && make + insmod bios.o + +Now you have a new device, /dev/bios and, if you have +your kernel configured to have the /proc/ interface, +you have a status file /proc/bios. + +Since this driver is in an early state, you should have +a look at dmesg very often. + +5. Writing to the devices +-------------------------- + +If you insert bios.o without any options, you are not able +to write any of the devices. To enable writing, you should +use + insmod bios.o write=1 + +Writing is now possible with i.e. + dd if=yourbios.bin of=/dev/bios bs=128k count=1 +or + dd if=yourbios.bin of=/dev/bios bs=256k count=1 + +depending on the size of your flash chip. + +You can use 'cat' for flashing as well. Note: Many flashchips are +sectored and the whole sector has to be rewritten, the 4k clusters +of cat may be very slow (and an 112 kb sector has to be written 28 +times completely instead of 1 time with dd) + +Make sure that your file "yourbios.bin" is a valid bios image for +your motherboard and that it is not pkzipped or exe-pkzipped. +(Usually, a 128kb bios images consist of 112kb lha-compressed data, +2*4kb ESCD and DMI (PnP) Data and an 8 kb emergency boot block.) + +Writing to /dev/bios does not work for many chips right now. Write +accesses are ignored in this case. If you want an unsupported flash +rom supported, please mail me. +WARNING: Setting an unsupported chip to "supported" without changing +the rest of the code will *very likely* destroy the contents of your +chip. + +On machines with an AWARD bios you can test whether writing works +safely by only deleting the ESCD/DMI memory on the flash chip. +This data is rewritten by the bios when empty, corrupted or when +you put in a new expansion device. In that case you should see a +message stating "Updating ESCD" during the next boot. + +Please have a close look at the size of your flash chip. For 128k +flash chips, try + + dd if=/dev/zero of=/dev/bios bs=4096 seek=28 count=2 + +For 256k flash chips, you _MUST_ use the following line instead, +or your system bios is going byebye: + + dd if=/dev/zero of=/dev/bios bs=4096 seek=56 count=2 + +Attention: I found other machines with their ESCD memory in the +first sectors of the flash chip. These are afaics 512k+ chips +often connected via a firmware hub. +Behaviour of other BIOSs may be similar, but I can't give you +any warranty it works. + +NOTE: If you listen to music from your soundcard while flashing, +you may get errors like this: + Sound: DMA (output) timed out - IRQ/DRQ config error? + +Second, sound switches off while flashing. This is because all +IRQs are blocked while the write procedure to ensure it doesn't +get disturbed by any other hardware. + +6. About PCI chipsets +---------------------- + +Because this driver uses direct PCI accesses to switch shadowing +and write protection of the bios off on PC architecture, each PCI +chipset (or at least chipset group) has to be implemented and +tested seperately. Successfully tested PCI chipsets are + + * Intel 430HX/TX, 440BX/ZX, 460, 8x0 + * UMC 486 (8881F/8886A) + * VIA (M)VP3 + * AMD Irongate and others + * ServerWorks chipsets + * NSC CS5530 (geode companion) + +Any success/error reports are highly welcome. If you need a certain +system type supported, contact me. + + +7. About APM Power Management (ix86 only) +------------------------------------------ + +This driver is known to cause kernel oopses with some of the chipset +drivers when APM is enabled. Reason is that the flash chip is mapped +to the low bios address space which makes the unpacked bios image vanish +so all pointers to APM functions are invalid. +Nowadays most of the chipset drivers only map the high bios area, so +this problem should not occur on any but old UMC/SiS chipsets. If you +encounter oopses while reading/probing flash devices, disable power +management before any write attempts. To achieve so, please pass "apm=off" +as a kernel option, if your kernel is compiled with APM support. + + + +8. About different flashchips +------------------------------ + +Flash chips, /dev/bios has been successfully tested (writing) on: + + * Winbond 29EE011 + * Intel 28F008(SA) + * Atmel AT29C512 + * SST 29EE010, 39SF020 + +It *should* work, if you see a "Supported: yes" in /proc/bios, but +I am not responsible in any way for what you do.. Please be careful. +Please report any working flash chips so that this list can be completed. +Currently many more flash chips than mentioned here will work. +If you need a certain flash device supported, contact me. + +9. Hints for BIOS-Flashing +--------------------------- + +* Always try to write to the ESCD/DMI Memory before you overwrite the rest + of a bios (ix86) If you get ANY errors in dmesg output, DO NOT CONTINUE! +* Always "diff" the new bios with the written image before rebooting +* You may use comp, a little utility in the devbios source tree instead + of diff. It has a nicer output for binary files. +* on Intel, only write the first 120k of an image to the System ROM, this keeps + the emergency bootblock working. + +************** FINAL NOTE ***************************** + +If you want to help this project, send me + + * /proc/bios-output + * dmesg-output (after insmodding the driver) + * your system-configuration + (e.g. output of lspci or /proc/bus/pci/devices) + * any comments + * any ideas + + + Stefan Reinauer + diff --git a/utils/devbios/ToDo b/utils/devbios/ToDo new file mode 100644 index 0000000..2d320a9 --- /dev/null +++ b/utils/devbios/ToDo @@ -0,0 +1,33 @@ +ToDo-/Buglist 2003/06/04 (0.4pre6) +---------------------------------- + +Memory Stuff + * devbios does not find any flash chip on some systems even though + they are supported. One of the reasons this might happen is that + the flash memory area is hidden using the CPUs mtrrs. If you have + a Pentium II/III/IV or AMD K6/K7 board, you might try + echo "base=0xffe00000 size=0x200000 type=uncachable" >| /proc/mtrr + before loading the module. + +Misc Stuff + * port this driver to fit into the linux kernel's + mtd device drivers. + * join with ctflasher code + * port to *BSD (if anybody wants that) + * disable NMI watchdog while flashing, if active + +PCI Stuff + * unshadow functions do not work on certain 440BX/GX chipsets? + when loading the module, no system flashchip is detected. + * change unshadow functions not to touch low bios area to + be apm and pci bios safe. + +Module stuff + * /proc/sys/kernel/bios-writable + +Flashchip Stuff + * Finnish FWH support. + * Implement writing for Macronix and AMD. + (Catalyst have Intel and AMD compatible chips) + * Implement write protection checking some flash chips have. + * Test/complete existing support diff --git a/utils/devbios/bios.h b/utils/devbios/bios.h new file mode 100644 index 0000000..b27372d --- /dev/null +++ b/utils/devbios/bios.h @@ -0,0 +1,38 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * bios.h - compile time configuration and globals + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include + +#define BIOS_MAJOR 104 +#define BIOS_MAXDEV 8 +#define BIOS_VERSION "0.4rc1" + +// #define UTC_BIOS + +extern int write; +extern unsigned char *bios; +extern spinlock_t bios_lock; + diff --git a/utils/devbios/bios_core.c b/utils/devbios/bios_core.c new file mode 100644 index 0000000..d165cdb --- /dev/null +++ b/utils/devbios/bios_core.c @@ -0,0 +1,198 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * bios_core.c - core skeleton + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#endif +#include +#endif +#include +#include +#include +#include + +#include + +#include "bios.h" +#include "pcisets.h" +#include "flashchips.h" +#include "programming.h" + +extern struct file_operations bios_fops; +int bios_proc_register(void); +int bios_proc_unregister(void); + +int write = 0; + +spinlock_t bios_lock = SPIN_LOCK_UNLOCKED; + +/* + * ****************************************** + * + * Cleanup + * + * ****************************************** + */ + +static void free_iomaps(void) +{ + unsigned long lastmapped=0; + unsigned int i; + + /* We remember the last mapped area to be sure that we only iounmap + * every mapped area once. If two flash devices are in the same + * area but do not occur sequentially during probing you have a + * seriously strange hardware + */ + for (i=0; i"); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,10) +MODULE_LICENSE("GPL"); +#endif + +static __exit void cleanup_bios_module (void) +{ +#ifdef CONFIG_PROC_FS + bios_proc_unregister(); +#endif + free_iomaps(); + + unregister_chrdev(BIOS_MAJOR, "bios"); + printk(KERN_INFO "BIOS driver removed.\n"); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +int init_module(void) +{ + return bios_init(); +} + +void cleanup_module(void) +{ + cleanup_bios_module(); +} +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,74) +module_init(bios_init); +module_exit(cleanup_bios_module); +#endif + +void inc_mod(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + MOD_INC_USE_COUNT; +#endif +} + +void dec_mod(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + MOD_DEC_USE_COUNT; +#endif +} + +#endif diff --git a/utils/devbios/comp.c b/utils/devbios/comp.c new file mode 100644 index 0000000..9d2acb1 --- /dev/null +++ b/utils/devbios/comp.c @@ -0,0 +1,47 @@ +/* Simple utility to compare 2 files. + * Diff or cmp are not sufficient, when + * comparing bioses :-) + * + * Copyright (c) 1998-2000 by Stefan Reinauer + */ + + +#include + +int main (int argc, char *argv[]) +{ + FILE *eins,*zwei; + int a,b,i=0,flag=0; + + if(argv[1]==NULL||argv[2]==NULL) { + printf ("Usage: %s file1 file2\n %s compares two files.\n",argv[0],argv[0]); + return 0; + } + eins=fopen(argv[1],"r"); + zwei=fopen(argv[2],"r"); + + if (eins==NULL) { + printf ("File %s not found or unreadable.\n",argv[1]); + return 0; + } + if (zwei==NULL) { + printf ("File %s not found or unreadable.\n",argv[2]); + fclose (eins); + return 0; + } + + while (!feof(eins)) { + a=fgetc(eins); + b=fgetc(zwei); + if (flag==0 && (a==-1||b==-1) && (a!=-1||b!=-1)) { + printf ("One file ended. Printing the rest of the other.\n"); + flag=1; + } + if(a!=b) printf ("0x%06x: 0x%02x -> 0x%02x\n",i,a,b); + i++; + } + + fclose(eins); + fclose(zwei); + return 0; +} diff --git a/utils/devbios/filesystem.c b/utils/devbios/filesystem.c new file mode 100644 index 0000000..0dab711 --- /dev/null +++ b/utils/devbios/filesystem.c @@ -0,0 +1,300 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * filesystem.c - vfs character device interface + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && defined(MODVERSIONS) +#include +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include "bios.h" +#include "flashchips.h" +#include "pcisets.h" +#include "programming.h" + +#ifdef MODULE +void inc_mod(void); +void dec_mod(void); +#endif + +/* + * ****************************************** + * + * /dev/bios filesystem operations + * + * ****************************************** + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#define FDEV (MINOR(file->f_dentry->d_inode->i_rdev)) +#else +#define FDEV (iminor(file->f_dentry->d_inode)) +#endif +#define CFLASH flashdevices[FDEV] +// #define BIOS_SIZE ((flashchips[CFLASH.flashnum].size)*1024) +#define BIOS_SIZE (CFLASH.size) + +static loff_t bios_llseek(struct file *file, loff_t offset, int origin ) +{ + currflash=FDEV; + switch(origin) { + case 0: + break; + case 1: + offset += file->f_pos; + break; + case 2: + offset += BIOS_SIZE; + break; + } + return((offset >= 0)?(file->f_pos = offset):-EINVAL); +} + +static ssize_t bios_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + signed int size=((BIOS_SIZE-*ppos>count) ? count : BIOS_SIZE-*ppos); + unsigned char *addr = (unsigned char*)CFLASH.mapped + CFLASH.offset; + int i; + + currflash = FDEV; + + devices[flashdevices[currflash].idx].activate(); + + for (i=0;i BIOS_SIZE-*ppos ) + return -EFBIG; + + /* FIXME: Autoselect(AMD) BC-90 + * -> 00/MID; + * 01/PID; + * 02/Protected (1=yes/0=no) + */ + + /* Determine size of data to be written */ + + if (!(flashchips[fn].flags & f_needs_erase) ) { + offset=(unsigned int)*ppos&~(flashchips[fn].pagesize-1); + size=(((unsigned int)*ppos+count+(flashchips[fn].pagesize-1))& + ~(flashchips[CFLASH.flashnum].pagesize-1))-offset; + } else { + while (flashchips[fn].sectors[secnum] <= flashchips[fn].size ) { + if ((unsigned int)*ppos >= flashchips[fn].sectors[secnum]*1024) { + offset=flashchips[fn].sectors[secnum]*1024; + startsec=secnum; + } + if ((unsigned int)*ppos+count-1 <= flashchips[fn].sectors[secnum]*1024) { + size=(flashchips[fn].sectors[secnum]*1024)-offset; + endsec=secnum-1; + break; + } + secnum++; + } + } + +#ifdef DEBUG + printk (KERN_DEBUG "BIOS: Write [0x%06x..0x%06x] [0x%06x..0x%06x]\n", + (unsigned int)(*ppos),(unsigned int)(*ppos+count-1),offset,offset+size-1); +#endif + + /* prepare data for writing */ + + clipboard=vmalloc(size); + + spin_lock_irqsave(&bios_lock, flags); + + devices[flashdevices[currflash].idx].activate(); + + for (i=0; i < size; i++) + clipboard[i] = flash_readb(addr,offset+i); + + copy_from_user(clipboard+(*ppos-offset), buffer, count); + + /* start write access */ + + if (flashchips[fn].flags & f_intel_compl) { + iflash_erase_sectors(addr,fn,startsec,endsec); + + for (i=0;i0) { + if ((flashchips[fn].flags & f_manuf_compl) != f_atmel_compl) { + flash_program(addr); + } else { + flash_program_atmel(addr); + } + for (i=0;if_flags & O_EXCL)) || + (CFLASH.open_mode & O_EXCL) || + ((file->f_mode & 2) && (CFLASH.open_mode & O_RDWR))) + return -EBUSY; + + if (file->f_flags & O_EXCL) + CFLASH.open_mode |= O_EXCL; + + if (file->f_mode & 2) + CFLASH.open_mode |= O_RDWR; + + CFLASH.open_cnt++; + + +#ifdef MODULE + inc_mod(); +#endif + return 0; +} + +static int bios_release(struct inode *inode, struct file *file) +{ + currflash=FDEV; + if (file->f_flags & O_EXCL) + CFLASH.open_mode &= ~O_EXCL; + + if (file->f_mode & 2) + CFLASH.open_mode &= ~O_RDWR; + + CFLASH.open_cnt--; + +#ifdef MODULE + dec_mod(); +#endif + return 0; +} + +struct file_operations bios_fops = { + .owner = THIS_MODULE, + .llseek = bios_llseek, + .read = bios_read, + .write = bios_write, + .open = bios_open, + .release = bios_release, +}; + diff --git a/utils/devbios/flashchips.c b/utils/devbios/flashchips.c new file mode 100644 index 0000000..460a85d --- /dev/null +++ b/utils/devbios/flashchips.c @@ -0,0 +1,313 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * flashchips.c - contains all information about supported flash devices. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ +// <-- C++ style comments are for experimental comments only. +// They will disappear as soon as I fixed all the stuff. + +#include "bios.h" +#include "flashchips.h" + +unsigned int currflash=0; + +const manufacturer_t manufacturers[] = +{ + { "AMD", 0x01 }, + { "AMI", 0x02 }, + { "Fairchild", 0x83 }, + { "Fujitsu", 0x04 }, + { "GTE", 0x85 }, + { "Harris", 0x86 }, + { "Hitachi", 0x07 }, + { "Inmos", 0x08 }, + { "Intel", 0x89 }, + { "I.T.T.", 0x8A }, + { "Intersil", 0x0B }, + { "Monolithic Memories",0x8C }, + { "Mostek", 0x0D }, + { "Motorola", 0x0E }, + { "National", 0x8F }, + { "NEC", 0x10 }, + { "RCA", 0x91 }, + { "Raytheon", 0x92 }, + { "Rockwell", 0x13 }, + { "Seeq", 0x94 }, + { "Philips Semi.", 0x15 }, + { "Synertek", 0x16 }, + { "Texas Instruments", 0x97 }, + { "Toshiba", 0x98 }, + { "Xicor", 0x19 }, + { "Zilog", 0x1A }, + { "Eurotechnique", 0x9B }, + { "Mitsubishi", 0x1C }, + { "PMC Flash", 0x9D }, + { "Exel", 0x9E }, + { "Atmel", 0x1F }, + { "SGS/Thomson", 0x20 }, + { "Lattice Semi.", 0xA1 }, + { "NCR", 0xA2 }, + { "Wafer Scale Integr.",0x23 }, + { "IBM", 0xA4 }, + { "Tristar", 0x25 }, + { "Visic", 0x26 }, + { "Intl. CMOS Tech.", 0xA7 }, + { "SSSI", 0xA8 }, + { "MicrochipTech.", 0x29 }, + { "Ricoh Ltd.", 0x2A }, + { "VLSI", 0xAB }, + { "Micron Technology", 0x2C }, + { "Hyundai Elect.", 0xAD }, + { "OKI Semiconductor", 0xAE }, + { "ACTEL", 0x2F }, + { "Sharp", 0xB0 }, + { "Catalyst", 0x31 }, + { "Panasonic", 0x32 }, + { "IDT", 0xB3 }, + { "Cypress", 0x34 }, + { "DEC", 0xB5 }, + { "LSI Logic", 0xB6 }, + { "Plessey", 0x37 }, + { "UTMC", 0x38 }, + { "Thinking Machine", 0xB9 }, + { "Thomson CSF", 0xBA }, + { "Integ. CMOS(Vertex)",0x3B }, + { "Honeywell", 0xBC }, + { "Tektronix", 0x3D }, + { "Sun Microsystems", 0x3E }, + { "SST", 0xBF }, + { "MOSEL", 0x40 }, + { "Siemens", 0xC1 }, + { "Macronix", 0xC2 }, + { "Xerox", 0x43 }, + { "Plus Logic", 0xC4 }, + { "SunDisk", 0x45 }, + { "Elan Circuit Tech.", 0x46 }, + { "Europ. Silicon Str.",0xC7 }, + { "Apple Computer", 0xC8 }, + { "Xilinx", 0xC9 }, + { "Compaq", 0x4A }, + { "Protocol Engines", 0xCB }, + { "SCI", 0x4C }, + { "Seiko Instruments", 0xCD }, + { "Samsung", 0xCE }, + { "I3 Design System", 0x4F }, + { "Klic", 0xD0 }, + { "Crosspoint Sol.", 0x51 }, + { "Alliance Semicond.", 0x52 }, + { "Tandem", 0xD3 }, + { "Hewlett-Packard", 0x54 }, + { "Intg. Silicon Sol.", 0xD5 }, + { "Brooktree", 0xD6 }, + { "New Media", 0x57 }, + { "MHS Electronic", 0x58 }, + { "Performance Semi.", 0xD9 }, + { "Winbond", 0xDA }, + { "Kawasaki Steel", 0x5B }, + { "Bright Micro", 0xDC }, + { "TECMAR", 0x5D }, + { "Exar", 0x5E }, + { "PCMCIA", 0xDF }, + { "Goldstar", 0xE0 }, + { "Northern Telecom", 0x61 }, + { "Sanyo", 0x62 }, + { "Array Microsystems", 0xE3 }, + { "Crystal Semicond.", 0x64 }, + { "Analog Devices", 0xE5 }, + { "PMC-Sierra", 0xE6 }, + { "Asparix", 0x67 }, + { "Convex Computer", 0x68 }, + { "Quality Semicond.", 0xE9 }, + { "Nimbus Technology", 0xEA }, + { "Transwitch", 0x6B }, + { "ITT Intermetall", 0xEC }, + { "Cannon", 0x6D }, + { "Altera", 0x6E }, + { "NEXCOM", 0xEF }, + { "QUALCOMM", 0x70 }, + { "Sony", 0xF1 }, + { "Cray Research", 0xF2 }, + { "AMS(Austria Micro)", 0x73 }, + { "Vitesse", 0xF4 }, + { "Aster Electronics", 0x75 }, + { "Bay Networks(Synoptic)", 0x76 }, + { "Zentrum Mikroelec.", 0xF7 }, + { "TRW", 0xF8 }, + { "Thesys", 0x79 }, + { "Solbourne Computer", 0x7A }, + { "Allied-Signal", 0xFB }, + { "Dialog", 0x7C }, + { "Media Vision", 0xFD }, + { "Level One Commun.", 0xFE }, + { "Eon", 0x7F }, + + { "Unknown", 0x00 } +}; + +const flashchip_t flashchips[] = +{ + /* AMD */ + { "29F016B", 0xad01, 5, 2048, 0, 1, 1, (int []) { 0,2048 } }, + { "29F080B", 0xd501, 5, 1024, 0, 1, 1, (int []) { 0,1024 } }, + { "29F800BT", 0xd601, 5, 1024, 0, 1, 1, (int []) { 0,1024 } }, + { "29F800BB", 0x5801, 5, 1024, 0, 1, 1, (int []) { 0,1024 } }, + { "29F040B", 0xa401, 5, 512, 0, 1, 1, (int []) { 0, 512 } }, + { "29F400T", 0x2301, 5, 512, 0, 1, 1, (int []) { 0, 512 } }, + { "29LV004T", 0xb501, 3, 512, 0, 1, 1, (int []) { 0, 512 } }, + { "29LV400T", 0xb901, 3, 512, 0, 1, 1, (int []) { 0, 512 } }, + { "29F400B", 0xab01, 5, 512, 0, 1, 1, (int []) { 0, 512 } }, + { "29LV004B", 0xb601, 3, 512, 0, 1, 1, (int []) { 0, 512 } }, + { "29LV400B", 0xba01, 3, 512, 0, 1, 1, (int []) { 0, 512 } }, + { "28F020A", 0x2901, 12, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "28F020", 0x2a01, 12, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29F002T", 0xb001, 5, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29LV002T", 0x4001, 3, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29LV200T", 0x3b01, 3, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29F200T", 0x5101, 5, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29F002B", 0x3401, 5, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29LV002B", 0xc201, 3, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29LV200B", 0xbf01, 3, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29F200B", 0x5701, 5, 256, 0, 1, 1, (int []) { 0, 256 } }, + { "29F010", 0x2001, 5, 128, 0, 1, 1, (int []) { 0, 128 } }, + { "28F010A", 0xa201, 12, 128, 0, 1, 1, (int []) { 0, 128 } }, + { "28F010", 0xa701, 12, 128, 0, 1, 1, (int []) { 0, 128 } }, + { "29F100T", 0xd901, 5, 64, 0, 1, 1, (int []) { 0, 64 } }, + { "29F100B", 0xdf01, 5, 64, 0, 1, 1, (int []) { 0, 64 } }, + { "28F512A", 0xae01, 12, 64, 0, 1, 1, (int []) { 0, 64 } }, + { "28F512", 0x2501, 12, 64, 0, 1, 1, (int []) { 0, 64 } }, + { "28F256A", 0x2f01, 12, 32, 0, 1, 1, (int []) { 0, 32 } }, + { "28F256", 0xa101, 12, 32, 0, 128, 1, (int []) { 0, 32 } }, + + /* Atmel */ + { "AT49BV010", 0x851f, 3, 128, 0, 128, 1, (int []) { 0, 128 } }, +//Word { "AT49F1025", 0x851f, 5, 128, 0, 256, 1, (int []) { 0, 128 } }, + { "AT49x020", 0x0b1f, 5, 256, 0, 128, 1, (int []) { 0, 256 } }, + { "AT49F040", 0x131f, 5, 512, 0, 128, 1, (int []) { 0, 512 } }, + { "AT49F010", 0x171f, 5, 128, 0, 128, 1, (int []) { 0, 128 } }, + { "AT49F080", 0x231f, 5, 1024, 0, 128, 1, (int []) { 0,1024 } }, + { "AT29C040A", 0xa41f, 5, 512, 1, 256, 4, (int []) { 0, 512 } }, +//Word { "AT29C1024", 0x251f, 3, 128, 0, 128, 0, (int []) { 0, 128 } }, +//Word { "AT29LV1024", 0x261f, 3, 128, 0, 128, 0, (int []) { 0, 128 } }, + { "AT49F080T", 0xa71f, 5, 1024, 0, 128, 1, (int []) { 0,1024 } }, + { "AT29BV010A", 0x351f, 3, 128, 1, 128, 4, (int []) { 0, 128 } }, + { "AT29BV020", 0xba1f, 3, 256, 1, 256, 4, (int []) { 0, 256 } }, + { "AT29LV256", 0xbc1f, 3, 32, 1, 64, 4, (int []) { 0, 32 } }, + { "AT29LV512", 0x3d1f, 3, 64, 1, 128, 4, (int []) { 0, 64 } }, + { "AT29BV040A", 0xc41f, 3, 512, 1, 256, 4, (int []) { 0, 512 } }, + { "AT29C010A", 0xd51f, 5, 128, 1, 128, 4, (int []) { 0, 128 } }, + { "AT29C020", 0xda1f, 5, 256, 1, 256, 4, (int []) { 0, 256 } }, + { "AT29C256", 0xdc1f, 3, 32, 1, 64, 4, (int []) { 0, 32 } }, + { "AT29C512", 0x5d1f, 5, 64, 1, 128, 4, (int []) { 0, 64 } }, + + /* Catalyst */ + { "CAT28F150T", 0x0431, 12, 192, 1, 128, 3, (int []) { 0, 64,160,168,176,192 } }, + { "CAT28F150B", 0x8531, 12, 192, 1, 128, 3, (int []) { 0, 16, 24, 32,128, 192 } }, + { "CAT28F001T", 0x9431, 12, 128, 1, 128, 3, (int []) { 0,112,116,120,128 } }, + { "CAT28F001B", 0x1531, 12, 128, 1, 128, 3, (int []) { 0, 8, 12, 16,128 } }, + { "CAT29F002T", 0xb031, 5, 256, 0, 128, 1, (int []) { 0, 64,128,192,224,232,240,256 } }, + { "CAT29F002B", 0x3431, 5, 256, 0, 128, 1, (int []) { 0, 16, 24, 32, 64,128,192,256 } }, + { "CAT28F002T", 0x7c31, 12, 256, 1, 128, 3, (int []) { 0,128,224,232,240,256 } }, + { "CAT28F002B", 0xfd31, 12, 256, 1, 128, 3, (int []) { 0, 16, 24, 32,128,256 } }, + { "CAT28F020" , 0xbd31, 12, 256, 0, 1, 1, (int []) { 0,256 } }, +//Word { "CAT28F102" , 0x5131, 12, 128, 0, 0, 0, (int []) { 0,128 } }, + { "CAT28F010" , 0xb431, 12, 128, 0, 1, 1, (int []) { 0,128 } }, + { "CAT28F512" , 0xb831, 12, 64, 0, 1, 1, (int []) { 0, 64 } }, + + { "29F040", 0xa404, 5, 512, 1, 1, 1, (int []) { 0, 64, 128, 192, 256, 320, 384, 448, 512 } }, /* Fujitsu */ + + + /* Intel */ + { "28F010", 0x3489, 12, 128, 0, 128, 1, (int []) { 0,128 } }, + { "28F020", 0x3d89, 12, 256, 0, 128, 1, (int []) { 0,256 } }, + { "28F001BX-T", 0x9489, 12, 128, 1, 128, 3, (int []) { 0,112,116,120,128 } }, + { "28F001BX-B", 0x9589, 12, 128, 1, 128, 3, (int []) { 0, 8, 12, 16,128 } }, +//Word { "28F400BX-T", 0x7089, 12, 512, 0, 256, 3, (int []) { 0,128,256,384,480,488,496,512 } }, +//Word { "28F400BX-B", 0xF189, 12, 512, 0, 256, 3, (int []) { 0, 16, 24, 32,128,256,384,512 } }, +//Word { "28F200-T", 0xF489, 12, 256, 0, 256, 3, (int []) { 0,128,224,232,240,256} }, +//Word { "28F200-B", 0x7589, 12, 256, 0, 256, 3, (int []) { 0, 16, 24, 32,128,256 } }, + { "28F016B3-T", 0xd089, 3, 1024, 0, 1, 3, (int []) { 0, 2048 } }, + { "28F016B3-B", 0xd189, 3, 1024, 0, 1, 3, (int []) { 0, 2048 } }, + { "28F008B3-T", 0xd289, 3, 1024, 0, 1, 3, (int []) { 0, 1024 } }, + { "28F008B3-B", 0xd389, 3, 1024, 0, 1, 3, (int []) { 0, 1024 } }, + { "28F004B3-T", 0xd489, 3, 512, 0, 128, 3, (int []) { 0,128,256,384,480,488,496,512 } }, + { "28F004B3-B", 0xd589, 3, 512, 0, 128, 3, (int []) { 0, 16, 24, 32,128,256,384,512 } }, + { "28F004BX-T", 0xF889, 12, 512, 1, 128, 3, (int []) { 0,128,256,384,480,488,496,512 } }, + { "28F004BX-B", 0x7989, 12, 512, 1, 128, 3, (int []) { 0, 16, 24, 32,128,256,384,512 } }, + { "28F002-T", 0x7c89, 12, 256, 1, 128, 3, (int []) { 0,128,224,232,240,256 } }, + { "28F002-B", 0xfd89, 12, 256, 1, 256, 3, (int []) { 0, 16, 24, 32,128,256 } }, + { "28F008??", 0xa289, 12, 1024, 1, 1, 3, (int []) { 0, 64,128,192,256,320,384,448,512,576,640,704,768,832,896,960,1024 } }, + { "28F008SA", 0xa189, 12, 1024, 1, 1, 3, (int []) { 0, 64,128,192,256,320,384,448,512,576,640,704,768,832,896,960,1024 } }, + { "28F004??", 0xad89, 5, 512, 0, 1, 3, (int []) { 0, 512} }, + { "28F008??", 0xac89, 5, 1024, 0, 1, 3, (int []) { 0,1024} }, + + /* Eon */ + { "E28F004S5", 0x7f8f, 5, 512, 1, 1, 3, (int []) { 0, 64,128,192,256,320,384,448,512 } }, + { "EN29F002B", 0x977f, 5, 256, 1, 1, 1, (int []) { 0, 16, 24, 32,128,256 } }, + { "EN29F002T", 0x927f, 5, 256, 1, 1, 1, (int []) { 0,128,224,232,240,256 } }, + + /* SST */ + { "28EE011", 0x01bf, 5, 128, 0, 128, 0, (int []) { 0, 128 } }, + { "28EE040", 0x04bf, 5, 512, 0, 128, 0, (int []) { 0, 512 } }, + { "29EE010", 0x07bf, 5, 128, 1, 128, 0, (int []) { 0, 128 } }, + { "29x010", 0x08bf, 3, 128, 0, 128, 0, (int []) { 0, 128 } }, + { "29EE020", 0x10bf, 5, 256, 0, 128, 0, (int []) { 0, 256 } }, + { "29x020", 0x92bf, 3, 256, 0, 128, 0, (int []) { 0, 256 } }, + { "29x512", 0x3dbf, 3, 64, 0, 128, 0, (int []) { 0, 64 } }, + { "29EE512", 0x5dbf, 5, 64, 0, 128, 0, (int []) { 0, 64 } }, + { "29x020", 0x92bf, 3, 256, 0, 128, 0, (int []) { 0, 256 } }, + { "39SF020", 0xb6bf, 5, 256, 1, 1, 0x81, (int []) { 0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256 } }, + { "49LF002A", 0x57bf, 3, 256, 0, 1, 0x81, (int[]) {0,256} }, + { "49LF003A", 0x1bbf, 3, 384, 0, 1, 0x81, (int[]) {0,384} }, + { "49LF004A", 0x60bf, 3, 512, 1, 1, 0x09, (int[]) {0, 4, 8, 12, 16, 24,28, 32, 512} }, + { "49LF008A", 0x5abf, 3, 1024, 0, 1, 0x81, (int[]) {0,1024} }, + { "49LF020", 0x61bf, 3, 256, 1, 4096, 0, (int[]) {0,256} }, + { "49LF040", 0x51bf, 3, 512, 1, 4096, 0, (int[]) {0,512} }, + { "49LF080A", 0x5bbf, 3, 1024, 1, 4096, 0, (int[]) {0,1024} }, + + /* Macronix */ + { "MX28F1000AP",0x1ac2, 12, 128, 0, 1, 1, (int []) { 0, 16, 32, 48, 64, 80, 96,112,116,120,124,128 } }, + { "MX28F1000P", 0x91c2, 12, 128, 0, 1, 1, (int []) { 0, 16, 32, 48, 64, 80, 96,112,128 } }, + { "MX28F1000PC",0xf7c2, 12, 128, 0, 1, 1, (int []) { 0, 16, 32, 48, 64, 80, 96,112,128 } }, +//id? { "MX28F1000PPC",0x7fc2,12, 128, 0, 1, 1, (int []) { 0, 16, 32, 48, 64, 80, 96,112,116,120,124,128 } }, + { "MX29F1610A", 0xfac2, 5, 2048, 1, 128, 0, (int []) { 0, 2048} }, + + /* Winbond */ + { "W29EE011", 0xc1da, 5, 128, 1, 128, 0, (int []) { 0, 128 } }, + { "W29C020", 0x45da, 5, 256, 1, 128, 0, (int []) { 0, 256 } }, + { "W29C040/042",0x46da, 5, 512, 1, 256, 0, (int []) { 0, 512 } }, + { "W29EE512", 0xc8da, 5, 64, 1, 128, 0, (int []) { 0, 64 } }, + { "W29C101", 0x4fda, 5, 128, 1, 256, 0, (int []) { 0, 128 } }, + { "W49V002", 0xb0da, 3, 256, 1, 1, 1, (int []) { 0, 64, 128, 192, 224, 232, 240, 256 } }, + //{ "W49F002", 0x0bda, 5, 256, 1, 1, 1, (int []) { 0, 64, 128, 192, 224, 232, 240, 256 } }, + { "W49F002U", 0x0bda, 5, 256, 1, 1,0x09, (int []) { 0, 128, 224, 232, 240, 256 } }, /* Winbond */ + + /* SGS/Thomson */ + { "M29F002B(N)T", 0xb020, 5, 256, 0, 1, 0, (int[]) {0, 64, 128, 256 } }, + { "M29F002B(N)B", 0x3420, 5, 256, 0, 1, 0, (int[]) {0, 256 } }, + { "M50FW040", 0x2c20, 3, 512, 1, 128, 0x0b, (int []) { 0, 64, 128, 192, 256, 320, 384, 448, 512 } }, + + { "Pm29F002T", 0x1d9d, 5, 256, 1, 1, 0x1, (int []) { 0,128,224,232,240,256 } }, + /* default entry */ + { "Unknown", 0x0000, 0, 0, 0, 0, 0, (int []) { 0 } } +}; + diff --git a/utils/devbios/flashchips.h b/utils/devbios/flashchips.h new file mode 100644 index 0000000..3e6e5a6 --- /dev/null +++ b/utils/devbios/flashchips.h @@ -0,0 +1,81 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * flashchips.h - flash device structures. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* + * flags structure + * bit 0 = needs erase before write (f_needs_erase) + * bit 1-3 flash manu type + * bit 4-6 probably needed for more manu + * bit 7 = sector erase happens one sector at a time + * (f_slow_sector_erase) + */ + +#define f_needs_erase 0x01 + +/* 3 bit for flashtype */ +#define f_manuf_compl 0x0e /* Mask out bits 1-3 */ +#define f_intel_compl 0x02 /* 001 */ +#define f_atmel_compl 0x04 /* 010 */ +#define f_fwh_compl 0x08 /* 100 */ + +#define f_slow_sector_erase 0x80 + +#define FLASH_UNKNOWN 0 +#define FLASH_CFI 1 +#define FLASH_JEDEC 2 + +typedef struct flashdevice { + unsigned long mapped; + unsigned long physical; + unsigned long offset; + unsigned int flashnum, manufnum; + unsigned short id; + unsigned int size, sectors; + unsigned int idx; + void *data; + int open_mode, open_cnt; +} flashdevice_t; + +typedef struct flashchip { + char *name; + unsigned short id; + unsigned int voltage; + unsigned int size; /* KBytes */ + unsigned int supported; + unsigned int pagesize; /* Bytes */ + unsigned int flags; + unsigned int *sectors; /* Kbytes[] including end of last sector */ +} flashchip_t; + +typedef struct manufacturer { + char *name; + unsigned short id; +} manufacturer_t; + +extern unsigned int currflash; +extern flashdevice_t flashdevices[BIOS_MAXDEV]; +extern const flashchip_t flashchips[]; +extern const manufacturer_t manufacturers[]; diff --git a/utils/devbios/pcisets.c b/utils/devbios/pcisets.c new file mode 100644 index 0000000..91b9e0e --- /dev/null +++ b/utils/devbios/pcisets.c @@ -0,0 +1,630 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * pcisets.c - support functions to map flash devices to kernel space + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#ifdef MODVERSIONS +#include +#endif +#endif +#include +#include +#include +#include +#ifdef __alpha__ +#include +#endif + +#include "bios.h" +#include "flashchips.h" +#include "pcisets.h" +#include "programming.h" + +#ifdef CONFIG_PCI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) +#define pci_find_class pci_get_class +#endif + +#define pci_id(dev) ((dev->vendor<<16) | (dev->device)) +struct pci_dev *hostbridge=NULL; +static unsigned char pci_dummy[4]; + +/* + * ****************************************** + * + * own pci/shadow handling; We can't use + * the PCI bios here as it would sweep + * itself out! + * + * ****************************************** + */ + +static int pci_read(struct pci_dev *dev, unsigned char where) +{ + if (!dev) return 0; + + outl((0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | + (where & ~3)), 0xCF8); + mb(); + return inb(0xCFC + (where&3)); +} + +static void pci_write(struct pci_dev *dev, unsigned char where, unsigned char value) +{ + if (!dev) return; + outl((0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | + (where & ~3)), 0xCF8); + mb(); + outb(value, 0xCFC + (where&3)); +} + +/* + * standard system firmware adress emitter + */ + +static int system_memarea(unsigned long *address, unsigned long *size, + struct pci_dev *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + const struct pci_driver *drv; + drv = pci_dev_driver(dev); +#endif +#ifndef __alpha__ + *address=0xffe00000; + *size=2048*1024; +#else + *address=0xfffffffffc000000; + *size=512*1024; +#endif + printk(KERN_INFO "BIOS: Probing system firmware with " + "%ldk rom area @0x%lx (%04x:%04x)\n", + (*size>>10), *address, dev->vendor, dev->device ); +#ifdef CONFIG_PCI_NAMES +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (drv) printk(KERN_INFO "BIOS: System device is %s\n", drv->name); +#else + printk(KERN_INFO "BIOS: System device is %s\n", dev->name); +#endif +#endif + return 0; +} + +static int memarea_256k(unsigned long *address, unsigned long *size, + struct pci_dev *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + const struct pci_driver *drv; + drv = pci_dev_driver(dev); +#endif + *address=0xfffc0000; + *size=256*1024; + printk(KERN_INFO "BIOS: Probing system firmware with " + "%ldk rom area @0x%lx (%04x:%04x)\n", + (*size>>10), *address, dev->vendor, dev->device ); +#ifdef CONFIG_PCI_NAMES +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (drv) printk(KERN_INFO "BIOS: System device is %s\n", drv->name); +#else + printk(KERN_INFO "BIOS: System device is %s\n", dev->name); +#endif +#endif + return 0; +} + +/* + * standard address emitter for normal pci devices + */ + +static int default_memarea(unsigned long *address, unsigned long *size, + struct pci_dev *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + *address=dev->resource[PCI_ROM_RESOURCE].start; + *size=dev->resource[PCI_ROM_RESOURCE].end - *address + 1; +#else + *address=0xdeadbeef; + *size=0x00000000; +#endif + if (*address && (signed long)*address!=-1 ) { + printk (KERN_DEBUG "BIOS: Probing PCI device %02x:%02x.%01x " + "with %ldk rom area @ 0x%lx\n", + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), + (*size>>10), *address); + return 1; + } + *address=0xdeadbeef; + *size=0x00000000; + return 0; +} + +#ifdef __alpha__ +void probe_alphafw(void) +{ + switch(hwrpb->sys_type) { + case ST_DEC_EB164: + /* Fall through */ + break; + case ST_DTI_RUFFIAN: + /* case ST_DEC_TSUNAMI: // This crashes for whatever reason */ + probe_pcibus(); + return; + default: + printk(KERN_INFO "BIOS: unsupported alpha motherboard.\n"); + return; + } + + /* LX164 has system variation 0x2000 */ + if (hwrpb->sys_variation == 0x2000) + printk(KERN_INFO "BIOS: LX164 detected\n"); + else + printk(KERN_INFO "BIOS: EB164 board detected. Sys_var=0x%lx\n", + hwrpb->sys_variation); + + flashdevices[flashcount].data=(void *)0xfff80000; + flash_probe_area(0xfff80000, 512*1024, 0); +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#define pci_for_each_dev(dev) \ + for(dev = pci_devices->next; dev != pci_devices; dev = dev->next) +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,74) +#define pci_for_each_dev(dev) \ + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev))) +#endif + +#define DEVICE(x) devices[g].pcidevs[x] +void probe_pcibus(void) +{ + struct pci_dev *dev=NULL; + unsigned int g=0, d, map_always=0; + unsigned long addr, size; + + /* Look whether we find something supported */ + pci_for_each_dev(dev) { + /* Search all device groups */ + for (g=0; DEVICE(0); g++ ) { + /* Search all devices in group */ + for (d=0; DEVICE(d) && DEVICE(d) != pci_id(dev); d++); + if(DEVICE(d) == pci_id(dev)) + break; + } + + flashdevices[flashcount].idx=g; + flashdevices[flashcount].data=dev; + + map_always=devices[g].memarea(&addr, &size, dev); +#ifdef DEBUG_PCI + printk(KERN_INFO "BIOS: device=%x, cs=%d addr=%lx, size=%ld\n", + pci_id(dev),g, addr,size); +#endif + if(!size) + continue; + + flash_probe_area(addr, size, map_always); + } +} +#undef DEVICE + +/* Intel 430, 440, 450 PCI Chipsets */ + +#define CURRENT ((struct pci_dev *)flashdevices[currflash].data) +static int gporeg_save; +static void intel4x0_activate(void) +{ +#ifdef __ABIT_BE6II_v11__ +#define GPONUM 26 +#define GPOREG_OFFSET 0x34 + register unsigned int gporeg; + /* Read Bus 0, Dev 7, Func 3, Reg 40-44 (Power Managment Base Address) */ + outl (0x80003B40, 0x0CF8); + /* calc General Purpose Output Register I/O port address */ + gporeg = (0xFFFFFFFE & inl (0x0CFC)) + GPOREG_OFFSET; + + /* Set GPO26 to 0 */ + gporeg_save=inl(gporeg); + printk(KERN_DEBUG "BIOS: GPOREG=0x%08x, mask=0x%x, new=0x%x\n",gporeg_save, (~(1<device < 0x7000) { + /* enable 512k */ + pci_dummy[2]|=0x80; + } else { + /* enable 1M */ + pci_write(CURRENT, 0x4f, pci_dummy[1] | 0x02); + } + + pci_write(CURRENT, 0x4e, pci_dummy[0] | pci_dummy[2]); + + // printk(KERN_DEBUG "BIOS: isa bridge cfg is 0x%02x\n", pci_dummy[0]); +} + +static void intel4x0_deactivate(void) +{ +#ifdef __ABIT_BE6II_v11__ +#define GPOREG_OFFSET 0x34 + register unsigned long gporeg; + + /* Read Bus 0, Dev 7, Func 3, Reg 40-44 (Power Managment Base Address) */ + outl (0x80003B40, 0x0CF8); + /* calc General Purpose Output Register I/O port address */ + gporeg = (0xFFFFFFFE & inl (0x0CFC)) + GPOREG_OFFSET; + + /* Reset GBO26 */ + outl (gporeg_save, gporeg); +#undef GPOREG_OFFSET +#endif + pci_write(CURRENT, 0x4e, pci_dummy[0]); + pci_write(CURRENT, 0x4f, pci_dummy[1]); +} + +/* preliminary support for Intel 830 mobile chipset. untested!! */ + +static void intel8x0_activate(void) +{ + pci_dummy[0]=pci_read(CURRENT, 0x4e); + pci_dummy[1]=pci_read(CURRENT, 0xe3); + pci_write(CURRENT, 0x4e, pci_dummy[0] | 0x01); + pci_write(CURRENT, 0xe3, pci_dummy[1] | 0xC0); + + // We don't have to change FWH_DEC_EN1, as it decodes + // all memory areas to the FWH per default. + // We try it anyways. + + // FWH_DEC_EN1: isabridge, 0xe3, 8bit, default 0xff. + // FWH_SEL1: isabridge, 0xe8, 32bit, default 0x00112233 (??) + + //printk(KERN_DEBUG "BIOS: BIOS_CNTL is 0x%02x\n", pci_dummy[0]); + //printk(KERN_DEBUG "BIOS: FWH_DEC_EN1 is 0x%02x\n", pci_dummy[1]); +} + +static void intel8x0_deactivate(void) +{ + pci_write(CURRENT, 0x4e, pci_dummy[0]); + pci_write(CURRENT, 0xe3, pci_dummy[1]); +} + +/* AMD 760/756/751 & VIA (M)VP3 */ + +static void amd7xx_activate(void) +{ + pci_dummy[0]=pci_read(CURRENT, 0x40); /* IO Control 1 */ + pci_dummy[1]=pci_read(CURRENT, 0x43); /* SEGEN */ + + pci_write(CURRENT, 0x40, pci_dummy[0] | 0x01); + pci_write(CURRENT, 0x43, pci_dummy[1] | 0x80); +} + +static void amd7xx_deactivate(void) +{ + pci_write(CURRENT, 0x43, pci_dummy[1]); + pci_write(CURRENT, 0x40, pci_dummy[0]); +} + +static void viamvp3_activate(void) +{ + hostbridge = pci_find_class(PCI_CLASS_BRIDGE_HOST<<8,NULL); + if (!hostbridge) + return; + pci_dummy[0]=pci_read(hostbridge,0x52); + pci_write(hostbridge, 0x52, pci_dummy[0] & 0xcf); + pci_dummy[1]=pci_read(hostbridge, 0x63); + pci_write(hostbridge, 0x63, pci_dummy[1] & 0x0f); + pci_dummy[2]=pci_read(CURRENT,0x43); + pci_write(CURRENT, 0x43, pci_dummy[2] |0xF8); + + pci_write(CURRENT, 0x40, pci_read(CURRENT,0x40) | 0x01); +} + +static void viamvp3_deactivate(void) +{ + if (!hostbridge) + return; + pci_write(CURRENT, 0x40, pci_read(CURRENT,0x40) & 0xfe); + pci_write(hostbridge, 0x63, pci_dummy[1]); + pci_write(hostbridge, 0x52, pci_dummy[0]); + pci_write(CURRENT, 0x43, pci_dummy[2]); +} + +/* SiS works with 530/5595 chipsets */ + +static void sis_activate(void) +{ + char b; + hostbridge = pci_find_class(PCI_CLASS_BRIDGE_HOST<<8,NULL); + if (!hostbridge) + return; + + pci_dummy[0]=pci_read(hostbridge, 0x76); + pci_dummy[1]=readb(0x51); + pci_dummy[2]=pci_read(CURRENT, 0x40); + pci_dummy[3]=pci_read(CURRENT, 0x45); + + /* disable shadow */ + pci_write(hostbridge, 0x76, 0x00); + /* disable cache */ + writeb(pci_dummy[1] & 0x7f, 0x51); + + /* Enable 0xFFF8000~0xFFFF0000 decoding on SiS 540/630 */ + pci_write(CURRENT, 0x40, pci_dummy[2]|0x0b); + /* Flash write enable on SiS 540/630 */ + pci_write(CURRENT, 0x45, pci_dummy[3]|0x40); + + /* The same thing on SiS 950 SuperIO side */ + outb(0x87, 0x2e); + outb(0x01, 0x2e); + outb(0x55, 0x2e); + outb(0x55, 0x2e); + if (inb(0x2f) != 0x87) { + /* printf("Can not access SiS 950\n"); */ + return; + } + + outb(0x24, 0x2e); + b = inb(0x2f) | 0xfc; + outb(0x24, 0x2e); + outb(b, 0x2f); + outb(0x02, 0x2e); + outb(0x02, 0x2f); +} + +static void sis_deactivate(void) +{ + if (!hostbridge) + return; + + /* Restore PCI Registers */ + pci_write(hostbridge, 0x76, pci_dummy[0]); + pci_write(CURRENT, 0x45, pci_dummy[2]); + pci_write(CURRENT, 0x45, pci_dummy[3]); + /* restore cache to original status */ + writeb(pci_dummy[1], 0x51); +} + +/* UMC 486 Chipset 8881/886a */ + +static void umc_activate(void) +{ + hostbridge = pci_find_class(PCI_CLASS_BRIDGE_HOST<<8,NULL); + if (!hostbridge) + return; + + pci_dummy[0]=pci_read(hostbridge, 0x54); + pci_dummy[1]=pci_read(hostbridge, 0x55); + + pci_write(hostbridge, 0x54, 0x00); + pci_write(hostbridge, 0x55, 0x40); + + pci_write(CURRENT,0x47, pci_read(CURRENT,0x47) & ~0x40); +} + +static void umc_deactivate(void) +{ + if (!hostbridge) + return; + + pci_write(CURRENT, 0x47, pci_read(CURRENT,0x47) | 0x40); + + pci_write(hostbridge, 0x54, pci_dummy[0]); + pci_write(hostbridge, 0x55, pci_dummy[1]); +} + +/* CS5530 functions */ + +static void cs5530_activate(void) +{ + /* Save modified registers for later reset */ + pci_dummy[0]=pci_read(CURRENT,0x52); + pci_dummy[1]=pci_read(CURRENT,0x5b); + + /* enable rom write access */ + pci_write(CURRENT, 0x52, pci_dummy[0]|0x06); + + /* enable rom positive decode */ + // pci_write(CURRENT,0x5b, pci_dummy[1]|0x20); + // pci_write(CURRENT,0x52, pci_read(CURRENT,0x52)|0x01); +} + +static void cs5530_deactivate(void) +{ + pci_write(CURRENT, 0x52, pci_dummy[0]); + // pci_write(CURRENT, 0x5b, pci_dummy[1]); +} + +/* Reliance / ServerWorks */ + +static void reliance_activate(void) +{ + pci_dummy[0]=pci_read(CURRENT,0x41); + pci_dummy[1]=pci_read(CURRENT,0x70); + pci_dummy[2]=inb(0xc6f); + + /* Enable 512k */ + pci_write(CURRENT, 0x41, pci_dummy[0] | 0x02); + /* Enable 4MB */ + pci_write(CURRENT, 0x70, pci_dummy[1] | 0x80); + /* Enable flash write */ + outb(pci_dummy[2] | 0x40, 0xc6f); +} + +static void reliance_deactivate(void) +{ + pci_write(CURRENT, 0x41, pci_dummy[0]); + pci_write(CURRENT, 0x70, pci_dummy[1]); + outb(pci_dummy[2], 0xc6f); +} + +/* ALi Methods - untested */ +static void ali_activate(void) +{ + pci_dummy[0]=pci_read(CURRENT, 0x47); + pci_dummy[1]=pci_read(CURRENT, 0x79); + pci_dummy[2]=pci_read(CURRENT, 0x7f); + + /* write enable, 256k enable */ +#ifdef OLD_ALi + pci_write(CURRENT, 0x47, pci_dummy[0]|0x47); +#else + pci_write(CURRENT, 0x47, pci_dummy[0]|0x43); +#endif + + /* M1543C rev B1 supports 512k. Register reserved before */ +#ifdef OLD_ALi + pci_write(CURRENT, 0x79, pci_dummy[1]|0x10); + pci_write(CURRENT, 0x7f, pci_dummy[2]|0x01); +#else + pci_write(CURRENT, 0x7b, pci_dummy[1]|0x10); +#endif +} + +static void ali_deactivate(void) +{ + pci_write(CURRENT, 0x47, pci_dummy[0]); + pci_write(CURRENT, 0x79, pci_dummy[1]); + pci_write(CURRENT, 0x7f, pci_dummy[2]); +} + +/* Default routines. Use these if nothing else works */ +#if 0 +static unsigned int def_addr; +#endif +static void default_activate(void) +{ +#if 0 && LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0) + struct resource *r; + + r=&CURRENT->resource[PCI_ROM_RESOURCE]; + + r->flags |= PCI_ROM_ADDRESS_ENABLE; + r->flags &= ~(IORESOURCE_READONLY|IORESOURCE_CACHEABLE); + pci_read_config_dword(CURRENT, CURRENT->rom_base_reg, &def_addr); + if (def_addr) + pci_write_config_dword (CURRENT, CURRENT->rom_base_reg, + def_addr|PCI_ROM_ADDRESS_ENABLE); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + long ret; + + if (pci_enable_device(CURRENT)) + return; + + pci_write_config_dword (CURRENT, CURRENT->rom_base_reg, + pci_resource_start(CURRENT, PCI_ROM_RESOURCE)| + PCI_ROM_ADDRESS_ENABLE); + + ret=(long)request_mem_region( pci_resource_start(CURRENT, + PCI_ROM_RESOURCE), pci_resource_len(CURRENT, + PCI_ROM_RESOURCE), "Firmware memory"); + if (!ret) + printk (KERN_ERR "BIOS: cannot reserve MMROM region " + "0x%lx+0x%lx\n", + pci_resource_start(CURRENT, PCI_ROM_RESOURCE), + pci_resource_len(CURRENT, PCI_ROM_RESOURCE)); + else + printk (KERN_INFO "BIOS: mapped rom region to 0x%lx\n", ret); +#endif +} + +static void default_deactivate(void) +{ +#if 0 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + struct resource *r; + r=&CURRENT->resource[PCI_ROM_RESOURCE]; + r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + r->flags |= (IORESOURCE_READONLY|IORESOURCE_CACHEABLE); + pci_write_config_dword (CURRENT, CURRENT->rom_base_reg, def_addr); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + release_mem_region(pci_resource_start(CURRENT, PCI_ROM_RESOURCE), + pci_resource_len(CURRENT, PCI_ROM_RESOURCE)); +#endif +} + +const struct flashdev devices[] = { + /* Intel 4x0 chipsets */ + { (int[]) { 0x8086122e, 0x80861234, 0x80867000, 0x80867110, + 0x80867198, 0 }, + intel4x0_activate, intel4x0_deactivate, system_memarea }, + + /* Intel 8x0 chipsets */ + { (int[]) { 0x80862410, 0x80862420, 0x80862440, 0x8086244c, + 0x80862480, 0x8086248c, 0x80867600, 0 }, + intel8x0_activate, intel8x0_deactivate, system_memarea }, + + /* Irongate 75x, AMD-76xMP(X), VT8231/3 */ + { (int[]) { 0x10227400, 0x10227408, 0x10227410, 0x10227440, + 0x11068231, 0x11063074, 0 }, + amd7xx_activate, amd7xx_deactivate, system_memarea }, + + /* AMD Hammer (thor chipset) */ + { (int[]) { 0x10227468, 0 }, + amd7xx_activate, amd7xx_deactivate, system_memarea }, + + /* VIA (M)VP3, VT82C686 [Apollo Super South] */ + { (int[]) { 0x11060586, 0x11060596, 0x11060686, 0 }, + viamvp3_activate, viamvp3_deactivate, memarea_256k }, + + /* UMC */ + { (int[]) { 0x1060886a, 0x10600886, 0x1060e886, 0x10608886, 0 }, + umc_activate, umc_deactivate, system_memarea }, + + /* SiS */ + { (int[]) { 0x10390008, 0x10390018, 0 }, + sis_activate, sis_deactivate, system_memarea }, + + /* OPTi */ + { (int[]) { 0x1045c558, 0 }, + default_activate, default_deactivate, system_memarea }, + + /* NSC CS5530(A) */ + { (int[]) { 0x10780100, 0 }, + cs5530_activate, cs5530_deactivate, memarea_256k }, + + /* Reliance/ServerWorks NB6xxx */ + { (int[]) { 0x11660200, 0 }, + reliance_activate, reliance_deactivate, system_memarea }, + + /* ALi */ + { (int[]) { 0x10b91523, 0x10b91533, 0x10b91543, 0 }, + ali_activate, ali_deactivate, system_memarea }, + + { (int[]) { 0x00000000 }, + default_activate, default_deactivate, default_memarea } +}; + +#endif /* CONFIG_PCI */ + diff --git a/utils/devbios/pcisets.h b/utils/devbios/pcisets.h new file mode 100644 index 0000000..1045f0a --- /dev/null +++ b/utils/devbios/pcisets.h @@ -0,0 +1,45 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * pcisets.h - structures for device bindings + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include + +#ifdef CONFIG_PCI + +struct flashdev { + unsigned int *pcidevs; + void (*activate)(void); + void (*deactivate) (void); + int (*memarea)(unsigned long *address, unsigned long *size, + struct pci_dev *dev); +}; + +extern const struct flashdev devices[]; + +void probe_pcibus(void); +#ifdef __alpha__ +void probe_alphafw(void); +#endif +#endif diff --git a/utils/devbios/procfs.c b/utils/devbios/procfs.c new file mode 100644 index 0000000..12ad17e --- /dev/null +++ b/utils/devbios/procfs.c @@ -0,0 +1,162 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * procfs.c - proc filesystem handling for flash device listing. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && defined(MODVERSIONS) +#include +#endif +#include + +#ifdef CONFIG_PROC_FS +#include "bios.h" +#include "pcisets.h" +#include "flashchips.h" +#include "programming.h" + +struct proc_dir_entry *proc_bios; + +#define PRINT_PROC(fmt,args...) \ + do { \ + if (!run) \ + break; \ + len += sprintf( buffer+len, fmt, ##args ); \ + if (begin + len > offset + size) \ + run=0; \ + else if (begin + len < offset) { \ + begin += len; \ + len = 0; \ + } \ + } while (0) + +/* + * ****************************************** + * + * /proc/bios handling + * + * ****************************************** + */ + +#define CFLASH flashdevices[i] +#define FLASH flashchips[CFLASH.flashnum] +#define MANUF manufacturers[CFLASH.manufnum] + +int bios_read_proc(char *buffer, char **start, off_t offset, int size, int *eof, void *data) +{ + int len=0, run=1, i; + off_t begin = 0; + + for (i=0;i>10); + PRINT_PROC("Flash Type : "); + + if (CFLASH.id == 0) { + PRINT_PROC("ROM\n"); + continue; + } + + /* Flash chip completely unknown -> output ID and proceed */ + if (FLASH.id == 0) { + PRINT_PROC("unknown %s device (id 0x%04x)\n", + MANUF.name, CFLASH.id); + PRINT_PROC("Supported : no\n"); + continue; + } + + PRINT_PROC("%s %s (%dV)\n", MANUF.name, + FLASH.name, FLASH.voltage); + + PRINT_PROC("Supported : %s\n", + FLASH.supported ? "yes": "no"); +#ifdef DEBUG + PRINT_PROC("Pagetable : %d Byte\n", FLASH.pagesize ); + + PRINT_PROC("Erase first : %s\n", + FLASH.flags & f_needs_erase ? "yes": "no"); + + PRINT_PROC("Intel compliant : %s\n", + FLASH.flags & f_intel_compl ? "yes": "no"); + + PRINT_PROC("FWH compliant : %s\n", + FLASH.flags & f_fwh_compl ? "yes": "no"); + + if (CFLASH.sectors > 1) + PRINT_PROC("Sectors : %d\n", CFLASH.sectors); +#endif + } +#ifdef DEBUG_PROC + printk(KERN_DEBUG "BIOS: read_proc done.\n"); +#endif + /* set to 1 if we're done */ + *eof=run; + + if (offset >= begin + len) + return 0; + + *start = buffer + (begin - offset); + + return (size < begin + len - offset ? size : begin + len - offset); +} +#undef FLASH +#undef MANUF +#undef CFLASH + +#ifdef PROC_WRITEABLE +int bios_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + printk (KERN_INFO "%s\n",buffer); + return count; +} +#endif + +int bios_proc_register(void) +{ + if ((proc_bios = create_proc_entry("bios", 0, 0))) { + proc_bios->read_proc = bios_read_proc; +#ifdef PROC_WRITABLE + proc_bios->write_proc = bios_write_proc; +#endif + return 0; + } + return 1; +} + +int bios_proc_unregister(void) +{ + if (proc_bios) + remove_proc_entry("bios", 0); + return 0; +} +#endif diff --git a/utils/devbios/programming.c b/utils/devbios/programming.c new file mode 100644 index 0000000..e1b35a3 --- /dev/null +++ b/utils/devbios/programming.c @@ -0,0 +1,539 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * programming.c - flash device programming and probing algorithms. + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +// <-- C++ style comments are for experimental comments only. +// They will disappear as soon as I fixed all the stuff. + +/* #define DEBUG_PROBING */ + +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && defined(MODVERSIONS) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bios.h" +#include "pcisets.h" +#include "flashchips.h" +#include "programming.h" + +struct flashdevice flashdevices[BIOS_MAXDEV]; +int flashcount; + +/* + * ****************************************** + * + * flashchip handling + * + * ****************************************** + */ + + +void flash_command (unsigned char *addr, unsigned char command) +#if 1 +{ + flash_writeb(addr, 0x5555, 0xaa); + flash_writeb(addr, 0x2AAA, 0x55); + flash_writeb(addr, 0x5555, command); +} +void fwh_flash_command(unsigned char *addr, unsigned char command) +#endif +{ + flash_writeb(addr, 0x75555, 0xaa); + flash_writeb(addr, 0x72aaa, 0x55); + flash_writeb(addr, 0x75555, command); +} + +#define CFLASH flashdevices[flashcount] +int flash_probe_address(void *address) +{ + int flashnum=0, manufnum=0, sectors=0; + unsigned short flash_id, testflash; + unsigned long flags; +#ifdef DEBUG_PROBING + printk( KERN_DEBUG "BIOS: Probing for flash chip @0x%08lx\n", (unsigned long) address); +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + save_flags(flags); +#endif + spin_lock_irqsave(&bios_lock, flags); + + testflash= (flash_readb(address, 0))+(flash_readb(address, 1)<<8); + + /* 1st method: Intel, Atmel listen to this.. */ + + flash_command(address, 0x90); + udelay(20); + + flash_id = (flash_readb(address, 0))+(flash_readb(address, 1)<<8); + +#ifdef DEBUG_PROBING + printk (KERN_DEBUG "BIOS: testflash[%04x] flash_id[%04x]\n", + testflash, flash_id); +#endif + + /* 2nd method: Winbond (I think this is Jedec standard) */ + + if (flash_id==testflash) { +#ifdef DEBUG_PROBING + printk (KERN_DEBUG "BIOS: Trying 2nd ID method.\n"); +#endif + flash_command(address, 0xf0); /* Reset */ + udelay(20); + + flash_command(address, 0x80); + flash_command(address, 0x60); + udelay(20); + + flash_id = (flash_readb(address, 0))+(flash_readb(address, 1)<<8); +#ifdef DEBUG_PROBING + printk (KERN_DEBUG "BIOS: testflash[%04x] flash_id[%04x]\n", + testflash, flash_id); +#endif + } + + /* 3rd Method: Some Winbonds seem to want this */ + + if (flash_id==testflash) { +#ifdef DEBUG_PROBING + printk (KERN_DEBUG "BIOS: Trying 3rd ID method.\n"); +#endif + flash_command(address, 0xf0); /* Reset again */ + udelay(20); + + flash_command(address, 0x80); + flash_command(address, 0x20); + udelay(20); + + flash_id = (flash_readb(address, 0))+(flash_readb(address, 1)<<8); +#ifdef DEBUG_PROBING + printk (KERN_DEBUG "BIOS: testflash[%04x] flash_id[%04x]\n", + testflash, flash_id); +#endif + } + + if (flash_id==0x7f7f && flash_readb(address, 0x100)==0x1c) { + /* We have an Eon flashchip. They keep their + * device id at 0x101 instead of 0x1 + */ + printk(KERN_INFO "BIOS: Eon flash device detected\n"); + flash_id=(flash_readb(address, 0x1))+(flash_readb(address, 0x101)<<8); + } + + flash_command(address, 0xf0); + udelay(20); + + spin_unlock_irqrestore(&bios_lock, flags); + + if (flash_id==testflash) return 0; /* Nothing found :-( */ + + while (flashchips[flashnum].id!=0) { + if (flash_id==flashchips[flashnum].id) + break; + flashnum++; + } + + while (manufacturers[manufnum].id!=0) { + if ((flash_id&0xff)==manufacturers[manufnum].id) + break; + manufnum++; + } + + if (flashchips[flashnum].id) { + while (flashchips[flashnum].sectors[sectors]= BIOS_MAXDEV) { + printk(KERN_DEBUG "BIOS: Too many flash devices found.\n"); + return -1; + } + + CFLASH.flashnum = flashnum; + CFLASH.manufnum = manufnum; + CFLASH.id = flash_id; + CFLASH.size = (flashchips[flashnum].size<<10); + CFLASH.sectors = sectors; + CFLASH.open_mode= 0; + CFLASH.open_cnt = 0; + + return 1; +} + +void flash_probe_area(unsigned long romaddr, unsigned long romsize, + int map_always) +{ + unsigned long probeaddr; + unsigned char *mapped; + + mapped=ioremap(romaddr, romsize); + + devices[flashdevices[currflash].idx].activate(); + + probeaddr=(unsigned long)mapped; + + while ( probeaddr < (unsigned long)mapped + romsize - 0x5555 ) { + if ( flash_probe_address ((void *)probeaddr) != 1) { + probeaddr += 4*1024; + continue; + } + + CFLASH.offset = probeaddr-(unsigned long)mapped; + CFLASH.mapped = (unsigned long)mapped; + CFLASH.physical = romaddr+CFLASH.offset; + + printk( KERN_INFO "BIOS: flash device with size " + "%dk (ID 0x%04x) found.\n", + CFLASH.size >> 10, CFLASH.id); + + printk( KERN_INFO "BIOS: physical address " + "0x%08lx (va=0x%08lx+0x%lx).\n", + CFLASH.physical, (unsigned long)CFLASH.mapped, + CFLASH.offset); + + if (flashchips[CFLASH.flashnum].flags&f_fwh_compl) { + unsigned long t_lk; + unsigned int i=7; + printk(KERN_INFO "BIOS: FWH compliant " + "chip detected.\n"); + for (t_lk=0xffb80002; t_lk<=0xffbf0002; t_lk+=0x10000) + { + printk(KERN_INFO "Lock register %d " + "(0x%08lx): 0x%x\n", + i, t_lk, (unsigned int) + (readb(phys_to_virt(t_lk)))); + i--; + } + } + flashcount++; + currflash++; +#ifdef MULTIPLE_FLASH + probeaddr += flashdevices[flashcount-1].size; + flashdevices[flashcount].mapped=flashdevices[flashcount-1].mapped; + flashdevices[flashcount].data=flashdevices[flashcount-1].data; + continue; +#else + break; +#endif + } + + /* We might want to always map the memory + * region in certain cases + */ + + if (map_always) { + CFLASH.flashnum = 0; + CFLASH.manufnum = 0; + CFLASH.id = 0; + CFLASH.size = romsize; + CFLASH.sectors = 0; + CFLASH.open_mode= 0; + CFLASH.open_cnt = 0; + CFLASH.offset = 0; + CFLASH.mapped = (unsigned long)mapped; + CFLASH.physical = romaddr; + printk( KERN_INFO "BIOS: rom device with size " + "%dk registered.\n", CFLASH.size >> 10); + flashcount++; currflash++; + return; + } + + /* We found nothing in this area, so let's unmap it again */ + + if (flashcount && flashdevices[flashcount-1].mapped != (unsigned long)mapped) + iounmap(mapped); + + devices[flashdevices[currflash].idx].deactivate(); +} + +#undef CFLASH + +void flash_program (unsigned char *addr) +{ + flash_command(addr, 0xa0); +} + +void flash_program_atmel (unsigned char *addr) +{ + flash_command(addr, 0x80); + flash_command(addr, 0x20); +} + +int flash_erase (unsigned char *addr, unsigned int flashnum) +{ + flash_command(addr, 0x80); + flash_command(addr, 0x10); + udelay(80); + return flash_ready_toggle(addr, 0); +} + +int flash_erase_sectors (unsigned char *addr, unsigned int flashnum, unsigned int startsec, unsigned int endsec) +{ + unsigned int sector; + + if (!(flashchips[flashnum].flags & f_slow_sector_erase)) { + flash_command(addr, 0x80); + + if (flashchips[flashnum].flags&f_fwh_compl) { + flash_writeb(addr, 0x75555,0xaa); + flash_writeb(addr, 0x72aaa,0x55); + } else { + flash_writeb(addr, 0x5555,0xaa); + flash_writeb(addr, 0x2aaa,0x55); + } + + for (sector=startsec; sector <= endsec; sector++) { + flash_writeb (addr, flashchips[flashnum].sectors[sector]*1024, 0x30); + } + + udelay(150); // 80 max normally, wait 150usec to be sure +#if 0 + if (flashchips[flashnum].flags&f_fwh_compl) +#endif + return flash_ready_toggle(addr, flashchips[flashnum].sectors[sector-1]*1024); +#if 0 + else + return flash_ready_poll(addr, flashchips[flashnum].sectors[sector-1]*1024, 0xff); +#endif + } + + /* sectors must be sent the sector erase command for every sector */ + for (sector=startsec; sector <= endsec; sector++) { + flash_command(addr, 0x80); + if (flashchips[flashnum].flags&f_fwh_compl) { + flash_writeb(addr, 0x75555,0xaa); + flash_writeb(addr, 0x72aaa,0x55); + } else { + flash_writeb(addr, 0x5555,0xaa); + flash_writeb(addr, 0x2aaa,0x55); + } + + flash_writeb(addr, flashchips[flashnum].sectors[sector]*1024, 0x30); + udelay(150); +#if 0 + if (flashchips[flashnum].flags&f_fwh_compl) +#endif + flash_ready_toggle(addr, flashchips[flashnum].sectors[sector] *1024); +#if 0 + else + flash_ready_poll(addr, flashchips[flashnum].sectors[sector]*1024, 0xff); +#endif + } + + return 0; + +} + +/* waiting for the end of programming/erasure by using the toggle method. + * As long as there is a programming procedure going on, bit 6 of the last + * written byte is toggling it's state with each consecutive read. + * The toggling stops as soon as the procedure is completed. + * This function returns 0 if everything is ok, 1 if an error occured + * while programming was in progress. + */ + +int flash_ready_toggle (unsigned char *addr, unsigned int offset) +{ + unsigned long int timeout=0; + unsigned char oldflag, flag; + int loop=1; + + oldflag=flash_readb(addr, offset) & 0x40; + + while (loop && (timeout<0x7fffffff)) { + flag=flash_readb(addr, offset) & 0x40; + + if (flag == oldflag) + loop=0; + + oldflag=flag; + timeout++; + } + + if (loop) { + printk(KERN_DEBUG "BIOS: operation timed out (Toggle)\n"); + return 1; + } + + return 0; +} + +/* This functions is similar to the above one. While a programming + * procedure is going on, bit 7 of the last written data byte is + * inverted. When the procedure is completed, bit 7 contains the + * correct data value + */ + +int flash_ready_poll (unsigned char *addr, unsigned int offset, unsigned char data) +{ + unsigned long int timeout=0; + unsigned char flag; + + flag=flash_readb(addr, offset); + + while ( ( flag & 0x80) != ( data & 0x80)) { + if ( ( flag & 0x80 ) == ( data & 0x80 ) ) { +#ifdef DBGTIMEOUT + printk(KERN_DEBUG "BIOS: Timeout value (EOT Polling) %ld\n",timeout); +#endif + return 0; + } + flag=flash_readb(addr, offset); + if (timeout++>12800) { // 10 times more than usual. + printk(KERN_ERR "BIOS: EOT Polling timed out at 0x%08x." + " Try again or increase max. timeout.\n",offset); + return 1; + } + if ((flag & 0x80) == ( data & 0x80)) { + flag=flash_readb(addr, offset); + } + } +#ifdef DBGTIMEOUT + printk(KERN_DEBUG "BIOS: Timeout value (EOT Polling) %ld\n",timeout); +#endif + + flag=flash_readb(addr, offset); + if ( ( flag & 0x80 ) == ( data & 0x80 ) ) return 0; else return 1; +} + + + +void iflash_program_byte (unsigned char *addr, unsigned int offset, unsigned char data) +{ + unsigned long int timeout=0; + unsigned char flag; + + flash_writeb (addr, offset, 0x40); + flash_writeb (addr, offset, data); + + flash_writeb (addr, offset, 0x70); /* Read Status */ + do { + flag=flash_readb (addr, offset); + if (timeout++>100) { // usually 2 or 3 :-) + printk(KERN_ERR "BIOS: Intel programming timed out at" + "0x%08x. Try again or increase max. timeout.\n",offset); + return; + } + } while ((flag&0x80) != 0x80); + +#ifdef DBGTIMEOUT + printk (KERN_DEBUG"BIOS: Timeout value (Intel byte program) %ld\n",timeout); +#endif + + if (flag&0x18) { + flash_writeb (addr, offset, 0x50); /* Reset Status Register */ + printk (KERN_ERR "BIOS: Error occured, please repeat write operation. (intel)\n"); + } + + flash_writeb (addr, offset, 0xff); +} + + + +int iflash_erase_sectors (unsigned char *addr, unsigned int flashnum, unsigned int startsec, unsigned int endsec) +{ + unsigned long int timeout; + unsigned int sector, offset=0; + unsigned char flag; + + for (sector=startsec; sector<=endsec; sector++) { + offset=(flashchips[flashnum].sectors[sector]*1024); + flash_writeb (addr, offset, 0x20); + flash_writeb (addr, offset, 0xd0); + + flash_writeb (addr, offset, 0x70); /* Read Status */ + timeout=0; + do { + flag=flash_readb (addr, offset); + if (timeout++>1440000) { // usually 144000 + printk(KERN_ERR "BIOS: Intel sector erase timed out at 0x%08x. Try again or increase max. timeout.\n",offset); + return 1; + } + } while ((flag&0x80) != 0x80); + +#ifdef DBGTIMEOUT + printk (KERN_DEBUG "BIOS: Timeout value (Intel sector erase) %ld\n",timeout); +#endif + + if (flag&0x28) { + flash_writeb (addr, offset, 0x50); + flash_writeb (addr, offset, 0xff); + return 1; /* Error! */ + } + } + + flash_writeb (addr, offset, 0xff); + return 0; +} + + + +unsigned char flash_readb(unsigned char *addr, unsigned int offset) +{ +#if defined(__alpha__) + if (flashdevices[currflash].data==(void *)0xfff80000) { + if (offset<0x80000) + outb(0x00,0x800); + else { + outb(0x01, 0x800); + offset-=0x80000; + } + } +#endif + return readb(addr+offset); +} + + + +void flash_writeb(unsigned char *addr, unsigned int offset, unsigned char data) +{ +#if defined(__alpha__) + if (flashdevices[currflash].data==(void *)0xfff80000) { + if (offset<0x80000) + outb(0x00,0x800); + else { + outb(0x01, 0x800); + offset-=0x80000; + } + } +#endif +/* + printk(KERN_DEBUG "BIOS: writing 0x%02x to 0x%lx+0x%x\n", + data,bios,offset); + */ + writeb(data,addr+offset); +} diff --git a/utils/devbios/programming.h b/utils/devbios/programming.h new file mode 100644 index 0000000..3ad104e --- /dev/null +++ b/utils/devbios/programming.h @@ -0,0 +1,73 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * programming.h - prototypes for flash device programming + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* Addresses */ +#define ADDR_MANUFACTURER 0x0000 +#define ADDR_DEVICE_ID 0x0001 +#define ADDR_SECTOR_LOCK 0x0002 +#define ADDR_HANDSHAKE 0x0003 + +#define ADDR_UNLOCK_1 0x5555 +#define ADDR_UNLOCK_2 0x2AAA +#define ADDR_COMMAND 0x5555 + +/* Commands */ +#define CMD_UNLOCK_DATA_1 0xAA +#define CMD_UNLOCK_DATA_2 0x55 +#define CMD_MANUFACTURER_UNLOCK_DATA 0x90 +#define CMD_UNLOCK_BYPASS_MODE 0x20 +#define CMD_PROGRAM_UNLOCK_DATA 0xA0 +#define CMD_RESET_DATA 0xF0 +#define CMD_SECTOR_ERASE_UNLOCK_DATA 0x80 +#define CMD_SECTOR_ERASE_UNLOCK_DATA_2 0x30 +#define CMD_ERASE_DATA 0x10 +#define CMD_UNLOCK_SECTOR 0x60 + +extern int flashcount; + +void flash_command(unsigned char *addr, unsigned char command); + +void flash_program (unsigned char *addr); +void flash_program_atmel (unsigned char *addr); + +int flash_ready_toggle (unsigned char *addr, unsigned int offset); +int flash_ready_poll (unsigned char *addr, unsigned int offset, unsigned char data); + +int flash_erase (unsigned char *addr, unsigned int flashnum); +int flash_erase_sectors (unsigned char *addr, unsigned int flashnum, + unsigned int startsec, unsigned int endsec); + +void iflash_program_byte (unsigned char *addr, unsigned int offset, unsigned char data); +int iflash_erase_sectors (unsigned char *addr, unsigned int flashnum, unsigned int startsec, unsigned int endsec); + +unsigned char flash_readb(unsigned char *addr, unsigned int offset); +void flash_writeb(unsigned char *addr, unsigned int offset, unsigned char data); + + +int flash_probe_address(void *address); +void flash_probe_area(unsigned long romaddr, unsigned long romsize, + int map_always); + diff --git a/utils/dist/debian/changelog b/utils/dist/debian/changelog new file mode 100644 index 0000000..d3c96a5 --- /dev/null +++ b/utils/dist/debian/changelog @@ -0,0 +1,6 @@ +openbios (0.1-1) unstable; urgency=low + + * Initial Debian version. + + -- Patrick Mauritz Mon, 22 Jul 2002 23:24:56 +0200 + diff --git a/utils/dist/debian/control b/utils/dist/debian/control new file mode 100644 index 0000000..5bf02d7 --- /dev/null +++ b/utils/dist/debian/control @@ -0,0 +1,16 @@ +Source: openbios +Maintainer: Patrick Mauritz +Section: devel +Priority: optional +Standards-Version: 3.5.2 +Build-Depends: grep-dctrl, yada (>= 0.9.9) + +Package: openbios +Architecture: any +Depends: ${openbios:Depends} +Description: OpenBIOS - OpenFirmware development tools + It contains: + - toke: tokenizer for fcode programs + - detok: decompiler for fcode programs + - paflof: (yet) incomplete forth environment which will be + _the_ core of OpenBIOS diff --git a/utils/dist/debian/packages b/utils/dist/debian/packages new file mode 100644 index 0000000..5dc56c0 --- /dev/null +++ b/utils/dist/debian/packages @@ -0,0 +1,45 @@ +Source: openbios +Section: devel +Priority: optional +Maintainer: Patrick Mauritz +Packager: Patrick Mauritz +Standards-Version: 3.5.2 +Upstream-Source: +Home-Page: +Description: OpenBIOS - OpenFirmware development tools +Copyright: GPL + Copyright 2001-2002 Stefan Reinauer, Segher Boessenkool +Major-Changes: + First release +Build: sh + CC=gcc + CFLAGS="-O2 -Wall" + cd toke; make; strip toke; cd .. + cd detok; make; strip detok; cd .. + cd paflof; make; strip paflof; cd .. + find toke/examples -name .cvsignore | xargs rm -f +Clean: sh + cd toke; make clean; cd .. + cd detok; make clean; cd .. + cd paflof; make clean; cd .. + +Package: openbios +Architecture: any +Depends: [/usr/bin/*] +Description: OpenBIOS - OpenFirmware development tools + It contains: + - toke: tokenizer for fcode programs + - detok: decompiler for fcode programs + - paflof: (yet) incomplete forth environment which will be + _the_ core of OpenBIOS +Install: sh + mkdir -p $ROOT/usr/bin + mkdir -p $ROOT/usr/share/openbios + mkdir -p $ROOT/usr/share/doc/packages/openbios + cp toke/toke $ROOT/usr/bin + cp detok/detok $ROOT/usr/bin + cp paflof/paflof $ROOT/usr/bin + cp -a toke/examples $ROOT/usr/share/doc/openbios + cp -a forth $ROOT/usr/share/openbios + cp toke/README $ROOT/usr/share/doc/openbios/README.toke + cp detok/README $ROOT/usr/share/doc/openbios/README.detok diff --git a/utils/dist/debian/rules b/utils/dist/debian/rules new file mode 100755 index 0000000..6bf5326 --- /dev/null +++ b/utils/dist/debian/rules @@ -0,0 +1,189 @@ +#! /usr/bin/make -f +# Generated automatically from debian/packages +# by yada v0.9.9, of Tue, 07 Dec 1999 +# Modified by Piotr Roszatycki , Mon, 1 Oct 2001 13:14:11 +0200 + +DEB_HOST_GNU_CPU := $(shell dpkg-architecture -qDEB_HOST_GNU_CPU) +DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_HOST_GNU_SYSTEM := $(shell dpkg-architecture -qDEB_HOST_GNU_SYSTEM) + +DEB_BUILD_GNU_CPU := $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU) +DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_BUILD_GNU_SYSTEM := $(shell dpkg-architecture -qDEB_BUILD_GNU_SYSTEM) + +VERSION:=$(shell LC_ALL=C dpkg-parsechangelog | sed -ne 's/^Version: *\([^2]*\)/\1/p') + +SHELL=/bin/bash + +.PHONY: default +default: + @echo "Specify a target:"; \ + echo " build compile the package"; \ + echo " binary make all binary packages"; \ + echo " binary-arch make all architecture-dependent binary packages"; \ + echo " binary-indep make all architecture-independent binary packages"; \ + echo " clean clean up the source package"; \ + echo; \ + echo " depends check build-time dependencies"; \ + echo " install-tree compile the package and create the install trees"; \ + echo " clean-install-tree clean up only under debian/"; \ + echo + +# Check build dependencies and conflicts + +.PHONY: depends +depends: chmod-yada debian/depends-stamp +debian/depends-stamp: + @echo 'Checking build conflicts and dependencies; just a minute...' + @echo -n 'grep-dctrl...'; v=$$(grep-status -X -F Package 'grep-dctrl' | grep Version | head -1 | sed -e 's/^Version: //'); \ + if test ! "$$v"; then echo -n 'grep-dctrl (virtual package)...'; v=$$(grep-status -e -F Provides '(^grep-dctrl, |, grep-dctrl$$|^grep-dctrl$$)' | grep Version | head -1 | sed -e 's/^Version: //'); fi; \ + if test "$$v"; then \ + exit 0; \ + fi; \ + echo 'Build depends on `grep-dctrl'\'' (any version), which is not satisfied' | fmt; exit 1 + @echo -n 'yada...'; v=$$(grep-status -X -F Package 'yada' | grep Version | head -1 | sed -e 's/^Version: //'); \ + if test ! "$$v"; then echo -n 'yada (virtual package)...'; v=$$(grep-status -e -F Provides '(^yada, |, yada$$|^yada$$)' | grep Version | head -1 | sed -e 's/^Version: //'); fi; \ + if test "$$v"; then \ + if dpkg --compare-versions "$$v" '>=' '0.9.9'; then \ + exit 0; \ + fi; \ + fi; \ + echo 'Build depends on `yada'\'' (version >= 0.9.9), which is not satisfied' | fmt; exit 1 + @echo + @echo 'Conflicts and dependencies all satisfied!' + touch debian/depends-stamp + +# Build the package and prepare the install tree + +.PHONY: build-only build +build-only: debian/build-stamp +build: chmod-yada build-only + +# Make sure these rules and the control file are up-to-date + +.PHONY: rules control +rules: debian/rules +debian/rules: $(shell which yada) debian/packages + $(shell which yada) rebuild rules + +control: debian/control +debian/control: $(shell which yada) debian/packages + $(shell which yada) rebuild control + +debian/build-stamp: debian/depends-stamp + @[ -f $(shell which yada) -a -f debian/rules ] + @umask 022 \ + && export PACKAGE="openbios" \ + && export VERSION="$(VERSION)" \ + && export DEB_HOST_GNU_CPU="$(DEB_HOST_GNU_CPU)" \ + && export DEB_HOST_GNU_TYPE="$(DEB_HOST_GNU_TYPE)" \ + && export DEB_HOST_GNU_SYSTEM="$(DEB_HOST_GNU_SYSTEM)" \ + && export DEB_BUILD_GNU_CPU="$(DEB_BUILD_GNU_CPU)" \ + && export DEB_BUILD_GNU_TYPE="$(DEB_BUILD_GNU_TYPE)" \ + && export DEB_BUILD_GNU_SYSTEM="$(DEB_BUILD_GNU_SYSTEM)" \ + && (\ + echo -E 'eval "yada () { perl $$(which yada) \"\$$@\"; }"; set -e; set -v';\ + echo -E 'CC=gcc';\ + echo -E 'CFLAGS="-O2 -Wall"';\ + echo -E 'cd toke; make; strip toke; cd ..';\ + echo -E 'cd detok; make; strip detok; cd ..';\ + echo -E 'cd paflof; make; strip paflof; cd ..';\ + echo -E 'find toke/examples -name .cvsignore | xargs rm -f') | /bin/sh + touch debian/build-stamp + +.PHONY: install-tree +install-tree: chmod-yada install-tree-any +install-tree-any: \ + debian/tmp-openbios/DEBIAN/control + +debian/tmp-openbios/DEBIAN/control: debian/build-stamp debian/control + rm -rf debian/tmp-openbios + umask 022 && install -d debian/tmp-openbios/DEBIAN + install -d debian/tmp-openbios/usr/share/doc/openbios + umask 022; $(shell which yada) generate copyright \ + >debian/tmp-openbios/usr/share/doc/openbios/copyright + install -m 644 -p debian/changelog \ + debian/tmp-openbios/usr/share/doc/openbios/changelog.Debian + @umask 022 \ + && export PACKAGE="openbios" \ + && export ROOT="$$(pwd)/debian/tmp-openbios" \ + && export CONTROL="$$(pwd)/debian/tmp-openbios/DEBIAN" \ + && export VERSION="$(VERSION)" \ + && export DEB_HOST_GNU_CPU="$(DEB_HOST_GNU_CPU)" \ + && export DEB_HOST_GNU_TYPE="$(DEB_HOST_GNU_TYPE)" \ + && export DEB_HOST_GNU_SYSTEM="$(DEB_HOST_GNU_SYSTEM)" \ + && export DEB_BUILD_GNU_CPU="$(DEB_BUILD_GNU_CPU)" \ + && export DEB_BUILD_GNU_TYPE="$(DEB_BUILD_GNU_TYPE)" \ + && export DEB_BUILD_GNU_SYSTEM="$(DEB_BUILD_GNU_SYSTEM)" \ + && (\ + echo -E 'eval "yada () { perl $$(which yada) \"\$$@\"; }"; set -e; set -v';\ + echo -E 'mkdir -p $$ROOT/usr/bin';\ + echo -E 'mkdir -p $$ROOT/usr/share/openbios';\ + echo -E 'mkdir -p $$ROOT/usr/share/doc/packages/openbios';\ + echo -E 'cp toke/toke $$ROOT/usr/bin';\ + echo -E 'cp detok/detok $$ROOT/usr/bin';\ + echo -E 'cp paflof/paflof $$ROOT/usr/bin';\ + echo -E 'cp -a toke/examples $$ROOT/usr/share/doc/openbios';\ + echo -E 'cp -a forth $$ROOT/usr/share/openbios';\ + echo -E 'cp toke/README $$ROOT/usr/share/doc/openbios/README.toke';\ + echo -E 'cp detok/README $$ROOT/usr/share/doc/openbios/README.detok') | /bin/sh + LD_LIBRARY_PATH="debian/tmp-openbios/lib:debian/tmp-openbios/usr/lib:$$LD_LIBRARY_PATH" dpkg-shlibdeps -pshlibs:openbios -dDepends debian/tmp-openbios/usr/bin/* + $(shell which yada) compress openbios + $(shell which yada) generate maintscripts openbios + find debian/tmp-openbios -type f -print \ + | sed -n 's/^debian\/tmp-openbios\(\/etc\/.*\)$$/\1/p' \ + > debian/tmp-openbios/DEBIAN/conffiles + if test ! -s debian/tmp-openbios/DEBIAN/conffiles; then rm -f debian/tmp-openbios/DEBIAN/conffiles; fi + $(shell which yada) rebuild control + $(shell which yada) generate substvars openbios + umask 022 && dpkg-gencontrol -isp -popenbios -Pdebian/tmp-openbios + +# Build package files + +.PHONY: binary binary-arch binary-indep +binary: binary-arch binary-indep +binary-arch: chmod-yada binary-arch-any + +.PHONY: binary-arch-any +binary-arch-any: \ + binary-package-openbios +binary-indep: chmod-yada + +.PHONY: binary-package-openbios +binary-package-openbios: check-root debian/tmp-openbios/DEBIAN/control + @[ -f $(shell which yada) -a -f debian/rules ] + chown -R 0.0 debian/tmp-openbios + chmod -R u=rwX,go=rX debian/tmp-openbios + @if [ -d debian/tmp-openbios/usr/doc/openbios ]; then \ + echo "*** Yada warning: /usr/doc/openbios should be /usr/share/doc/openbios";\ + fi + dpkg-deb --build debian/tmp-openbios .. + +.PHONY: check-root +check-root: + @[ `id -u` = 0 ] || (echo "You must be root to do this!"; false) + +.PHONY: chmod-yada +chmod-yada: + @if [ -f debian/yada -a ! -x debian/yada ]; then \ + chmod +x debian/yada; \ + fi + +# Clean up afterwards + +.PHONY: clean clean-install-tree clean-build +clean: chmod-yada clean-install-tree clean-build debian/control debian/rules + +clean-build: + @[ -f $(shell which yada) -a -f debian/rules ] + rm -f debian/build-stamp debian/depends-stamp + @umask 022 && (\ + echo -E 'eval "yada () { perl $$(which yada) \"\$$@\"; }"; set -e; set -v';\ + echo -E 'cd toke; make clean; cd ..';\ + echo -E 'cd detok; make clean; cd ..';\ + echo -E 'cd paflof; make clean; cd ..') | /bin/sh + +clean-install-tree: chmod-yada debian/rules + @[ -f $(shell which yada) -a -f debian/rules ] + rm -f debian/install-tree-stamp + rm -rf debian/tmp* debian/files* debian/substvars diff --git a/utils/dist/openbios.spec b/utils/dist/openbios.spec new file mode 100644 index 0000000..fcce7ab --- /dev/null +++ b/utils/dist/openbios.spec @@ -0,0 +1,61 @@ +# +# spec file for package openbios +# + +Name: openbios +Version: 0.1 +Release: 0 +Summary: OpenBIOS development utilities +License: GNU General Public License (GPL) - all versions, Other License(s), see package +Group: Development/Tools/Other +Autoreqprov: on +# Scripts and programs +Source0: OpenBIOS.tar.bz2 +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +This package contains the OpenBIOS development utilities. + +There are +* toke - an IEEE 1275-1994 compliant FCode tokenizer +* detok - an IEEE 1275-1994 compliant FCode detokenizer +* paflof - a forth kernel running in user space +* an fcode bytecode evaluator running in paflof + +See /usr/share/doc/packages/openbios for details and examples. + +Authors: +-------- + Stefan Reinauer + Segher Boessenkool + +%prep +%setup -n openbios + +%build +( cd toke; make; strip toke ) +( cd detok; make; strip detok ) +( cd paflof; make; strip paflof ) +( find toke/examples -name .cvsignore | xargs rm -f ) + +%install +rm -rf ${RPM_BUILD_ROOT} +mkdir -p ${RPM_BUILD_ROOT}/usr/bin/ +mkdir -p ${RPM_BUILD_ROOT}/usr/share/openbios +mkdir -p ${RPM_BUILD_ROOT}/usr/share/doc/packages/openbios +cp toke/toke ${RPM_BUILD_ROOT}/usr/bin/ +cp detok/detok ${RPM_BUILD_ROOT}/usr/bin/ +cp paflof/paflof ${RPM_BUILD_ROOT}/usr/bin/ +cp -a toke/examples ${RPM_BUILD_ROOT}/usr/share/doc/packages/openbios +cp -a forth ${RPM_BUILD_ROOT}/usr/share/openbios +cp toke/README ${RPM_BUILD_ROOT}/usr/share/doc/packages/openbios/README.toke +cp detok/README ${RPM_BUILD_ROOT}/usr/share/doc/packages/openbios/README.detok + +%files +/usr/bin +/usr/share/openbios +%doc /usr/share/doc/packages/openbios + +%changelog -n openbios +* Mon Jul 22 2002 - stepan@suse.de +- initial version diff --git a/utils/fccc/COPYING b/utils/fccc/COPYING new file mode 100644 index 0000000..ca34b30 --- /dev/null +++ b/utils/fccc/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/utils/fccc/include/fccc-tools.h b/utils/fccc/include/fccc-tools.h new file mode 100644 index 0000000..223c2cc --- /dev/null +++ b/utils/fccc/include/fccc-tools.h @@ -0,0 +1,12 @@ +#ifndef FCCCTOOLS_H +#define FCCCTOOLS_H + +void reverse(char *); +void itoa(int number, char *); +void generate_id(const char *, char *); +void error_found(void); /* Function to set the global error flag */ +char *dot_c2dot_f(char *); +FILE *init_output_file(char *); +FILE *init_input_file(char *); + +#endif /* FCCCTOOLS_H */ diff --git a/utils/fccc/include/fccc.h b/utils/fccc/include/fccc.h new file mode 100644 index 0000000..430a0b2 --- /dev/null +++ b/utils/fccc/include/fccc.h @@ -0,0 +1,44 @@ +#ifndef FCCC_H +#define FCCC_H + +#define LEXEM_SIZE 256 + +#include +#include +#include +#include + +/* Debugging macro */ +#ifdef P_DEBUG +#undef P_DEBUG +#define P_DEBUG(P_STR) (P_STR) +#else +#define P_DEBUG(P_STR) +#endif /* P_DEBUG */ + +extern FILE *yyin; + +FILE *forthfile; + +int getlinenum(void); +void error_found(void); + +enum var_types {CHAR_T, SHORT_T, INT_T, LONG_T, VOID_T, ERROR_T}; + +typedef struct { + char lexem[LEXEM_SIZE]; + char unique_id[LEXEM_SIZE]; + int scope_no; + enum var_types type; /* Used for return type and variable type */ +} symbol; + +struct tag_yystype { + char text[LEXEM_SIZE]; + int num; + enum var_types var_type; + symbol* symbol_ref; +}; + +#define YYSTYPE struct tag_yystype + +#endif /* FCCC_H */ diff --git a/utils/fccc/include/linklist.h b/utils/fccc/include/linklist.h new file mode 100644 index 0000000..6822404 --- /dev/null +++ b/utils/fccc/include/linklist.h @@ -0,0 +1,24 @@ +#ifndef LINKLIST_H +#define LINKLIST_H + +#include +#include + +struct tag_list_entry { + void *data; + struct tag_list_entry *next; +}; +typedef struct tag_list_entry list_entry; + +struct tag_linked_list { + list_entry *first; + list_entry *loop; +}; +typedef struct tag_linked_list linked_list; + +linked_list *new_list(void); +void remove_first_elem(linked_list * list); +void new_first_elem(linked_list * list); +void destroy_list(linked_list * list); + +#endif /* LINKLIST_H */ diff --git a/utils/fccc/include/parserfunctions.h b/utils/fccc/include/parserfunctions.h new file mode 100644 index 0000000..3a7e206 --- /dev/null +++ b/utils/fccc/include/parserfunctions.h @@ -0,0 +1,10 @@ +#ifndef PARSERFUNCTIONS_H +#define PARSERFUNCTIONS_H + +#include +#include +#include + +YYSTYPE plain_ass(YYSTYPE, YYSTYPE); + +#endif /* PARSERFUNCTIONS_H */ diff --git a/utils/fccc/include/symboltable.h b/utils/fccc/include/symboltable.h new file mode 100644 index 0000000..6be9cad --- /dev/null +++ b/utils/fccc/include/symboltable.h @@ -0,0 +1,24 @@ +#ifndef SYMBOLTABLE_H +#define SYMBOLTABLE_H + +#include +#include +#include + +linked_list* current_scope; +linked_list* symboltable; +int scope_count; + +void init_symboltable(void); +void destroy_symboltable(void); +symbol* insert(char* lexem_to_insert); +symbol* lookup(char* lexem_to_find); +symbol* lookup_local(char* lexem_to_find); +void new_scope(void); +void exit_scope(void); +void dump(void); + +void dump_symbol(symbol* symbol_to_dump); + + +#endif /* SYMBOLTABLE_H */ diff --git a/utils/fccc/src/Makefile b/utils/fccc/src/Makefile new file mode 100644 index 0000000..cbde7e9 --- /dev/null +++ b/utils/fccc/src/Makefile @@ -0,0 +1,35 @@ +CC = gcc +CCFLAGS = -Wall -O0 -ansi -pedantic -g -c -I../include -I./ +LINK = gcc +LEX = flex +YACC = bison +YACCFLAGS = -d -v +DEBUGFLAGS = -U L_DEBUG -D P_DEBUG + +.phony: all +all: fccc + +.phony: clean +clean: + $(RM) *.o *~ fccc_lex.c fccc_bison.c fccc_bison.output fccc_bison.h \ + fccc core + +OFILES = $(patsubst %.c,%.o,$(wildcard *.c)) + +%.o: %.c + $(CC) $(CCFLAGS) $<; + +fccc: $(OFILES) fccc_bison.o fccc_lex.o + $(LINK) -o fccc $(shell \ls *.o) + +fccc_lex.o: fccc_lex.c + $(CC) $(CCFLAGS) $(DEBUGFLAGS) fccc_lex.c + +fccc_bison.o: fccc_bison.c + $(CC) $(CCFLAGS) $(DEBUGFLAGS) fccc_bison.c + +fccc_lex.c: fccc.lex fccc.y + $(LEX) -ofccc_lex.c fccc.lex + +fccc_bison.c: fccc.y + $(YACC) $(YACCFLAGS) -o fccc_bison.c fccc.y diff --git a/utils/fccc/src/fccc-tools.c b/utils/fccc/src/fccc-tools.c new file mode 100644 index 0000000..e52e5b5 --- /dev/null +++ b/utils/fccc/src/fccc-tools.c @@ -0,0 +1,88 @@ +#include +#include + +int id_taller = 0; + +void reverse(char *s) +{ + char c; + int i, j; + + for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +void itoa(int number, char *dest_str) +{ + int count, sign; + + if ((sign = number) < 0) + number *= -1; + count = 0; + do { + dest_str[count++] = number % 10 + '0'; + } while ((number /= 10) > 0); + if (sign < 0) + dest_str[count++] = '-'; + dest_str[count] = '\0'; + reverse(dest_str); +} + +void generate_id(const char *name, char *dest_str) +{ + char temp_str[LEXEM_SIZE]; + + itoa(id_taller++, dest_str); + reverse(dest_str); + strcat(dest_str, "_"); + strcpy(temp_str, name); + temp_str[LEXEM_SIZE - strlen(dest_str) - 1] = '\0'; + reverse(temp_str); + strcat(dest_str, temp_str); + reverse(dest_str); +} + +void error_found(void) +{ + extern int fccc_error; + + printf("error_found(), line %d\n", getlinenum()); + fccc_error = 1; +} + +char *dot_c2dot_f(char *c_str) +{ + c_str[strlen(c_str) - 2] = '\0'; + strcat(c_str, ".f"); + + return (c_str); +} + +FILE *init_input_file(char *input_filename) +{ + FILE *tempfp; + + tempfp = fopen(input_filename, "r"); + if (!tempfp) { + printf("Cannot open %s - bailing out!\n", input_filename); + exit(1); + } + printf("%s open for input.\n", input_filename); + return (tempfp); +} + +FILE *init_output_file(char *output_filename) +{ + FILE *tempfp; + + tempfp = fopen(output_filename, "w"); + if (!tempfp) { + printf("Cannot open %s - bailing out!\n", output_filename); + exit(1); + } + printf("%s open for output.\n", output_filename); + return (tempfp); +} diff --git a/utils/fccc/src/fccc.lex b/utils/fccc/src/fccc.lex new file mode 100644 index 0000000..00a9261 --- /dev/null +++ b/utils/fccc/src/fccc.lex @@ -0,0 +1,203 @@ +%option noyywrap +/* The linker throws itself on the back if the yywrapper is enabled, + so better disable than use a dummy return(1) function. + */ + +%{ +/* + * IDENTIFIER CONSTANT STRING_LITERAL SIZEOF + * PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP + * AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN + * SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN + * XOR_ASSIGN OR_ASSIGN TYPE_NAME + * + * TYPEDEF EXTERN STATIC AUTO REGISTER + * CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID + * STRUCT UNION ENUM ELLIPSIS + * + * CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN + */ + +#include +#include /* for malloc() */ +#include +#include + +#define YYDEBUG + +#ifdef L_DEBUG +#undef L_DEBUG +#define L_DEBUG(L_STR) (L_STR) +#endif +#ifndef L_DEBUG +#define L_DEBUG(L_STR) +#endif + +int getlinenum(void); +int linenum = 1; + +extern int fileno __P ((FILE *__stream)); /* To remove warnings */ +%} + +/* Regular definitions */ +delim [ \t] +ws {delim}+ +digit [0-9] +letter [a-zA-Z_] +hex [a-fA-F0-9] +id {letter}({letter}|{digit})* + +FS (f|F|l|L) +IS (u|U|l|L)* + +%s COMMENT +%% +"/*"[^"*/"\n]*"*/" { /* no action */ } +"/*"[^"*/"\n]*\n { ++linenum; BEGIN(COMMENT); } +[^"*/"\n]*\n { ++linenum; } +[^"*/"\n]*"*/" { BEGIN(INITIAL); } +{ws} { /* no action */ } +\n { linenum++; } +auto { L_DEBUG(printf("Lex, line %d: AUTO\n", linenum)); + return(AUTO); } +break { L_DEBUG(printf("Lex, line %d: BREAK\n", linenum)); + return(BREAK); } +case { L_DEBUG(printf("Lex, line %d: CASE\n", linenum)); + return(CASE); } +char { L_DEBUG(printf("Lex, line %d: CHAR\n", linenum)); + return(CHAR); } +const { L_DEBUG(printf("Lex, line %d: CONST\n", linenum)); + return(CONST); } +continue { L_DEBUG(printf("Lex, line %d: CONTINUE\n", linenum)); + return(CONTINUE); } +default { L_DEBUG(printf("Lex, line %d: DEFAULT\n", linenum)); + return(DEFAULT); } +do { L_DEBUG(printf("Lex, line %d: DO\n", linenum)); + return(DO); } +double { L_DEBUG(printf("Lex, line %d: DOUBLE\n", linenum)); + return(DOUBLE); } +else { L_DEBUG(printf("Lex, line %d: ELSE\n", linenum)); + return(ELSE); } +enum { L_DEBUG(printf("Lex, line %d: ENUM\n", linenum)); + return(ENUM); } +extern { L_DEBUG(printf("Lex, line %d: EXTERN\n", linenum)); + return(EXTERN); } +float { L_DEBUG(printf("Lex, line %d: FLOAT\n", linenum)); + return(FLOAT); } +for { L_DEBUG(printf("Lex, line %d: FOR\n", linenum)); + return(FOR); } +goto { L_DEBUG(printf("Lex, line %d: GOTO\n", linenum)); + return(GOTO); } +if { L_DEBUG(printf("Lex, line %d: IF\n", linenum)); + return(IF); } +int { L_DEBUG(printf("Lex, line %d: INT\n", linenum)); + yylval.var_type=INT_T; + return(INT); } +long { L_DEBUG(printf("Lex, line %d: LONG\n", linenum)); + return(LONG); } +register { L_DEBUG(printf("Lex, line %d: REGISTER\n", linenum)); + return(REGISTER); } +return { L_DEBUG(printf("Lex, line %d: RETURN\n", linenum)); + return(RETURN); } +short { L_DEBUG(printf("Lex, line %d: SHORT\n", linenum)); + return(SHORT); } +signed { L_DEBUG(printf("Lex, line %d: SIGNED\n", linenum)); + return(SIGNED); } +sizeof { L_DEBUG(printf("Lex, line %d: SIZEOF\n", linenum)); + return(SIZEOF); } +static { L_DEBUG(printf("Lex, line %d: STATIC\n", linenum)); + return(STATIC); } +struct { L_DEBUG(printf("Lex, line %d: STRUCT\n", linenum)); + return(STRUCT); } +switch { L_DEBUG(printf("Lex, line %d: SWITCH\n", linenum)); + return(SWITCH); } +typedef { L_DEBUG(printf("Lex, line %d: TYPEDEF\n", linenum)); + return(TYPEDEF); } +union { L_DEBUG(printf("Lex, line %d: UNION\n", linenum)); + return(UNION); } +unsigned { L_DEBUG(printf("Lex, line %d: UNSIGNED\n", linenum)); + return(UNSIGNED); } +void { L_DEBUG(printf("Lex, line %d: VOID\n", linenum)); + return(VOID); } +volatile { L_DEBUG(printf("Lex, line %d: VOLATILE\n", linenum)); + return(VOLATILE); } +while { L_DEBUG(printf("Lex, line %d: WHILE\n", linenum)); + return(WHILE); } +0[xX]{hex}+{IS}? { L_DEBUG(printf("Lex, line %d: CONSTANT\n", linenum)); + yylval.num=atoi(yytext); + return(CONSTANT); } +0{digit}+{IS}? { L_DEBUG(printf("Lex, line %d: CONSTANT\n", linenum)); + yylval.num=atoi(yytext); + return(CONSTANT); } +{digit}+{IS}? { L_DEBUG(printf("Lex, line %d: CONSTANT\n", linenum)); + yylval.num = atoi(yytext); + return(CONSTANT); } +L?'(\\.|[^\\'])+' { L_DEBUG(printf("Lex, line %d: CONSTANT\n", linenum)); + return(CONSTANT); } +L?\"(\\.|[^\\"])*\" { L_DEBUG(printf("Lex, line %d: STR_LIT\n", linenum)); + strncpy(yylval.text, yytext, LEXEM_SIZE-1); + yylval.text[LEXEM_SIZE-1]='\0'; + return(STRING_LITERAL); } +{id} { L_DEBUG(printf("Lex, line %d: ID\n", linenum)); + strncpy(yylval.text, yytext, LEXEM_SIZE-1); + yylval.text[LEXEM_SIZE-1]='\0'; + return(IDENTIFIER); } + +"..." { L_DEBUG(printf("Lex, line %d: ELLIPSIS\n", linenum)); + return(ELLIPSIS); } +">>=" { return(RIGHT_ASSIGN); } +"<<=" { return(LEFT_ASSIGN); } +"+=" { return(ADD_ASSIGN); } +"-=" { return(SUB_ASSIGN); } +"*=" { return(MUL_ASSIGN); } +"/=" { return(DIV_ASSIGN); } +"%=" { return(MOD_ASSIGN); } +"&=" { return(AND_ASSIGN); } +"^=" { return(XOR_ASSIGN); } +"|=" { return(OR_ASSIGN); } +">>" { return(RIGHT_OP); } +"<<" { return(LEFT_OP); } +"++" { return(INC_OP); } +"--" { return(DEC_OP); } +"->" { return(PTR_OP); } +"&&" { return(AND_OP); } +"||" { return(OR_OP); } +"<=" { return(LE_OP); } +">=" { return(GE_OP); } +"==" { return(EQ_OP); } +"!=" { return(NE_OP); } +";" { return(';'); } +("{"|"<%") { return('{'); } +("}"|"%>") { return('}'); } +"," { return(','); } +":" { return(':'); } +"=" { return('='); } +"(" { return('('); } +")" { return(')'); } +("["|"<:") { return('['); } +("]"|":>") { return(']'); } +"." { return('.'); } +"&" { return('&'); } +"!" { return('!'); } +"~" { return('~'); } +"-" { return('-'); } +"+" { return('+'); } +"*" { return('*'); } +"/" { return('/'); } +"%" { return('%'); } +"<" { return('<'); } +">" { return('>'); } +"^" { return('^'); } +"|" { return('|'); } +"?" { return('?'); } + +%% + +int getlinenum(void) { + return linenum; +} + +void suppress_flex_bug_warning(void) { + if (0) unput('\n'); +} + diff --git a/utils/fccc/src/fccc.y b/utils/fccc/src/fccc.y new file mode 100644 index 0000000..323d193 --- /dev/null +++ b/utils/fccc/src/fccc.y @@ -0,0 +1,562 @@ +%{ + +int yylex(void); /* Implemented by flex. */ + +#include +#include + +int fccc_error=0; + +int yyerror(char *); +#define YYERROR_VERBOSE + +%} + +%expect 1 /* We know about the if-then-else shift-/reduceconflict */ + +%token IDENTIFIER CONSTANT STRING_LITERAL SIZEOF +%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN +%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN +%token XOR_ASSIGN OR_ASSIGN TYPE_NAME + +%token TYPEDEF EXTERN STATIC AUTO REGISTER +%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID +%token STRUCT UNION ENUM ELLIPSIS + +%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN + +%start translation_unit +%% + +primary_expression + : IDENTIFIER + { P_DEBUG(printf("P, line %d: found identifier \"%s\"\n", getlinenum(),$$.text)); } + | CONSTANT + { P_DEBUG(printf("P, line %d: found constant %d\n", getlinenum(),$$.num)); } + | STRING_LITERAL + { P_DEBUG(printf("P, line %d: found string literal \"%s\"\n", getlinenum(),$$.text)); } + | '(' expression ')' + { P_DEBUG(printf("P, line %d: found expression.\n", getlinenum())); } + ; + +postfix_expression + : primary_expression + { P_DEBUG(printf("P, line %d: found primary expression\n", getlinenum())); } + | postfix_expression '[' expression ']' + { P_DEBUG(printf("P, line %d: found array\n", getlinenum())); } + | postfix_expression '(' ')' + { P_DEBUG(printf("P, line %d: found void function\n", getlinenum())); } + | postfix_expression '(' argument_expression_list ')' + { P_DEBUG(printf("P, line %d: found function\n", getlinenum())); } + | postfix_expression '.' IDENTIFIER + { P_DEBUG(printf("P, line %d: found struct member access\n", getlinenum())); } + | postfix_expression PTR_OP IDENTIFIER + { P_DEBUG(printf("P, line %d: found pointer operator\n", getlinenum())); } + | postfix_expression INC_OP + { P_DEBUG(printf("P, line %d: found increase\n", getlinenum())); } + | postfix_expression DEC_OP + { P_DEBUG(printf("P, line %d: found decrease\n", getlinenum())); } + ; + +argument_expression_list + : assignment_expression + { P_DEBUG(printf("P, line %d: found an assignment\n", getlinenum())); } + | argument_expression_list ',' assignment_expression + { P_DEBUG(printf("P, line %d: found an additional assignment\n", getlinenum())); } + ; + +unary_expression + : postfix_expression + { P_DEBUG(printf("P, line %d: found a postfix expression\n", getlinenum())); } + | INC_OP unary_expression + { P_DEBUG(printf("P, line %d: found preinc on unary exp\n", getlinenum())); } + | DEC_OP unary_expression + { P_DEBUG(printf("P, line %d: found predec on unary exp\n", getlinenum())); } + | unary_operator cast_expression + { P_DEBUG(printf("P, line %d: found unary operation on cast exp\n", getlinenum())); } + | SIZEOF unary_expression + { P_DEBUG(printf("P, line %d: found sizeof(unary expr)\n", getlinenum())); } + | SIZEOF '(' type_name ')' + { P_DEBUG(printf("P, line %d: found sizeof(type)\n", getlinenum())); } + ; + +unary_operator + : '&' + { P_DEBUG(printf("P, line %d: found address operator\n", getlinenum())); } + | '*' + { P_DEBUG(printf("P, line %d: found pointer operator\n", getlinenum())); } + | '+' + { P_DEBUG(printf("P, line %d: found positive operator\n", getlinenum())); } + | '-' + { P_DEBUG(printf("P, line %d: found negative operator\n", getlinenum())); } + | '~' + { P_DEBUG(printf("P, line %d: found binary not\n", getlinenum())); } + | '!' + { P_DEBUG(printf("P, line %d: found boolean not\n", getlinenum())); } + ; + +cast_expression + : unary_expression + | '(' type_name ')' cast_expression + ; + +multiplicative_expression + : cast_expression + | multiplicative_expression '*' cast_expression + | multiplicative_expression '/' cast_expression + | multiplicative_expression '%' cast_expression + ; + +additive_expression + : multiplicative_expression + | additive_expression '+' multiplicative_expression + | additive_expression '-' multiplicative_expression + ; + +shift_expression + : additive_expression + | shift_expression LEFT_OP additive_expression + | shift_expression RIGHT_OP additive_expression + ; + +relational_expression + : shift_expression + | relational_expression '<' shift_expression + | relational_expression '>' shift_expression + | relational_expression LE_OP shift_expression + | relational_expression GE_OP shift_expression + ; + +equality_expression + : relational_expression + | equality_expression EQ_OP relational_expression + | equality_expression NE_OP relational_expression + ; + +and_expression + : equality_expression + | and_expression '&' equality_expression + ; + +exclusive_or_expression + : and_expression + | exclusive_or_expression '^' and_expression + ; + +inclusive_or_expression + : exclusive_or_expression + | inclusive_or_expression '|' exclusive_or_expression + ; + +logical_and_expression + : inclusive_or_expression + | logical_and_expression AND_OP inclusive_or_expression + ; + +logical_or_expression + : logical_and_expression + | logical_or_expression OR_OP logical_and_expression + ; + +conditional_expression + : logical_or_expression + | logical_or_expression '?' expression ':' conditional_expression + ; + +assignment_expression + : conditional_expression + { P_DEBUG(printf("P, line %d: assignment_expression ends with conditional_exp\n", getlinenum()));} + | unary_expression assignment_operator assignment_expression + { P_DEBUG(printf("P, line %d: Found further assignment_expression\n", getlinenum())); } + ; + +assignment_operator + : '=' + { P_DEBUG(printf("P, line %d: found = assignment\n", getlinenum())); } + | MUL_ASSIGN + { P_DEBUG(printf("P, line %d: found *= assignment\n", getlinenum())); } + | DIV_ASSIGN + { P_DEBUG(printf("P, line %d: found /= assignment\n", getlinenum())); } + | MOD_ASSIGN + { P_DEBUG(printf("P, line %d: found \\= assignment\n", getlinenum())); } + | ADD_ASSIGN + { P_DEBUG(printf("P, line %d: found += assignment\n", getlinenum())); } + | SUB_ASSIGN + { P_DEBUG(printf("P, line %d: found -= assignment\n", getlinenum())); } + | LEFT_ASSIGN + { P_DEBUG(printf("P, line %d: found >>= assignment\n", getlinenum())); } + | RIGHT_ASSIGN + { P_DEBUG(printf("P, line %d: found <<= assignment\n", getlinenum())); } + | AND_ASSIGN + { P_DEBUG(printf("P, line %d: found &= assignment\n", getlinenum())); } + | XOR_ASSIGN + { P_DEBUG(printf("P, line %d: found ^= assignment\n", getlinenum())); } + | OR_ASSIGN + { P_DEBUG(printf("P, line %d: found |= assignment\n", getlinenum())); } + ; + +expression + : assignment_expression + { P_DEBUG(printf("P, line %d: found assignment exp\n", getlinenum())); } + | expression ',' assignment_expression + { P_DEBUG(printf("P, line %d: found additional assignment exp\n", getlinenum())); } + ; + +constant_expression + : conditional_expression + { P_DEBUG(printf("P, line %d: found conditional exp\n", getlinenum())); } + ; + +declaration + : declaration_specifiers ';' + { P_DEBUG(printf("P, line %d: found uninitialized declaration\n", getlinenum())); } + | declaration_specifiers init_declarator_list ';' + { P_DEBUG(printf("P, line %d: found initialized declaration\n", getlinenum())); } + ; + +declaration_specifiers + : storage_class_specifier + { P_DEBUG(printf("P, line %d: found storage class spec\n", getlinenum())); } + | storage_class_specifier declaration_specifiers + | type_specifier + { P_DEBUG(printf("P, line %d: found type spec\n", getlinenum())); } + | type_specifier declaration_specifiers + | type_qualifier + | type_qualifier declaration_specifiers + ; + +init_declarator_list + : init_declarator + { P_DEBUG(printf("P, line %d: found init declarator\n", getlinenum())); } + | init_declarator_list ',' init_declarator + { P_DEBUG(printf("P, line %d: found additional init declarator\n", getlinenum())); } + ; + +init_declarator + : declarator + | declarator '=' initializer + ; + +storage_class_specifier + : TYPEDEF + | EXTERN + | STATIC + | AUTO + | REGISTER + ; + +type_specifier + : VOID + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | SIGNED + | UNSIGNED + | struct_or_union_specifier + | enum_specifier + | TYPE_NAME + ; + +struct_or_union_specifier + : struct_or_union IDENTIFIER '{' struct_declaration_list '}' + | struct_or_union '{' struct_declaration_list '}' + | struct_or_union IDENTIFIER + ; + +struct_or_union + : STRUCT + | UNION + ; + +struct_declaration_list + : struct_declaration + | struct_declaration_list struct_declaration + ; + +struct_declaration + : specifier_qualifier_list struct_declarator_list ';' + ; + +specifier_qualifier_list + : type_specifier specifier_qualifier_list + | type_specifier + | type_qualifier specifier_qualifier_list + | type_qualifier + ; + +struct_declarator_list + : struct_declarator + | struct_declarator_list ',' struct_declarator + ; + +struct_declarator + : declarator + | ':' constant_expression + | declarator ':' constant_expression + ; + +enum_specifier + : ENUM '{' enumerator_list '}' + | ENUM IDENTIFIER '{' enumerator_list '}' + | ENUM IDENTIFIER + ; + +enumerator_list + : enumerator + | enumerator_list ',' enumerator + ; + +enumerator + : IDENTIFIER + | IDENTIFIER '=' constant_expression + ; + +type_qualifier + : CONST + | VOLATILE + ; + +declarator + : pointer direct_declarator + | direct_declarator + ; + +direct_declarator + : IDENTIFIER + { P_DEBUG(printf("P, line %d: declaring identifier \"%s\".\n", getlinenum(),$$.text)); + $$.symbol_ref=insert($$.text); + } + | '(' declarator ')' + { P_DEBUG(printf("P, line %d: found declarator decl.\n", getlinenum())); } + | direct_declarator '[' constant_expression ']' + | direct_declarator '[' ']' + | direct_declarator '(' + { printf ("P, line %d: los! fct parameter\n", getlinenum());} parameter_type_list ')' + { P_DEBUG(printf("P, line %d: found function param list for fct %s.\n", getlinenum(),$1.text)); + } + + | direct_declarator '(' identifier_list ')' + { P_DEBUG(printf("P, line %d: found identifier list decl.\n", getlinenum())); } + | direct_declarator '(' ')' + ; + +pointer + : '*' + | '*' type_qualifier_list + | '*' pointer + | '*' type_qualifier_list pointer + ; + +type_qualifier_list + : type_qualifier + | type_qualifier_list type_qualifier + ; + + +parameter_type_list + : parameter_list + | parameter_list ',' ELLIPSIS + ; + +parameter_list + : parameter_declaration + | parameter_list ',' parameter_declaration + ; + +parameter_declaration + : declaration_specifiers declarator + { P_DEBUG(printf("P, line %d: found normal param decl.\n", getlinenum())); } + | declaration_specifiers abstract_declarator + { P_DEBUG(printf("P, line %d: found abstr. param decl.\n", getlinenum())); } + | declaration_specifiers + { P_DEBUG(printf("P, line %d: found simple decl.\n", getlinenum())); } + ; + +identifier_list + : IDENTIFIER + | identifier_list ',' IDENTIFIER + ; + +type_name + : specifier_qualifier_list + | specifier_qualifier_list abstract_declarator + ; + +abstract_declarator + : pointer + | direct_abstract_declarator + { P_DEBUG(printf("P, line %d: found direct abstr decl.\n", getlinenum())); } + | pointer direct_abstract_declarator + ; + +direct_abstract_declarator + : '(' abstract_declarator ')' + | '[' ']' + | '[' constant_expression ']' + | direct_abstract_declarator '[' ']' + | direct_abstract_declarator '[' constant_expression ']' + | '(' ')' + | '(' parameter_type_list ')' + | direct_abstract_declarator '(' ')' + | direct_abstract_declarator '(' parameter_type_list ')' + ; + +initializer + : assignment_expression + { P_DEBUG(printf("P, line %d: found assignment init.\n", getlinenum())); } + | '{' initializer_list '}' + { P_DEBUG(printf("P, line %d: found initializer list.\n", getlinenum())); } + | '{' initializer_list ',' '}' + { P_DEBUG(printf("P, line %d: found open initializer list.\n", getlinenum())); } + ; + +initializer_list + : initializer + | initializer_list ',' initializer + ; + +statement + : labeled_statement + | compound_statement + { P_DEBUG(printf("P, line %d: found compound stat.\n", getlinenum())); } + | expression_statement + | selection_statement + | iteration_statement + | jump_statement + ; + +labeled_statement + : IDENTIFIER ':' statement + | CASE constant_expression ':' statement + | DEFAULT ':' statement + ; + +compound_statement + : '{' '}' + { P_DEBUG(printf("P, line %d: found empty compound.\n", getlinenum())); } + | '{' statement_list '}' + { P_DEBUG(printf("P, line %d: found sub program.\n", getlinenum())); } + | '{' declaration_list '}' + { P_DEBUG(printf("P, line %d: found decl. compound\n", getlinenum())); } + | '{' declaration_list statement_list '}' + { P_DEBUG(printf("P, line %d: found sub program w/ decl.\n", getlinenum())); } + ; + +declaration_list + : declaration + | declaration_list declaration + ; + +statement_list + : statement + | statement_list statement + ; + +expression_statement + : ';' + | expression ';' + ; + +selection_statement + : IF '(' expression ')' statement + { P_DEBUG(printf("P, line %d: Got an if-statement.\n", getlinenum())); } + | IF '(' expression ')' statement ELSE statement + { P_DEBUG(printf("P, line %d: Got an if-else-statement.\n", getlinenum())); } + | SWITCH '(' expression ')' statement + { P_DEBUG(printf("P, line %d: Got a switch-statement.\n", getlinenum())); } + ; + +iteration_statement + : WHILE '(' expression ')' statement + | DO statement WHILE '(' expression ')' ';' + | FOR '(' expression_statement expression_statement ')' statement + | FOR '(' expression_statement expression_statement expression ')' statement + ; + +jump_statement + : GOTO IDENTIFIER ';' + | CONTINUE ';' + | BREAK ';' + | RETURN ';' + | RETURN expression ';' + ; + +translation_unit + : external_declaration + | translation_unit external_declaration + ; + +external_declaration + : function_definition + | declaration + ; + +function_definition + : declaration_specifiers declarator {new_scope();} declaration_list compound_statement + { exit_scope(); P_DEBUG(printf("P, line %d: found function definition w/ decl list\n", getlinenum())); } + | declaration_specifiers declarator compound_statement + { P_DEBUG(printf("P, line %d: found function definition\n", getlinenum())); } + | declarator declaration_list compound_statement + { P_DEBUG(printf("P, line %d: found function definition w/ decl list w/o spec\n", getlinenum())); } + | declarator compound_statement + { P_DEBUG(printf("P, line %d: found function definition w/o spec\n", getlinenum())); } + ; + +%% +#include +#include +#include + +#if 0 +extern char yytext[]; +extern int column; +#endif + +int yyerror (char *s) { + printf("\033[37;31;1mParser: line %d: %s\033[0m\n", getlinenum(),s); + error_found(); + return 1; +} + +int main(int argc, char **argv) +{ + FILE* infile; + char outfilename[LEXEM_SIZE]; + + printf("fccc 0.0.1b October 13th 2001\n"); + if( argc==1 || argc>2) { + printf("Usage: fccc \n"); + exit(1); + } + yyin = init_input_file(argv[1]); + dot_c2dot_f(strncpy(outfilename, argv[1], LEXEM_SIZE)); + forthfile = init_output_file(outfilename); + + fccc_error = 0; /* No errors when we start */ + + init_symboltable(); /* Initialize symbol table */ + + yyparse(); /* Start the whole thing */ + + dump(); /* dump symbol table */ + + if(close((int)infile)) + printf("%s closed.\n", argv[1]); + else + printf("Cannot close %s!\n", argv[1]); + if(close((int)forthfile)) + printf("%s closed.\n", outfilename); + else + printf("Cannot close %s!\n", outfilename); + + if(fccc_error) { + unlink(outfilename); + printf("There where error's - %s deleted.\n", outfilename); + } + + return(0); +} diff --git a/utils/fccc/src/linklist.c b/utils/fccc/src/linklist.c new file mode 100644 index 0000000..04fb0bb --- /dev/null +++ b/utils/fccc/src/linklist.c @@ -0,0 +1,45 @@ +#include + +linked_list *new_list() +{ + linked_list *ll = (linked_list *) malloc(sizeof(linked_list)); + + ll->first = 0; + ll->loop = 0; + return ll; +} + +void new_first_elem(linked_list * list) +{ + list_entry *ne = (list_entry *) malloc(sizeof(list_entry)); + + ne->data = 0; + ne->next = list->first; + list->first = ne; +} + +void remove_first_elem(linked_list * list) +{ + list_entry *del = list->first; + + if (del != 0) { + if (del->data != 0) + free(del->data); + list->first = del->next; + free(del); + } +} + +void destroy_list(linked_list * list) +{ + list_entry *del; + + while (list->first != 0) { + del = list->first; + list->first = del->next; + if (del->data != 0) + free(del->data); + free(del); + } + free(list); +} diff --git a/utils/fccc/src/plain_ass.c b/utils/fccc/src/plain_ass.c new file mode 100644 index 0000000..3c3332c --- /dev/null +++ b/utils/fccc/src/plain_ass.c @@ -0,0 +1,41 @@ +/* plain_ass.c -- mmj@mmj.dk. + * Code to handle Plain Assignments */ + +#include + +YYSTYPE plain_ass(YYSTYPE _ID, YYSTYPE expr) +{ + symbol *tmpsym; + YYSTYPE retval; + + /* First check for errors, return if any. + * FIXME: not complete yet, 10202001 mmj */ + + if(expr.var_type == ERROR_T) { + retval.var_type=ERROR_T; + return(retval); + } + tmpsym=lookup(_ID.text); + if(!tmpsym) { + printf("Parser, %d: '%s' undefined\n", getlinenum(), _ID.text ); + retval.var_type = ERROR_T; + error_found(); + return(retval); + } + _ID.symbol_ref = tmpsym; + if(tmpsym->type != expr.var_type && tmpsym->type != ERROR_T) { + printf("Parser, %d: Wrong type for assignment.", getlinenum()); + retval.var_type = ERROR_T; + error_found(); + return(retval); + } + + /* Should not get here unless valid code */ + + P_DEBUG(printf("Parser, %d: Assignment found\n", getlinenum())); + retval.num=expr.num; + P_DEBUG(printf("Parser, %d: %s = %d\n", getlinenum(), + retval.text, retval.num)); + + return(retval); +} diff --git a/utils/fccc/src/symboltable.c b/utils/fccc/src/symboltable.c new file mode 100644 index 0000000..bd30947 --- /dev/null +++ b/utils/fccc/src/symboltable.c @@ -0,0 +1,105 @@ +#include + +void init_symboltable(void) +{ + scope_count = -1; + symboltable = new_list(); + new_scope(); +} + +void destroy_symboltable(void) +{ + destroy_list(symboltable); +} + +symbol *insert(char *lexem_to_insert) +{ + symbol *new_symbol; + + new_symbol = (symbol *) malloc(sizeof(symbol)); + strcpy(new_symbol->lexem, lexem_to_insert); + generate_id(lexem_to_insert, new_symbol->unique_id); + new_symbol->scope_no = scope_count; + new_first_elem(current_scope); + current_scope->first->data = (void *) new_symbol; + return new_symbol; +} + +symbol *lookup(char *lexem_to_find) +{ + linked_list *current_scope_save; + symbol *temp_symbol; + + symboltable->loop = symboltable->first; + current_scope_save = current_scope; + while (current_scope != 0) { + if ((temp_symbol = lookup_local(lexem_to_find)) != 0) { + current_scope = current_scope_save; + return temp_symbol; + } + if (symboltable->loop->next == 0) + current_scope = 0; + else { + symboltable->loop = symboltable->loop->next; + current_scope = + (linked_list *) (symboltable->loop->data); + } + } + current_scope = current_scope_save; + return 0; +} + +symbol *lookup_local(char *lexem_to_find) +{ + current_scope->loop = current_scope->first; + while (current_scope->loop != 0) { + if (!strcmp + ((char *) ((symbol *) (current_scope->loop->data))-> + lexem, lexem_to_find)) + return (symbol *) current_scope->loop->data; + current_scope->loop = current_scope->loop->next; + } + return 0; +} + +void new_scope(void) +{ + linked_list *temp_scope; + + temp_scope = new_list(); + new_first_elem(symboltable); + ++scope_count; + symboltable->first->data = (void *) temp_scope; + current_scope = temp_scope; +} + +void exit_scope(void) +{ + remove_first_elem(symboltable); + --scope_count; + current_scope = (linked_list *) symboltable->first->data; +} + +void dump_symbol(symbol * symbol_to_dump) +{ + printf("Lexem : %s\n", symbol_to_dump->lexem); + printf(" Unique ID : %s\n", symbol_to_dump->unique_id); + printf(" Scope number : %d\n", symbol_to_dump->scope_no); +} + +void dump(void) +{ + linked_list *temp_scope; + + printf("Dumping... ==========> \n"); + symboltable->loop = symboltable->first; + while (symboltable->loop != 0) { + temp_scope = (linked_list *) symboltable->loop->data; + temp_scope->loop = temp_scope->first; + while (temp_scope->loop != 0) { + dump_symbol((symbol *) temp_scope->loop->data); + temp_scope->loop = temp_scope->loop->next; + } + symboltable->loop = symboltable->loop->next; + } +} diff --git a/utils/fccc/test/test1.c b/utils/fccc/test/test1.c new file mode 100644 index 0000000..018c039 --- /dev/null +++ b/utils/fccc/test/test1.c @@ -0,0 +1,14 @@ +int main(int argc, char *argv[] ) +{ + int a = 1; + int b; + if (6) { + 12; + a=5; + } else { + a=7; + 6==8; + b=1; + } + return 0; +} diff --git a/utils/ofclient/Makefile b/utils/ofclient/Makefile new file mode 100644 index 0000000..f3c5159 --- /dev/null +++ b/utils/ofclient/Makefile @@ -0,0 +1,14 @@ +PROGRAM := ofclient +OBJECTS := of1275.o of1275_io.o ofclient.o +CC := gcc +CFLAGS := -m32 -fpic -fno-builtin-strlen -Os +LDFLAGS := -melf_i386 -s -N -Ttext 0x200000 -e _start + +$(PROGRAM): $(OBJECTS) + $(LD) $(LDFLAGS) -Map $(PROGRAM).map -o $(PROGRAM) $(OBJECTS) + +clean: + rm -f $(OBJECTS) + +distclean: clean + rm -f $(PROGRAM) $(PROGRAM).map diff --git a/utils/ofclient/README b/utils/ofclient/README new file mode 100644 index 0000000..785f6ec --- /dev/null +++ b/utils/ofclient/README @@ -0,0 +1,4 @@ +This is an example program using the openfirmware client +interface on x86. The same program can be compiled on ppc. + + diff --git a/utils/ofclient/endian.h b/utils/ofclient/endian.h new file mode 100644 index 0000000..4d20e71 --- /dev/null +++ b/utils/ofclient/endian.h @@ -0,0 +1,18 @@ + +#define __bswap32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +static int little_endian(void) +{ + static short one=1; + return *(char *)&one==1; +} + +static unsigned int ntohl(unsigned int netlong) +{ + if(little_endian()) + return __bswap32(netlong); + + return netlong; +} diff --git a/utils/ofclient/of1275.c b/utils/ofclient/of1275.c new file mode 100644 index 0000000..ff07782 --- /dev/null +++ b/utils/ofclient/of1275.c @@ -0,0 +1,451 @@ + +#include "of1275.h" +#include "endian.h" +static int (*of1275_server) (void *) = (int (*)(void *)) -1; + +_start(void *residual_data_structure, + void *program_entry_point, + int (*client_interface_handler) (void *), void *args, int argslen) +{ + int status; + of1275_server = client_interface_handler; + status = main(); + of1275_exit(status); +} + +/* 6.3.2.1 Client interface */ + + +int of1275_test(const char *name, int *missing) +{ + int result; + static of1275_test_service s; + s.service = "test"; + s.n_args = 1; + s.n_returns = 1; + s.name = name; + result = of1275_server(&s); + *missing = s.missing; + return result; +} + + +/* 6.3.2.2 Device tree */ + + +int of1275_peer(int phandle, int *sibling_phandle) +{ + int result; + static of1275_peer_service s; + s.service = "peer"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of1275_server(&s); + *sibling_phandle = s.sibling_phandle; + return result; +} + +int of1275_child(int phandle, int *child_phandle) +{ + int result; + static of1275_child_service s; + s.service = "child"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of1275_server(&s); + *child_phandle = s.child_phandle; + return result; +} + +int of1275_parent(int phandle, int *parent_phandle) +{ + int result; + static of1275_parent_service s; + s.service = "parent"; + s.n_args = 1; + s.n_returns = 1; + s.phandle = phandle; + result = of1275_server(&s); + *parent_phandle = s.parent_phandle; + return result; +} + +int of1275_instance_to_package(int ihandle, int *phandle) +{ + int result; + static of1275_instance_to_package_service s; + s.service = "instance-to-package"; + s.n_args = 1; + s.n_returns = 1; + s.ihandle = ihandle; + result = of1275_server(&s); + *phandle = s.phandle; + return result; +} + +int of1275_getproplen(int phandle, const char *name, int *proplen) +{ + int result; + static of1275_getproplen_service s; + s.service = "getproplen"; + s.n_args = 2; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + result = of1275_server(&s); + *proplen = s.proplen; + return result; +} + +int +of1275_getprop(int phandle, const char *name, void *buf, int buflen, + int *size) +{ + int result; + static of1275_getprop_service s; + s.service = "getprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.buflen = buflen; + result = of1275_server(&s); + *size = s.size; + return result; +} + +int +of1275_nextprop(int phandle, const char *previous, void *buf, int *flag) +{ + int result; + static of1275_nextprop_service s; + s.service = "nextprop"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.previous = previous; + s.buf = buf; + result = of1275_server(&s); + *flag = s.flag; + return result; +} + +int +of1275_setprop(int phandle, const char *name, void *buf, int len, + int *size) +{ + int result; + static of1275_setprop_service s; + s.service = "setprop"; + s.n_args = 4; + s.n_returns = 1; + s.phandle = phandle; + s.name = name; + s.buf = buf; + s.len = len; + result = of1275_server(&s); + *size = s.size; + return result; +} + +int +of1275_canon(const char *device_specifier, void *buf, int buflen, + int *length) +{ + int result; + static of1275_canon_service s; + s.service = "canon"; + s.n_args = 3; + s.n_returns = 1; + s.device_specifier = device_specifier; + s.buf = buf; + s.buflen = buflen; + result = of1275_server(&s); + *length = s.length; + return result; +} + +int of1275_finddevice(const char *device_specifier, int *phandle) +{ + int result; + static of1275_finddevice_service s; + s.service = "finddevice"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of1275_server(&s); + *phandle = s.phandle; + return result; +} + +int +of1275_instance_to_path(int ihandle, void *buf, int buflen, int *length) +{ + int result; + static of1275_instance_to_path_service s; + s.service = "instance-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.buf = buf; + s.buflen = buflen; + result = of1275_server(&s); + *length = s.length; + return result; +} + +int of1275_package_to_path(int phandle, void *buf, int buflen, int *length) +{ + int result; + static of1275_package_to_path_service s; + s.service = "package-to-path"; + s.n_args = 3; + s.n_returns = 1; + s.phandle = phandle; + s.buf = buf; + s.buflen = buflen; + result = of1275_server(&s); + *length = s.length; + return result; +} + +/* int of1275_call_method(const char *method, int ihandle, ...); */ + + +/* 6.3.2.3 Device I/O */ + + +int of1275_open(const char *device_specifier, int *ihandle) +{ + int result; + static of1275_open_service s; + s.service = "open"; + s.n_args = 1; + s.n_returns = 1; + s.device_specifier = device_specifier; + result = of1275_server(&s); + *ihandle = s.ihandle; + return result; +} + +int of1275_close(int ihandle) +{ + int result; + static of1275_close_service s; + s.service = "close"; + s.n_args = 1; + s.n_returns = 0; + s.ihandle = ihandle; + result = of1275_server(&s); + return result; +} + +int of1275_read(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of1275_read_service s; + s.service = "read"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of1275_server(&s); + *actual = s.actual; + return result; +} + +int of1275_write(int ihandle, void *addr, int len, int *actual) +{ + int result; + static of1275_write_service s; + s.service = "write"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.addr = addr; + s.len = len; + result = of1275_server(&s); + *actual = s.actual; + return result; +} + +int of1275_seek(int ihandle, int pos_hi, int pos_lo, int *status) +{ + int result; + static of1275_seek_service s; + s.service = "seek"; + s.n_args = 3; + s.n_returns = 1; + s.ihandle = ihandle; + s.pos_hi = pos_hi; + s.pos_lo = pos_lo; + result = of1275_server(&s); + *status = s.status; + return result; +} + + +/* 6.3.2.4 Memory */ + + +int of1275_claim(void *virt, int size, int align, void **baseaddr) +{ + int result; + static of1275_claim_service s; + s.service = "claim"; + s.n_args = 3; + s.n_returns = 1; + s.virt = virt; + s.size = size; + s.align = align; + result = of1275_server(&s); + *baseaddr = s.baseaddr; + return result; +} + +int of1275_release(void *virt, int size) +{ + int result; + static of1275_release_service s; + s.service = "release"; + s.n_args = 2; + s.n_returns = 0; + s.virt = virt; + s.size = size; + result = of1275_server(&s); + return result; +} + + +/* 6.3.2.5 Control transfer */ + + +int of1275_boot(const char *bootspec) +{ + int result; + static of1275_boot_service s; + s.service = "boot"; + s.n_args = 1; + s.n_returns = 0; + s.bootspec = bootspec; + result = of1275_server(&s); + return result; +} + +int of1275_enter(void) +{ + int result; + static of1275_enter_service s; + s.service = "enter"; + s.n_args = 0; + s.n_returns = 0; + result = of1275_server(&s); + return result; +} + +int of1275_exit(int status) +{ + int result; + static of1275_exit_service s; + s.service = "exit"; + s.n_args = 1; + s.n_returns = 0; + s.status = status; + result = of1275_server(&s); + return result; +} + +/* int of1275_chain(void *virt, int size, void *entry, void *args, int len); */ + + +/* 6.3.2.6 User interface */ + + +/* int of1275_interpret(const char *arg, ...); */ + +int of1275_set_callback(void *newfunc, void **oldfunc) +{ + int result; + static of1275_set_callback_service s; + s.service = "set-callback"; + s.n_args = 1; + s.n_returns = 1; + s.newfunc = newfunc; + result = of1275_server(&s); + *oldfunc = s.oldfunc; + return result; +} + +int of1275_set_symbol_lookup(void *sym_to_value, void *value_to_sym) +{ + int result; + static of1275_set_symbol_lookup_service s; + s.service = "set-symbol-lookup"; + s.n_args = 2; + s.n_returns = 0; + s.sym_to_value = sym_to_value; + s.value_to_sym = s.value_to_sym; + result = of1275_server(&s); + return result; +} + + +/* 6.3.2.7 Time */ + +int of1275_milliseconds(int *ms) +{ + int result; + static of1275_milliseconds_service s; + s.service = "milliseconds"; + s.n_args = 0; + s.n_returns = 1; + result = of1275_server(&s); + *ms = s.ms; + return result; +} + + +int of_find_integer_property(const char *device, const char *property) +{ + int phandle; + int integer; + int size; + /* find the device's phandle */ + if (of1275_finddevice(device, &phandle) < 0) { + //printk("of1275: no such device '%s'\n", device); + exit(1); + } + /* find the device's property */ + of1275_getprop(phandle, property, &integer, + sizeof(integer), &size); + if (size < sizeof(integer)) { + //printk("of1275: unknown integer property '%s'\n", property); + exit(1); + } + return ntohl(integer); +} + +void +of_find_string_property(const char *device, + const char *property, + char *string, int sizeof_string) +{ + int phandle; + int size; + /* find the device's phandle */ + if (of1275_finddevice(device, &phandle) < 0) { + //printk("of1275: no such device '%s'\n", device); + exit(1); + } + + /* find the device's property */ + of1275_getprop(phandle, property, string, sizeof_string, &size); + if (size == 0 || size >= sizeof_string) { + //printk("of1275: unknown string property '%s'\n", property); + exit(1); + } +} diff --git a/utils/ofclient/of1275.h b/utils/ofclient/of1275.h new file mode 100644 index 0000000..a73bb19 --- /dev/null +++ b/utils/ofclient/of1275.h @@ -0,0 +1,437 @@ +/* OpenFirmware interface */ + + +/* 6.3.2.1 Client interface */ + + +typedef struct _of1275_test_service { + const char *service; + int n_args; + int n_returns; + /*in */ + const char *name; + /*out */ + int missing; +} of1275_test_service; + +int of1275_test(const char *name, int *missing); + + +/* 6.3.2.2 Device tree */ + + +typedef struct _of1275_peer_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + /*out */ + int sibling_phandle; +} of1275_peer_service; + +int of1275_peer(int phandle, int *sibling_phandle); + + +typedef struct _of1275_child_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + /*out */ + int child_phandle; +} of1275_child_service; + +int of1275_child(int phandle, int *child_phandle); + + +typedef struct _of1275_parent_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + /*out */ + int parent_phandle; +} of1275_parent_service; + +int of1275_child(int phandle, int *parent_phandle); + + +typedef struct _of1275_instance_to_package_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int ihandle; + /*out */ + int phandle; +} of1275_instance_to_package_service; + +int of1275_instance_to_package(int ihandle, int *phandle); + + +typedef struct _of1275_getproplen_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + const char *name; + /*out */ + int proplen; +} of1275_getproplen_service; + +int of1275_getproplen(int phandle, const char *name, int *proplen); + + +typedef struct _of1275_getprop_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + const char *name; + void *buf; + int buflen; + /*out */ + int size; +} of1275_getprop_service; + +int of1275_getprop(int phandle, const char *name, void *buf, int buflen, + int *size); + + +typedef struct _of1275_nextprop_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + const char *previous; + void *buf; + /*out */ + int flag; +} of1275_nextprop_service; + +int of1275_nextprop(int phandle, const char *previous, void *buf, + int *flag); + + +typedef struct _of1275_setprop_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + const char *name; + void *buf; + int len; + /*out */ + int size; +} of1275_setprop_service; + +int of1275_setprop(int phandle, const char *name, void *buf, int len, + int *size); + + +typedef struct _of1275_canon_service { + const char *service; + int n_args; + int n_returns; + /*in */ + const char *device_specifier; + void *buf; + int buflen; + /*out */ + int length; +} of1275_canon_service; + +int of1275_canon(const char *device_specifier, void *buf, int buflen, + int *length); + + +typedef struct _of1275_finddevice_service { + const char *service; + int n_args; + int n_returns; + /*in */ + const char *device_specifier; + /*out */ + int phandle; +} of1275_finddevice_service; + +int of1275_finddevice(const char *device_specifier, int *phandle); + + +typedef struct _of1275_instance_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int ihandle; + void *buf; + int buflen; + /*out */ + int length; +} of1275_instance_to_path_service; + +int of1275_instance_to_path(int ihandle, void *buf, int buflen, + int *length); + + +typedef struct _of1275_package_to_path_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int phandle; + void *buf; + int buflen; + /*out */ + int length; +} of1275_package_to_path_service; + +int of1275_package_to_path(int phandle, void *buf, int buflen, + int *length); + + +typedef struct _of1275_call_method_service { + const char *service; + int n_args; + int n_returns; + /*in */ + const char *method; + int ihandle; + /*... */ + int args[0]; +} of1275_call_method_service; + +int of1275_call_method(const char *method, int ihandle, ...); + + +/* 6.3.2.3 Device I/O */ + + +typedef struct _of1275_open_service { + const char *service; + int n_args; + int n_returns; + /*in */ + const char *device_specifier; + /*out */ + int ihandle; +} of1275_open_service; + +int of1275_open(const char *device_specifier, int *ihandle); + + +typedef struct _of1275_close_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int ihandle; + /*out */ +} of1275_close_service; + +int of1275_close(int ihandle); + + +typedef struct _of1275_read_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int ihandle; + void *addr; + int len; + /*out */ + int actual; +} of1275_read_service; + +int of1275_read(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of1275_write_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int ihandle; + void *addr; + int len; + /*out */ + int actual; +} of1275_write_service; + +int of1275_write(int ihandle, void *addr, int len, int *actual); + + +typedef struct _of1275_seek_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int ihandle; + int pos_hi; + int pos_lo; + /*out */ + int status; +} of1275_seek_service; + +int of1275_seek(int ihandle, int pos_hi, int pos_lo, int *status); + + +/* 6.3.2.4 Memory */ + + +typedef struct _of1275_claim_service { + const char *service; + int n_args; + int n_returns; + /*in */ + void *virt; + int size; + int align; + /*out */ + void *baseaddr; +} of1275_claim_service; + +int of1275_claim(void *virt, int size, int align, void **baseaddr); + + +typedef struct _of1275_release_service { + const char *service; + int n_args; + int n_returns; + /*in */ + void *virt; + int size; + int align; + /*out */ +} of1275_release_service; + +int of1275_release(void *virt, int size); + + +/* 6.3.2.5 Control transfer */ + + +typedef struct _of1275_boot_service { + const char *service; + int n_args; + int n_returns; + /*in */ + const char *bootspec; + /*out */ +} of1275_boot_service; + +int of1275_boot(const char *bootspec); + + +typedef struct _of1275_enter_service { + const char *service; + int n_args; + int n_returns; + /*in */ + /*out */ +} of1275_enter_service; + +int of1275_enter(void); + +typedef struct _of1275_exit_service { + const char *service; + int n_args; + int n_returns; + /*in */ + int status; + /*out */ +} of1275_exit_service; + +int of1275_exit(int status); + + +typedef struct _of1275_chain_service { + const char *service; + int n_args; + int n_returns; + /*in */ + void *virt; + int size; + void *entry; + void *args; + int len; + /*out */ +} of1275_chain_service; + +int of1275_chain(void *virt, int size, void *entry, void *args, int len); + + +/* 6.3.2.6 User interface */ + + +typedef struct _of1275_interpret_service { + const char *service; + int n_args; + int n_returns; + /*in */ + const char *cmd; + int args[0]; + /*... */ + /*out */ + /*... */ +} of1275_interpret_service; + +int of1275_interpret(const char *arg, ...); + + +typedef struct _of1275_set_callback_service { + const char *service; + int n_args; + int n_returns; + /*in */ + void *newfunc; + /*out */ + void *oldfunc; +} of1275_set_callback_service; + +int of1275_set_callback(void *newfunc, void **oldfunc); + + +typedef struct _of1275_set_symbol_lookup_service { + const char *service; + int n_args; + int n_returns; + /*in */ + void *sym_to_value; + void *value_to_sym; + /*out */ +} of1275_set_symbol_lookup_service; + +int of1275_set_symbol_lookup(void *sym_to_value, void *value_to_sym); + + +/* 6.3.2.7 Time */ + + +typedef struct _of1275_milliseconds_service { + const char *service; + int n_args; + int n_returns; + /*in */ + /*out */ + int ms; +} of1275_milliseconds_service; + +int of1275_milliseconds(int *ms); + + +/* Common and useful utilities */ + + +int of_find_integer_property(const char *path, const char *property); + +void of_find_string_property(const char *path, const char *property, + char *string, int sizeof_string); diff --git a/utils/ofclient/of1275_io.c b/utils/ofclient/of1275_io.c new file mode 100644 index 0000000..25d1132 --- /dev/null +++ b/utils/ofclient/of1275_io.c @@ -0,0 +1,51 @@ +#include "of1275.h" + +static int of_write_initialized = 0; +static int stdout_ihandle = 0; +static int of_read_initialized = 0; +static int stdin_ihandle = 0; + +int write(int fd, char *buf, int len) +{ + int actual; + + if (fd != 1 && fd != 2) { + // printk("write: bad id %x\n", fd); + exit(1); + } + + if (!of_write_initialized) { + stdout_ihandle = + of_find_integer_property("/chosen", "stdout"); + // printk("stdout_ihandle: %x\n",stdout_ihandle); + of_write_initialized = 1; + } + + of1275_write(stdout_ihandle, buf, len, &actual); + return actual; +} + +int read(int fd, char *buf, int len) +{ + int actual; + + if (fd != 0) { + // printk("write: bad id %x\n", fd); + exit(1); + } + + if (!of_read_initialized) { + stdin_ihandle = + of_find_integer_property("/chosen", "stdin"); + of_read_initialized = 1; + } + + of1275_read(stdin_ihandle, buf, len, &actual); + return actual; +} + +exit(int status) +{ + of1275_exit(status); + while (1); +} diff --git a/utils/ofclient/ofclient.c b/utils/ofclient/ofclient.c new file mode 100644 index 0000000..94214c6 --- /dev/null +++ b/utils/ofclient/ofclient.c @@ -0,0 +1,9 @@ +#include "of1275.h" + +int write(int fd, char *buf, int len); + +int main(void) +{ + write(1, "Hello world!\n", 13 ); + return 0; +} diff --git a/utils/romheaders/Makefile b/utils/romheaders/Makefile new file mode 100644 index 0000000..242cea1 --- /dev/null +++ b/utils/romheaders/Makefile @@ -0,0 +1,40 @@ +# +# OpenBIOS - free your system! +# ( Utilities ) +# +# This program is part of a free implementation of the IEEE 1275-1994 +# Standard for Boot (Initialization Configuration) Firmware. +# +# Copyright (C) 2002 Stefan Reinauer, +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA +# + + +CC = gcc +CFLAGS= -O2 -Wall -W -ansi + +.SUFFIXES: .c .o + +all: romheaders + +romheaders: romheaders.o + $(CC) $(CFLAGS) romheaders.o -o romheaders + strip romheaders + +clean: + rm -f *.o + +distclean: clean + rm -f romheaders diff --git a/utils/romheaders/romheaders.c b/utils/romheaders/romheaders.c new file mode 100644 index 0000000..9e01062 --- /dev/null +++ b/utils/romheaders/romheaders.c @@ -0,0 +1,291 @@ + + +#include +#include +#include +#include +#include + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int + +#define PCI_DATA_HDR (u32) ( ('R' << 24) | ('I' << 16) | ('C' << 8) | 'P' ) + +char *rom=NULL; +size_t romlen=0; + +typedef struct { + u16 signature; + u8 reserved[0x16]; + u16 dptr; +} rom_header_t; + +typedef struct { + u32 signature; + u16 vendor; + u16 device; + u16 reserved_1; + u16 dlen; + u8 drevision; + u8 class_hi; + u16 class_lo; + u16 ilen; + u16 irevision; + u8 type; + u8 indicator; + u16 reserved_2; +} pci_data_t; + + +/* make this endian safe without fancy system headers */ +static u16 little_word(u16 val) +{ + u8 *ptr=(u8 *)&val; + return (ptr[0]|(ptr[1]<<8)); +} + +static u16 little_dword(u16 val) +{ + u8 *ptr=(u8 *)&val; + return (ptr[0]|(ptr[1]<<8)|(ptr[2]<<16)|(ptr[3]<<24)); +} + +/* dump the rom headers */ +static int dump_rom_header(rom_header_t *data) +{ + u16 sig=little_word(data->signature); + int i; + + printf ("PCI Expansion ROM Header:\n"); + + printf (" Signature: 0x%02x%02x (%s)\n", + sig&0xff,sig>>8,sig==0xaa55?"Ok":"Not Ok"); + + printf (" CPU unique data:"); + for (i=0;i<16;i++) { + printf(" 0x%02x",data->reserved[i]); + if (i==7) printf("\n "); + } + + printf ("\n Pointer to PCI Data Structure: 0x%04x\n\n", + little_word(data->dptr)); + + return (sig==0xaa55); +} + +static int dump_pci_data(pci_data_t *data) +{ + u32 sig=little_dword(data->signature); + u32 classcode=(data->class_hi<<16)|(little_word(data->class_lo)); + + printf("PCI Data Structure:\n"); + printf(" Signature: '%c%c%c%c' (%s)\n", sig&0xff,(sig>>8)&0xff, + (sig>>16)&0xff, sig>>24, sig==PCI_DATA_HDR?"Ok":"Not Ok"); + printf(" Vendor ID: 0x%04x\n", little_word(data->vendor)); + printf(" Device ID: 0x%04x\n", little_word(data->device)); + printf(" Reserved: 0x%04x\n", little_word(data->reserved_1)); + printf(" PCI Data Structure Length: 0x%04x (%d bytes)\n", + little_word(data->dlen), little_word(data->dlen)); + printf(" PCI Data Structure Revision: 0x%02x\n", data->drevision); + printf(" Class Code: 0x%06x (",classcode); + switch (classcode) { + case 0x0100: + printf("SCSI Storage"); + break; + case 0x0101: + printf("IDE Storage"); + break; + case 0x0103: + printf("IPI Storage"); + break; + case 0x0104: + printf("RAID Storage"); + break; + case 0x0180: + printf("Storage"); + break; + + case 0x0200: + printf("Ethernet"); + break; + case 0x0201: + printf("Token Ring"); + break; + case 0x0202: + printf("FDDI"); + break; + case 0x0203: + printf("ATM"); + break; + case 0x0280: + printf("Network"); + + case 0x0300: + printf("VGA Display"); + break; + case 0x0301: + printf("XGA Display"); + break; + case 0x0302: + printf("3D Display"); + break; + case 0x0380: + printf("Display"); + break; + + default: + printf("unkown"); + } + printf(")\n Image Length: 0x%04x blocks (%d bytes)\n", + little_word(data->ilen), little_word(data->ilen)*512); + printf(" Revision Level of Code/Data: 0x%04x\n", + little_word(data->irevision)); + printf(" Code Type: 0x%02x (", data->type); + switch (data->type) { + case 0: + printf("Intel x86"); + break; + case 1: + printf("Open Firmware"); + break; + case 2: + printf("HP PA Risc"); + break; + case 3: + printf("Intel EFI (unofficial)"); + break; + default: + printf("unknown as of PCI specs 2.2"); + } + printf(")\n Indicator: 0x%02x %s\n", data->indicator, + data->indicator&0x80?"(last image in rom)":""); + printf(" Reserved: 0x%04x\n\n", little_word(data->reserved_2)); + + return (sig==PCI_DATA_HDR); +} + +static void dump_platform_extensions(u8 type, rom_header_t *data) +{ + u32 entry; + + switch (type) { + case 0x00: + printf("Platform specific data for x86 compliant option rom:\n"); + printf(" Initialization Size: 0x%02x (%d bytes)\n", + data->reserved[0], data->reserved[0]*512); + + /* We do a hack here - implement a jump disasm to be able + * to output correct offset for init code. Once again x86 + * is ugly. + */ + + switch (data->reserved[1]) { + case 0xeb: /* short jump */ + entry = data->reserved[2] + 2; + /* a short jump instruction is 2 bytes, + * we have to add those to the offset + */ + break; + case 0xe9: /* jump */ + entry = ((data->reserved[3]<<8)|data->reserved[2]) + 3; + /* jump is 3 bytes, so add them */ + break; + default: + entry=0; + break; + } + + if (entry) { + /* 0x55aa rom signature plus 1 byte len */ + entry += 3; + printf( " Entry point for INIT function:" + " 0x%x\n\n",entry); + } else + printf( " Unable to determin entry point for INIT" + " function. Please report.\n\n"); + + break; + case 0x01: + printf("Platform specific data for Open Firmware compliant rom:\n"); + printf(" Pointer to FCode program: 0x%04x\n\n", + data->reserved[1]<<8|data->reserved[0]); + break; + default: + printf("Parsing of platform specific data not available for this image\n\n"); + } +} + +int main(int argc, char **argv) +{ + char *name=argv[1]; + FILE *romfile; + struct stat finfo; + + rom_header_t *rom_header; + pci_data_t *pci_data; + + int i=1; + + if (argc!=2) { + printf ("\nUsage: %s \n",argv[0]); + printf ("\nromheaders dumps pci option rom headers " + "according to PCI \n" + "specs 2.2 in human readable form\n\n"); + return -1; + } + + if (stat(name,&finfo)) { + printf("Error while reading file information.\n"); + return -1; + } + + romlen=finfo.st_size; + + rom=malloc(romlen); + if (!rom) { + printf("Out of memory.\n"); + return -1; + } + + romfile=fopen(name,"r"); + if (!romfile) { + printf("Error while opening file\n"); + return -1; + } + + if (fread(rom, romlen, 1, romfile)!=1) { + printf("Error while reading file\n"); + free(rom); + return -1; + } + + fclose(romfile); + + rom_header=(rom_header_t *)rom; + + do { + printf("\nImage %d:\n",i); + if (!dump_rom_header(rom_header)) { + printf("Error occured. Bailing out.\n"); + break; + } + + pci_data=(pci_data_t *)(rom+little_word(rom_header->dptr)); + + if (!dump_pci_data(pci_data)) { + printf("Error occured. Bailing out.\n"); + break; + } + + dump_platform_extensions(pci_data->type, rom_header); + + rom_header+=little_word(pci_data->ilen)*512; + i++; + } while ((pci_data->indicator&0x80)!=0x80 && + romlen<(unsigned long)rom_header-(unsigned long)romlen); + + return 0; +} + +