From 1a2238d1bddc823df06f67312d96ccf9de2893cc Mon Sep 17 00:00:00 2001 From: root Date: Sat, 19 Dec 2015 13:13:57 +0000 Subject: CFE from danitool [without hostTools dir]: https://mega.nz/#!mwZyFK7a!CPT3BKC8dEw29kubtdYxhB91G9vIIismTkgzQ3iUy3k --- cfe/build/broadcom/bcm63xx_ram/Makefile | 76 + cfe/build/broadcom/bcm63xx_rom/Makefile | 160 + cfe/cfe/api/Makefile | 47 + cfe/cfe/api/cfe_api.c | 534 + cfe/cfe/api/cfe_api.h | 192 + cfe/cfe/api/cfe_api_int.h | 168 + cfe/cfe/api/cfe_error.h | 101 + cfe/cfe/applets/Makefile | 64 + cfe/cfe/applets/README | 21 + cfe/cfe/applets/cfe_applet.lds | 37 + cfe/cfe/applets/download.c | 163 + cfe/cfe/applets/download.lds | 12 + cfe/cfe/applets/minicrt0.S | 95 + cfe/cfe/applets/test.c | 211 + cfe/cfe/applets/vapitest.S | 96 + .../mips/board/bcm63xx_ram/include/bcm63xx_util.h | 167 + .../mips/board/bcm63xx_ram/include/bcm_common.h | 32 + .../arch/mips/board/bcm63xx_ram/include/bcm_cpu.h | 32 + .../arch/mips/board/bcm63xx_ram/include/bcm_map.h | 32 + .../arch/mips/board/bcm63xx_ram/include/bcmmii.h | 164 + .../arch/mips/board/bcm63xx_ram/include/bcmtypes.h | 144 + .../mips/board/bcm63xx_ram/include/bsp_config.h | 94 + .../board/bcm63xx_ram/include/dev_bcm63xx_eth.h | 127 + .../board/bcm63xx_ram/include/dev_bcm63xx_flash.h | 38 + .../arch/mips/board/bcm63xx_ram/include/jffs2.h | 251 + cfe/cfe/arch/mips/board/bcm63xx_ram/src/Makefile | 55 + .../mips/board/bcm63xx_ram/src/bcm63xx_board.c | 830 ++ .../arch/mips/board/bcm63xx_ram/src/bcm63xx_cmd.c | 1878 +++ .../arch/mips/board/bcm63xx_ram/src/bcm63xx_devs.c | 734 ++ .../mips/board/bcm63xx_ram/src/bcm63xx_env_subr.c | 277 + .../mips/board/bcm63xx_ram/src/bcm63xx_httpd.c | 1031 ++ .../mips/board/bcm63xx_ram/src/bcm63xx_ldr_elf.c | 388 + .../mips/board/bcm63xx_ram/src/bcm63xx_ldr_raw.c | 368 + .../arch/mips/board/bcm63xx_ram/src/bcm63xx_main.c | 611 + .../mips/board/bcm63xx_ram/src/bcm63xx_net_icmp.c | 199 + .../mips/board/bcm63xx_ram/src/bcm63xx_ram_boot.S | 88 + .../arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c | 1375 +++ .../mips/board/bcm63xx_ram/src/dev_bcm63xx_eth.c | 547 + .../mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c | 629 + .../mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c | 211 + .../arch/mips/board/bcm63xx_ram/src/html/ul.html | 48 + .../mips/board/bcm63xx_ram/src/html/ulinfo.html | 60 + cfe/cfe/arch/mips/board/bcm63xx_ram/src/ram_cfe.mk | 378 + .../arch/mips/board/bcm63xx_ram/src/robosw_reg.c | 615 + cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile | 23 + .../mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S | 548 + .../mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c | 439 + .../board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S | 1818 +++ .../arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c | 649 + cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c | 1031 ++ cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk | 370 + cfe/cfe/arch/mips/common/include/addrspace.h | 63 + cfe/cfe/arch/mips/common/include/disasm.h | 61 + cfe/cfe/arch/mips/common/include/exception.h | 223 + cfe/cfe/arch/mips/common/include/exchandler.h | 85 + cfe/cfe/arch/mips/common/include/initdata.h | 68 + cfe/cfe/arch/mips/common/include/lib_hssubr.h | 84 + cfe/cfe/arch/mips/common/include/lib_physio.h | 100 + cfe/cfe/arch/mips/common/include/lib_setjmp.h | 81 + cfe/cfe/arch/mips/common/include/mipsmacros.h | 376 + cfe/cfe/arch/mips/common/include/segtable.h | 97 + cfe/cfe/arch/mips/common/src/Makefile | 38 + cfe/cfe/arch/mips/common/src/cfe_ram_cached.lds | 40 + cfe/cfe/arch/mips/common/src/cfe_ram_uncached.lds | 40 + cfe/cfe/arch/mips/common/src/cfe_ramapp.lds | 41 + cfe/cfe/arch/mips/common/src/cfe_rom_cached.lds | 40 + .../arch/mips/common/src/cfe_rom_reloc_cached.lds | 43 + .../common/src/cfe_rom_reloc_cached_biendian.lds | 49 + .../mips/common/src/cfe_rom_reloc_uncached.lds | 41 + cfe/cfe/arch/mips/common/src/cfe_rom_uncached.lds | 39 + cfe/cfe/arch/mips/common/src/dev_flash_all.S | 220 + cfe/cfe/arch/mips/common/src/dev_flashop_engine.S | 695 ++ cfe/cfe/arch/mips/common/src/disasm.c | 2111 ++++ cfe/cfe/arch/mips/common/src/exception.S | 546 + cfe/cfe/arch/mips/common/src/exchandler.c | 580 + cfe/cfe/arch/mips/common/src/init_mips.S | 683 ++ cfe/cfe/arch/mips/common/src/init_ram.S | 889 ++ cfe/cfe/arch/mips/common/src/lib_hssubr.S | 194 + cfe/cfe/arch/mips/common/src/lib_physio.S | 173 + cfe/cfe/arch/mips/common/src/lib_setjmp.S | 94 + cfe/cfe/arch/mips/common/src/mips_arena.c | 186 + cfe/cfe/arch/mips/common/src/tools.mk | 83 + cfe/cfe/arch/mips/common/src/ui_memtest.c | 282 + cfe/cfe/arch/mips/cpu/SIBYTE_PRIVATE_FILES | 2 + cfe/cfe/arch/mips/cpu/bcmcore/include/bcm4710.h | 58 + cfe/cfe/arch/mips/cpu/bcmcore/include/bcm47xx.h | 8 + cfe/cfe/arch/mips/cpu/bcmcore/include/bcmnvram.h | 123 + cfe/cfe/arch/mips/cpu/bcmcore/include/cpu_config.h | 62 + cfe/cfe/arch/mips/cpu/bcmcore/include/sbmips.h | 670 ++ cfe/cfe/arch/mips/cpu/bcmcore/include/sbsdram.h | 92 + cfe/cfe/arch/mips/cpu/bcmcore/src/Makefile | 8 + cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_arena.c | 170 + .../arch/mips/cpu/bcmcore/src/bcmcore_cpuinit.S | 490 + .../arch/mips/cpu/bcmcore/src/bcmcore_l1cache.S | 219 + cfe/cfe/dev/SIBYTE_PRIVATE_FILES | 6 + cfe/cfe/dev/bcm5700.h | 1007 ++ cfe/cfe/dev/bcm5821.h | 278 + cfe/cfe/dev/dc21143.h | 588 + cfe/cfe/dev/dev_atapi.c | 222 + cfe/cfe/dev/dev_bcm1250.c | 275 + cfe/cfe/dev/dev_bcm5700.c | 2557 ++++ cfe/cfe/dev/dev_bcm5821.c | 1592 +++ cfe/cfe/dev/dev_dc21143.c | 2388 ++++ cfe/cfe/dev/dev_dp83815.c | 2290 ++++ cfe/cfe/dev/dev_ds17887clock.c | 422 + cfe/cfe/dev/dev_flash.c | 1367 +++ cfe/cfe/dev/dev_ht7520.c | 167 + cfe/cfe/dev/dev_ide_common.c | 1249 ++ cfe/cfe/dev/dev_ide_pci.c | 358 + cfe/cfe/dev/dev_newflash.c | 1428 +++ cfe/cfe/dev/dev_ns16550.c | 255 + cfe/cfe/dev/dev_ns16550_pci.c | 114 + cfe/cfe/dev/dev_null.c | 142 + cfe/cfe/dev/dev_promice.c | 402 + cfe/cfe/dev/dev_sp1011.c | 151 + cfe/cfe/dev/dev_tulip.c | 2985 +++++ cfe/cfe/dev/dp83815.h | 559 + cfe/cfe/dev/ns16550.h | 143 + cfe/cfe/dev/pci_devs.c | 79 + cfe/cfe/hosttools/Makefile | 12 + cfe/cfe/hosttools/README | 49 + cfe/cfe/hosttools/installboot.c | 352 + cfe/cfe/hosttools/makereg.c | 481 + cfe/cfe/hosttools/memconfig.c | 654 ++ cfe/cfe/hosttools/mkbootimage.c | 314 + cfe/cfe/hosttools/mkflashimage.c | 347 + cfe/cfe/hosttools/mkpcidb.c | 157 + cfe/cfe/include/cfe.h | 101 + cfe/cfe/include/cfe_autoboot.h | 71 + cfe/cfe/include/cfe_boot.h | 58 + cfe/cfe/include/cfe_bootblock.h | 129 + cfe/cfe/include/cfe_console.h | 92 + cfe/cfe/include/cfe_devfuncs.h | 76 + cfe/cfe/include/cfe_device.h | 118 + cfe/cfe/include/cfe_error.h | 110 + cfe/cfe/include/cfe_fileops.h | 109 + cfe/cfe/include/cfe_flashimage.h | 64 + cfe/cfe/include/cfe_iocb.h | 211 + cfe/cfe/include/cfe_ioctl.h | 167 + cfe/cfe/include/cfe_irq.h | 103 + cfe/cfe/include/cfe_loader.h | 86 + cfe/cfe/include/cfe_mem.h | 79 + cfe/cfe/include/cfe_timer.h | 74 + cfe/cfe/include/cfe_xiocb.h | 202 + cfe/cfe/include/dev_flash.h | 168 + cfe/cfe/include/dev_ide.h | 90 + cfe/cfe/include/dev_ide_common.h | 204 + cfe/cfe/include/dev_newflash.h | 344 + cfe/cfe/include/elf.h | 194 + cfe/cfe/include/env_subr.h | 117 + cfe/cfe/include/foxconnCfg.h | 9 + cfe/cfe/include/lib_arena.h | 76 + cfe/cfe/include/lib_malloc.h | 78 + cfe/cfe/include/lib_printf.h | 69 + cfe/cfe/include/lib_queue.h | 85 + cfe/cfe/include/lib_string.h | 117 + cfe/cfe/include/lib_types.h | 120 + cfe/cfe/include/socregs.h | 63 + cfe/cfe/include/tftpd.h | 26 + cfe/cfe/include/ui_command.h | 140 + cfe/cfe/lib/lib_arena.c | 389 + cfe/cfe/lib/lib_malloc.c | 620 + cfe/cfe/lib/lib_misc.c | 229 + cfe/cfe/lib/lib_printf.c | 442 + cfe/cfe/lib/lib_qsort.c | 88 + cfe/cfe/lib/lib_queue.c | 219 + cfe/cfe/lib/lib_string.c | 386 + cfe/cfe/lib/lib_string2.c | 96 + cfe/cfe/lzma/LzmaDecode.c | 584 + cfe/cfe/lzma/LzmaDecode.h | 113 + cfe/cfe/lzma/LzmaDecodeSize.c | 712 ++ cfe/cfe/lzma/LzmaStateDecode.c | 521 + cfe/cfe/lzma/LzmaStateDecode.h | 96 + cfe/cfe/lzma/LzmaStateTest.c | 195 + cfe/cfe/lzma/LzmaTest.c | 342 + cfe/cfe/lzma/LzmaTypes.h | 45 + cfe/cfe/lzma/Makefile | 5 + cfe/cfe/lzma/dcapi.c | 50 + cfe/cfe/main/cfe.mk | 301 + cfe/cfe/main/cfe_attach.c | 265 + cfe/cfe/main/cfe_autoboot.c | 456 + cfe/cfe/main/cfe_background.c | 174 + cfe/cfe/main/cfe_boot.c | 248 + cfe/cfe/main/cfe_console.c | 1190 ++ cfe/cfe/main/cfe_devfuncs.c | 279 + cfe/cfe/main/cfe_error.c | 134 + cfe/cfe/main/cfe_fatfs.c | 1983 ++++ cfe/cfe/main/cfe_filesys.c | 343 + cfe/cfe/main/cfe_httpfs.c | 396 + cfe/cfe/main/cfe_iocb_dispatch.c | 647 + cfe/cfe/main/cfe_ldr_elf.c | 396 + cfe/cfe/main/cfe_ldr_raw.c | 360 + cfe/cfe/main/cfe_ldr_srec.c | 557 + cfe/cfe/main/cfe_link.mk | 26 + cfe/cfe/main/cfe_loader.c | 135 + cfe/cfe/main/cfe_main.c | 636 + cfe/cfe/main/cfe_mem.c | 256 + cfe/cfe/main/cfe_rawfs.c | 293 + cfe/cfe/main/cfe_savedata.c | 123 + cfe/cfe/main/cfe_timer.c | 286 + cfe/cfe/main/cfe_version.mk | 12 + cfe/cfe/main/cfe_xreq.c | 346 + cfe/cfe/main/cfe_zlibfs.c | 453 + cfe/cfe/main/env_subr.c | 474 + cfe/cfe/main/nvram_subr.c | 300 + cfe/cfe/main/nvram_subr.h | 54 + cfe/cfe/net/README | 17 + cfe/cfe/net/dev_tcpconsole.c | 341 + cfe/cfe/net/mii.h | 187 + cfe/cfe/net/net_api.c | 1095 ++ cfe/cfe/net/net_api.h | 179 + cfe/cfe/net/net_arp.c | 865 ++ cfe/cfe/net/net_dhcp.c | 869 ++ cfe/cfe/net/net_dns.c | 354 + cfe/cfe/net/net_ebuf.h | 165 + cfe/cfe/net/net_ether.c | 705 ++ cfe/cfe/net/net_ether.h | 89 + cfe/cfe/net/net_icmp.c | 312 + cfe/cfe/net/net_ip.c | 722 ++ cfe/cfe/net/net_ip.h | 159 + cfe/cfe/net/net_ip_internal.h | 128 + cfe/cfe/net/net_nmrp.c | 656 ++ cfe/cfe/net/net_nmrp.h | 1 + cfe/cfe/net/net_tcp.c | 2215 ++++ cfe/cfe/net/net_tcp.h | 83 + cfe/cfe/net/net_tcp_internal.h | 244 + cfe/cfe/net/net_tcpbuf.c | 298 + cfe/cfe/net/net_tcpbuf.h | 83 + cfe/cfe/net/net_tftp.c | 921 ++ cfe/cfe/net/net_udp.c | 637 + cfe/cfe/pccons/Makefile | 3 + cfe/cfe/pccons/README | 19 + cfe/cfe/pccons/dev_pcconsole.c | 339 + cfe/cfe/pccons/dev_pcconsole2.c | 298 + cfe/cfe/pccons/kbd_subr.c | 371 + cfe/cfe/pccons/kbd_subr.h | 82 + cfe/cfe/pccons/pcibios.h | 72 + cfe/cfe/pccons/vga.h | 76 + cfe/cfe/pccons/vga_subr.c | 285 + cfe/cfe/pccons/vga_subr.h | 82 + cfe/cfe/pccons/vgainit.c | 1164 ++ cfe/cfe/pccons/x86mem.c | 423 + cfe/cfe/pccons/x86mem.h | 109 + cfe/cfe/pci/cfe_pci.h | 52 + cfe/cfe/pci/devlist2h.awk | 220 + cfe/cfe/pci/ldtinit.c | 641 + cfe/cfe/pci/ldtreg.h | 184 + cfe/cfe/pci/pci_machdep.h | 35 + cfe/cfe/pci/pci_subr.c | 710 ++ cfe/cfe/pci/pciconf.c | 1296 ++ cfe/cfe/pci/pcidevs | 1355 +++ cfe/cfe/pci/pcidevs.h | 1360 +++ cfe/cfe/pci/pcidevs_data.h | 5873 ++++++++++ cfe/cfe/pci/pcireg.h | 615 + cfe/cfe/pci/pcivar.h | 216 + cfe/cfe/ui/ui_cmddisp.c | 252 + cfe/cfe/ui/ui_command.c | 990 ++ cfe/cfe/ui/ui_devcmds.c | 101 + cfe/cfe/ui/ui_envcmds.c | 190 + cfe/cfe/ui/ui_examcmds.c | 713 ++ cfe/cfe/ui/ui_flash.c | 554 + cfe/cfe/ui/ui_loadcmds.c | 366 + cfe/cfe/ui/ui_memcmds.c | 171 + cfe/cfe/ui/ui_misccmds.c | 178 + cfe/cfe/ui/ui_netcmds.c | 710 ++ cfe/cfe/ui/ui_pcicmds.c | 282 + cfe/cfe/ui/ui_tcpcmds.c | 828 ++ cfe/cfe/ui/ui_test_disk.c | 439 + cfe/cfe/ui/ui_test_ether.c | 202 + cfe/cfe/ui/ui_test_flash.c | 260 + cfe/cfe/ui/ui_test_uart.c | 117 + cfe/cfe/ui/ui_tftpd.c | 119 + cfe/cfe/ui/ui_toyclock.c | 275 + cfe/cfe/ui/url.c | 357 + cfe/cfe/ui/url.h | 52 + cfe/cfe/usb/Makefile | 8 + cfe/cfe/usb/README | 183 + cfe/cfe/usb/ohci.c | 2126 ++++ cfe/cfe/usb/ohci.h | 490 + cfe/cfe/usb/usbchap9.h | 389 + cfe/cfe/usb/usbd.c | 1215 ++ cfe/cfe/usb/usbd.h | 308 + cfe/cfe/usb/usbdebug.c | 307 + cfe/cfe/usb/usbdevs.c | 168 + cfe/cfe/usb/usbeth.c | 850 ++ cfe/cfe/usb/usbeth.h | 112 + cfe/cfe/usb/usbhack.c | 528 + cfe/cfe/usb/usbhack.h | 66 + cfe/cfe/usb/usbhack.mk | 23 + cfe/cfe/usb/usbhid.c | 664 ++ cfe/cfe/usb/usbhub.c | 912 ++ cfe/cfe/usb/usbmain.c | 367 + cfe/cfe/usb/usbmass.c | 1199 ++ cfe/cfe/usb/usbserial.c | 713 ++ cfe/cfe/vendor/Makefile | 2 + cfe/cfe/vendor/cfe_vendor_cmds.c | 27 + cfe/cfe/vendor/cfe_vendor_iocb.h | 87 + cfe/cfe/vendor/cfe_vendor_iocb_dispatch.c | 179 + cfe/cfe/vendor/cfe_vendor_xiocb.h | 91 + cfe/cfe/vendor/cfe_vendor_xreq.c | 222 + cfe/cfe/verif/Makefile | 7 + cfe/cfe/verif/readme.txt | 342 + cfe/cfe/verif/ui_vapi.c | 300 + cfe/cfe/verif/vapi.S | 1150 ++ cfe/cfe/verif/vapi.h | 242 + cfe/cfe/verif/vapisubr.c | 122 + cfe/cfe/verif/vapitest.S | 108 + cfe/cfe/x86emu/LICENSE | 17 + cfe/cfe/x86emu/Makefile | 2 + cfe/cfe/x86emu/README | 12 + cfe/cfe/x86emu/debug.c | 462 + cfe/cfe/x86emu/decode.c | 1000 ++ cfe/cfe/x86emu/fpu.c | 945 ++ cfe/cfe/x86emu/ops.c | 11686 +++++++++++++++++++ cfe/cfe/x86emu/ops2.c | 2802 +++++ cfe/cfe/x86emu/prim_ops.c | 2915 +++++ cfe/cfe/x86emu/sys.c | 603 + cfe/cfe/x86emu/validate.c | 765 ++ cfe/cfe/x86emu/x86emu.h | 198 + cfe/cfe/x86emu/x86emu/debug.h | 212 + cfe/cfe/x86emu/x86emu/decode.h | 87 + cfe/cfe/x86emu/x86emu/fpu.h | 61 + cfe/cfe/x86emu/x86emu/fpu_regs.h | 115 + cfe/cfe/x86emu/x86emu/ops.h | 45 + cfe/cfe/x86emu/x86emu/ops_protos.h | 277 + cfe/cfe/x86emu/x86emu/prim_asm.h | 971 ++ cfe/cfe/x86emu/x86emu/prim_ops.h | 231 + cfe/cfe/x86emu/x86emu/regs.h | 351 + cfe/cfe/x86emu/x86emu/types.h | 89 + cfe/cfe/x86emu/x86emu/x86emui.h | 109 + cfe/cfe/zlib/ChangeLog | 471 + cfe/cfe/zlib/FAQ | 72 + cfe/cfe/zlib/INDEX | 86 + cfe/cfe/zlib/Make_vms.com | 115 + cfe/cfe/zlib/Makefile | 28 + cfe/cfe/zlib/Makefile.in | 174 + cfe/cfe/zlib/Makefile.orig | 174 + cfe/cfe/zlib/Makefile.riscos | 151 + cfe/cfe/zlib/README | 148 + cfe/cfe/zlib/adler32.c | 48 + cfe/cfe/zlib/algorithm.txt | 213 + cfe/cfe/zlib/compress.c | 68 + cfe/cfe/zlib/configure | 212 + cfe/cfe/zlib/crc32.c | 162 + cfe/cfe/zlib/deflate.c | 1350 +++ cfe/cfe/zlib/deflate.h | 318 + cfe/cfe/zlib/descrip.mms | 48 + cfe/cfe/zlib/example.c | 556 + cfe/cfe/zlib/gzio.c | 875 ++ cfe/cfe/zlib/infblock.c | 398 + cfe/cfe/zlib/infblock.h | 39 + cfe/cfe/zlib/infcodes.c | 257 + cfe/cfe/zlib/infcodes.h | 27 + cfe/cfe/zlib/inffast.c | 170 + cfe/cfe/zlib/inffast.h | 17 + cfe/cfe/zlib/inffixed.h | 151 + cfe/cfe/zlib/inflate.c | 366 + cfe/cfe/zlib/inftrees.c | 455 + cfe/cfe/zlib/inftrees.h | 58 + cfe/cfe/zlib/infutil.c | 87 + cfe/cfe/zlib/infutil.h | 98 + cfe/cfe/zlib/maketree.c | 85 + cfe/cfe/zlib/minigzip.c | 320 + cfe/cfe/zlib/trees.c | 1214 ++ cfe/cfe/zlib/trees.h | 128 + cfe/cfe/zlib/uncompr.c | 58 + cfe/cfe/zlib/zconf.h | 279 + cfe/cfe/zlib/zlib.3 | 107 + cfe/cfe/zlib/zlib.h | 893 ++ cfe/cfe/zlib/zutil.c | 225 + cfe/cfe/zlib/zutil.h | 220 + cfe/docs/cfe.pdf | Bin 0 -> 395677 bytes 372 files changed, 154644 insertions(+) create mode 100755 cfe/build/broadcom/bcm63xx_ram/Makefile create mode 100755 cfe/build/broadcom/bcm63xx_rom/Makefile create mode 100644 cfe/cfe/api/Makefile create mode 100644 cfe/cfe/api/cfe_api.c create mode 100644 cfe/cfe/api/cfe_api.h create mode 100644 cfe/cfe/api/cfe_api_int.h create mode 100644 cfe/cfe/api/cfe_error.h create mode 100644 cfe/cfe/applets/Makefile create mode 100644 cfe/cfe/applets/README create mode 100644 cfe/cfe/applets/cfe_applet.lds create mode 100644 cfe/cfe/applets/download.c create mode 100644 cfe/cfe/applets/download.lds create mode 100644 cfe/cfe/applets/minicrt0.S create mode 100644 cfe/cfe/applets/test.c create mode 100644 cfe/cfe/applets/vapitest.S create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm63xx_util.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_common.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_cpu.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_map.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmmii.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmtypes.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/bsp_config.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_eth.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_flash.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/include/jffs2.h create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/Makefile create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_board.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_cmd.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_devs.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_env_subr.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_elf.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_raw.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_main.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_net_icmp.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ram_boot.S create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_eth.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ul.html create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ulinfo.html create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/ram_cfe.mk create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_ram/src/robosw_reg.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c create mode 100755 cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk create mode 100644 cfe/cfe/arch/mips/common/include/addrspace.h create mode 100644 cfe/cfe/arch/mips/common/include/disasm.h create mode 100644 cfe/cfe/arch/mips/common/include/exception.h create mode 100644 cfe/cfe/arch/mips/common/include/exchandler.h create mode 100644 cfe/cfe/arch/mips/common/include/initdata.h create mode 100644 cfe/cfe/arch/mips/common/include/lib_hssubr.h create mode 100644 cfe/cfe/arch/mips/common/include/lib_physio.h create mode 100644 cfe/cfe/arch/mips/common/include/lib_setjmp.h create mode 100755 cfe/cfe/arch/mips/common/include/mipsmacros.h create mode 100755 cfe/cfe/arch/mips/common/include/segtable.h create mode 100755 cfe/cfe/arch/mips/common/src/Makefile create mode 100644 cfe/cfe/arch/mips/common/src/cfe_ram_cached.lds create mode 100644 cfe/cfe/arch/mips/common/src/cfe_ram_uncached.lds create mode 100755 cfe/cfe/arch/mips/common/src/cfe_ramapp.lds create mode 100755 cfe/cfe/arch/mips/common/src/cfe_rom_cached.lds create mode 100644 cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached.lds create mode 100644 cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached_biendian.lds create mode 100644 cfe/cfe/arch/mips/common/src/cfe_rom_reloc_uncached.lds create mode 100644 cfe/cfe/arch/mips/common/src/cfe_rom_uncached.lds create mode 100644 cfe/cfe/arch/mips/common/src/dev_flash_all.S create mode 100644 cfe/cfe/arch/mips/common/src/dev_flashop_engine.S create mode 100644 cfe/cfe/arch/mips/common/src/disasm.c create mode 100644 cfe/cfe/arch/mips/common/src/exception.S create mode 100644 cfe/cfe/arch/mips/common/src/exchandler.c create mode 100755 cfe/cfe/arch/mips/common/src/init_mips.S create mode 100755 cfe/cfe/arch/mips/common/src/init_ram.S create mode 100644 cfe/cfe/arch/mips/common/src/lib_hssubr.S create mode 100644 cfe/cfe/arch/mips/common/src/lib_physio.S create mode 100644 cfe/cfe/arch/mips/common/src/lib_setjmp.S create mode 100644 cfe/cfe/arch/mips/common/src/mips_arena.c create mode 100755 cfe/cfe/arch/mips/common/src/tools.mk create mode 100644 cfe/cfe/arch/mips/common/src/ui_memtest.c create mode 100644 cfe/cfe/arch/mips/cpu/SIBYTE_PRIVATE_FILES create mode 100644 cfe/cfe/arch/mips/cpu/bcmcore/include/bcm4710.h create mode 100644 cfe/cfe/arch/mips/cpu/bcmcore/include/bcm47xx.h create mode 100644 cfe/cfe/arch/mips/cpu/bcmcore/include/bcmnvram.h create mode 100755 cfe/cfe/arch/mips/cpu/bcmcore/include/cpu_config.h create mode 100644 cfe/cfe/arch/mips/cpu/bcmcore/include/sbmips.h create mode 100644 cfe/cfe/arch/mips/cpu/bcmcore/include/sbsdram.h create mode 100755 cfe/cfe/arch/mips/cpu/bcmcore/src/Makefile create mode 100755 cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_arena.c create mode 100755 cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_cpuinit.S create mode 100755 cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_l1cache.S create mode 100644 cfe/cfe/dev/SIBYTE_PRIVATE_FILES create mode 100644 cfe/cfe/dev/bcm5700.h create mode 100644 cfe/cfe/dev/bcm5821.h create mode 100644 cfe/cfe/dev/dc21143.h create mode 100644 cfe/cfe/dev/dev_atapi.c create mode 100644 cfe/cfe/dev/dev_bcm1250.c create mode 100644 cfe/cfe/dev/dev_bcm5700.c create mode 100644 cfe/cfe/dev/dev_bcm5821.c create mode 100644 cfe/cfe/dev/dev_dc21143.c create mode 100644 cfe/cfe/dev/dev_dp83815.c create mode 100644 cfe/cfe/dev/dev_ds17887clock.c create mode 100644 cfe/cfe/dev/dev_flash.c create mode 100644 cfe/cfe/dev/dev_ht7520.c create mode 100644 cfe/cfe/dev/dev_ide_common.c create mode 100644 cfe/cfe/dev/dev_ide_pci.c create mode 100644 cfe/cfe/dev/dev_newflash.c create mode 100644 cfe/cfe/dev/dev_ns16550.c create mode 100644 cfe/cfe/dev/dev_ns16550_pci.c create mode 100644 cfe/cfe/dev/dev_null.c create mode 100644 cfe/cfe/dev/dev_promice.c create mode 100644 cfe/cfe/dev/dev_sp1011.c create mode 100644 cfe/cfe/dev/dev_tulip.c create mode 100644 cfe/cfe/dev/dp83815.h create mode 100644 cfe/cfe/dev/ns16550.h create mode 100644 cfe/cfe/dev/pci_devs.c create mode 100644 cfe/cfe/hosttools/Makefile create mode 100644 cfe/cfe/hosttools/README create mode 100644 cfe/cfe/hosttools/installboot.c create mode 100644 cfe/cfe/hosttools/makereg.c create mode 100644 cfe/cfe/hosttools/memconfig.c create mode 100644 cfe/cfe/hosttools/mkbootimage.c create mode 100644 cfe/cfe/hosttools/mkflashimage.c create mode 100644 cfe/cfe/hosttools/mkpcidb.c create mode 100755 cfe/cfe/include/cfe.h create mode 100644 cfe/cfe/include/cfe_autoboot.h create mode 100644 cfe/cfe/include/cfe_boot.h create mode 100644 cfe/cfe/include/cfe_bootblock.h create mode 100755 cfe/cfe/include/cfe_console.h create mode 100644 cfe/cfe/include/cfe_devfuncs.h create mode 100644 cfe/cfe/include/cfe_device.h create mode 100644 cfe/cfe/include/cfe_error.h create mode 100644 cfe/cfe/include/cfe_fileops.h create mode 100644 cfe/cfe/include/cfe_flashimage.h create mode 100644 cfe/cfe/include/cfe_iocb.h create mode 100644 cfe/cfe/include/cfe_ioctl.h create mode 100644 cfe/cfe/include/cfe_irq.h create mode 100644 cfe/cfe/include/cfe_loader.h create mode 100644 cfe/cfe/include/cfe_mem.h create mode 100644 cfe/cfe/include/cfe_timer.h create mode 100644 cfe/cfe/include/cfe_xiocb.h create mode 100644 cfe/cfe/include/dev_flash.h create mode 100644 cfe/cfe/include/dev_ide.h create mode 100644 cfe/cfe/include/dev_ide_common.h create mode 100644 cfe/cfe/include/dev_newflash.h create mode 100644 cfe/cfe/include/elf.h create mode 100644 cfe/cfe/include/env_subr.h create mode 100755 cfe/cfe/include/foxconnCfg.h create mode 100644 cfe/cfe/include/lib_arena.h create mode 100644 cfe/cfe/include/lib_malloc.h create mode 100755 cfe/cfe/include/lib_printf.h create mode 100644 cfe/cfe/include/lib_queue.h create mode 100644 cfe/cfe/include/lib_string.h create mode 100644 cfe/cfe/include/lib_types.h create mode 100644 cfe/cfe/include/socregs.h create mode 100755 cfe/cfe/include/tftpd.h create mode 100644 cfe/cfe/include/ui_command.h create mode 100644 cfe/cfe/lib/lib_arena.c create mode 100644 cfe/cfe/lib/lib_malloc.c create mode 100644 cfe/cfe/lib/lib_misc.c create mode 100644 cfe/cfe/lib/lib_printf.c create mode 100644 cfe/cfe/lib/lib_qsort.c create mode 100644 cfe/cfe/lib/lib_queue.c create mode 100644 cfe/cfe/lib/lib_string.c create mode 100644 cfe/cfe/lib/lib_string2.c create mode 100755 cfe/cfe/lzma/LzmaDecode.c create mode 100755 cfe/cfe/lzma/LzmaDecode.h create mode 100755 cfe/cfe/lzma/LzmaDecodeSize.c create mode 100755 cfe/cfe/lzma/LzmaStateDecode.c create mode 100755 cfe/cfe/lzma/LzmaStateDecode.h create mode 100755 cfe/cfe/lzma/LzmaStateTest.c create mode 100755 cfe/cfe/lzma/LzmaTest.c create mode 100755 cfe/cfe/lzma/LzmaTypes.h create mode 100755 cfe/cfe/lzma/Makefile create mode 100755 cfe/cfe/lzma/dcapi.c create mode 100644 cfe/cfe/main/cfe.mk create mode 100644 cfe/cfe/main/cfe_attach.c create mode 100644 cfe/cfe/main/cfe_autoboot.c create mode 100644 cfe/cfe/main/cfe_background.c create mode 100644 cfe/cfe/main/cfe_boot.c create mode 100755 cfe/cfe/main/cfe_console.c create mode 100755 cfe/cfe/main/cfe_devfuncs.c create mode 100644 cfe/cfe/main/cfe_error.c create mode 100644 cfe/cfe/main/cfe_fatfs.c create mode 100755 cfe/cfe/main/cfe_filesys.c create mode 100644 cfe/cfe/main/cfe_httpfs.c create mode 100755 cfe/cfe/main/cfe_iocb_dispatch.c create mode 100644 cfe/cfe/main/cfe_ldr_elf.c create mode 100644 cfe/cfe/main/cfe_ldr_raw.c create mode 100644 cfe/cfe/main/cfe_ldr_srec.c create mode 100644 cfe/cfe/main/cfe_link.mk create mode 100644 cfe/cfe/main/cfe_loader.c create mode 100644 cfe/cfe/main/cfe_main.c create mode 100644 cfe/cfe/main/cfe_mem.c create mode 100644 cfe/cfe/main/cfe_rawfs.c create mode 100644 cfe/cfe/main/cfe_savedata.c create mode 100644 cfe/cfe/main/cfe_timer.c create mode 100755 cfe/cfe/main/cfe_version.mk create mode 100644 cfe/cfe/main/cfe_xreq.c create mode 100644 cfe/cfe/main/cfe_zlibfs.c create mode 100644 cfe/cfe/main/env_subr.c create mode 100644 cfe/cfe/main/nvram_subr.c create mode 100644 cfe/cfe/main/nvram_subr.h create mode 100644 cfe/cfe/net/README create mode 100644 cfe/cfe/net/dev_tcpconsole.c create mode 100644 cfe/cfe/net/mii.h create mode 100755 cfe/cfe/net/net_api.c create mode 100755 cfe/cfe/net/net_api.h create mode 100755 cfe/cfe/net/net_arp.c create mode 100644 cfe/cfe/net/net_dhcp.c create mode 100755 cfe/cfe/net/net_dns.c create mode 100644 cfe/cfe/net/net_ebuf.h create mode 100644 cfe/cfe/net/net_ether.c create mode 100644 cfe/cfe/net/net_ether.h create mode 100644 cfe/cfe/net/net_icmp.c create mode 100755 cfe/cfe/net/net_ip.c create mode 100755 cfe/cfe/net/net_ip.h create mode 100644 cfe/cfe/net/net_ip_internal.h create mode 100755 cfe/cfe/net/net_nmrp.c create mode 100755 cfe/cfe/net/net_nmrp.h create mode 100755 cfe/cfe/net/net_tcp.c create mode 100755 cfe/cfe/net/net_tcp.h create mode 100755 cfe/cfe/net/net_tcp_internal.h create mode 100644 cfe/cfe/net/net_tcpbuf.c create mode 100644 cfe/cfe/net/net_tcpbuf.h create mode 100644 cfe/cfe/net/net_tftp.c create mode 100644 cfe/cfe/net/net_udp.c create mode 100644 cfe/cfe/pccons/Makefile create mode 100644 cfe/cfe/pccons/README create mode 100644 cfe/cfe/pccons/dev_pcconsole.c create mode 100644 cfe/cfe/pccons/dev_pcconsole2.c create mode 100644 cfe/cfe/pccons/kbd_subr.c create mode 100644 cfe/cfe/pccons/kbd_subr.h create mode 100644 cfe/cfe/pccons/pcibios.h create mode 100644 cfe/cfe/pccons/vga.h create mode 100644 cfe/cfe/pccons/vga_subr.c create mode 100644 cfe/cfe/pccons/vga_subr.h create mode 100644 cfe/cfe/pccons/vgainit.c create mode 100644 cfe/cfe/pccons/x86mem.c create mode 100644 cfe/cfe/pccons/x86mem.h create mode 100644 cfe/cfe/pci/cfe_pci.h create mode 100644 cfe/cfe/pci/devlist2h.awk create mode 100644 cfe/cfe/pci/ldtinit.c create mode 100644 cfe/cfe/pci/ldtreg.h create mode 100644 cfe/cfe/pci/pci_machdep.h create mode 100644 cfe/cfe/pci/pci_subr.c create mode 100644 cfe/cfe/pci/pciconf.c create mode 100644 cfe/cfe/pci/pcidevs create mode 100644 cfe/cfe/pci/pcidevs.h create mode 100644 cfe/cfe/pci/pcidevs_data.h create mode 100644 cfe/cfe/pci/pcireg.h create mode 100644 cfe/cfe/pci/pcivar.h create mode 100644 cfe/cfe/ui/ui_cmddisp.c create mode 100644 cfe/cfe/ui/ui_command.c create mode 100644 cfe/cfe/ui/ui_devcmds.c create mode 100644 cfe/cfe/ui/ui_envcmds.c create mode 100644 cfe/cfe/ui/ui_examcmds.c create mode 100644 cfe/cfe/ui/ui_flash.c create mode 100644 cfe/cfe/ui/ui_loadcmds.c create mode 100644 cfe/cfe/ui/ui_memcmds.c create mode 100644 cfe/cfe/ui/ui_misccmds.c create mode 100644 cfe/cfe/ui/ui_netcmds.c create mode 100644 cfe/cfe/ui/ui_pcicmds.c create mode 100644 cfe/cfe/ui/ui_tcpcmds.c create mode 100644 cfe/cfe/ui/ui_test_disk.c create mode 100644 cfe/cfe/ui/ui_test_ether.c create mode 100644 cfe/cfe/ui/ui_test_flash.c create mode 100644 cfe/cfe/ui/ui_test_uart.c create mode 100755 cfe/cfe/ui/ui_tftpd.c create mode 100644 cfe/cfe/ui/ui_toyclock.c create mode 100644 cfe/cfe/ui/url.c create mode 100644 cfe/cfe/ui/url.h create mode 100644 cfe/cfe/usb/Makefile create mode 100644 cfe/cfe/usb/README create mode 100644 cfe/cfe/usb/ohci.c create mode 100644 cfe/cfe/usb/ohci.h create mode 100644 cfe/cfe/usb/usbchap9.h create mode 100644 cfe/cfe/usb/usbd.c create mode 100644 cfe/cfe/usb/usbd.h create mode 100644 cfe/cfe/usb/usbdebug.c create mode 100644 cfe/cfe/usb/usbdevs.c create mode 100644 cfe/cfe/usb/usbeth.c create mode 100644 cfe/cfe/usb/usbeth.h create mode 100644 cfe/cfe/usb/usbhack.c create mode 100644 cfe/cfe/usb/usbhack.h create mode 100644 cfe/cfe/usb/usbhack.mk create mode 100644 cfe/cfe/usb/usbhid.c create mode 100644 cfe/cfe/usb/usbhub.c create mode 100644 cfe/cfe/usb/usbmain.c create mode 100644 cfe/cfe/usb/usbmass.c create mode 100644 cfe/cfe/usb/usbserial.c create mode 100644 cfe/cfe/vendor/Makefile create mode 100644 cfe/cfe/vendor/cfe_vendor_cmds.c create mode 100644 cfe/cfe/vendor/cfe_vendor_iocb.h create mode 100644 cfe/cfe/vendor/cfe_vendor_iocb_dispatch.c create mode 100644 cfe/cfe/vendor/cfe_vendor_xiocb.h create mode 100644 cfe/cfe/vendor/cfe_vendor_xreq.c create mode 100644 cfe/cfe/verif/Makefile create mode 100644 cfe/cfe/verif/readme.txt create mode 100644 cfe/cfe/verif/ui_vapi.c create mode 100644 cfe/cfe/verif/vapi.S create mode 100644 cfe/cfe/verif/vapi.h create mode 100644 cfe/cfe/verif/vapisubr.c create mode 100644 cfe/cfe/verif/vapitest.S create mode 100644 cfe/cfe/x86emu/LICENSE create mode 100644 cfe/cfe/x86emu/Makefile create mode 100644 cfe/cfe/x86emu/README create mode 100644 cfe/cfe/x86emu/debug.c create mode 100644 cfe/cfe/x86emu/decode.c create mode 100644 cfe/cfe/x86emu/fpu.c create mode 100644 cfe/cfe/x86emu/ops.c create mode 100644 cfe/cfe/x86emu/ops2.c create mode 100644 cfe/cfe/x86emu/prim_ops.c create mode 100644 cfe/cfe/x86emu/sys.c create mode 100644 cfe/cfe/x86emu/validate.c create mode 100644 cfe/cfe/x86emu/x86emu.h create mode 100644 cfe/cfe/x86emu/x86emu/debug.h create mode 100644 cfe/cfe/x86emu/x86emu/decode.h create mode 100644 cfe/cfe/x86emu/x86emu/fpu.h create mode 100644 cfe/cfe/x86emu/x86emu/fpu_regs.h create mode 100644 cfe/cfe/x86emu/x86emu/ops.h create mode 100644 cfe/cfe/x86emu/x86emu/ops_protos.h create mode 100644 cfe/cfe/x86emu/x86emu/prim_asm.h create mode 100644 cfe/cfe/x86emu/x86emu/prim_ops.h create mode 100644 cfe/cfe/x86emu/x86emu/regs.h create mode 100644 cfe/cfe/x86emu/x86emu/types.h create mode 100644 cfe/cfe/x86emu/x86emu/x86emui.h create mode 100644 cfe/cfe/zlib/ChangeLog create mode 100644 cfe/cfe/zlib/FAQ create mode 100644 cfe/cfe/zlib/INDEX create mode 100644 cfe/cfe/zlib/Make_vms.com create mode 100644 cfe/cfe/zlib/Makefile create mode 100644 cfe/cfe/zlib/Makefile.in create mode 100644 cfe/cfe/zlib/Makefile.orig create mode 100644 cfe/cfe/zlib/Makefile.riscos create mode 100644 cfe/cfe/zlib/README create mode 100644 cfe/cfe/zlib/adler32.c create mode 100644 cfe/cfe/zlib/algorithm.txt create mode 100644 cfe/cfe/zlib/compress.c create mode 100755 cfe/cfe/zlib/configure create mode 100644 cfe/cfe/zlib/crc32.c create mode 100644 cfe/cfe/zlib/deflate.c create mode 100644 cfe/cfe/zlib/deflate.h create mode 100644 cfe/cfe/zlib/descrip.mms create mode 100644 cfe/cfe/zlib/example.c create mode 100644 cfe/cfe/zlib/gzio.c create mode 100644 cfe/cfe/zlib/infblock.c create mode 100644 cfe/cfe/zlib/infblock.h create mode 100644 cfe/cfe/zlib/infcodes.c create mode 100644 cfe/cfe/zlib/infcodes.h create mode 100644 cfe/cfe/zlib/inffast.c create mode 100644 cfe/cfe/zlib/inffast.h create mode 100644 cfe/cfe/zlib/inffixed.h create mode 100644 cfe/cfe/zlib/inflate.c create mode 100644 cfe/cfe/zlib/inftrees.c create mode 100644 cfe/cfe/zlib/inftrees.h create mode 100644 cfe/cfe/zlib/infutil.c create mode 100644 cfe/cfe/zlib/infutil.h create mode 100644 cfe/cfe/zlib/maketree.c create mode 100644 cfe/cfe/zlib/minigzip.c create mode 100644 cfe/cfe/zlib/trees.c create mode 100644 cfe/cfe/zlib/trees.h create mode 100644 cfe/cfe/zlib/uncompr.c create mode 100644 cfe/cfe/zlib/zconf.h create mode 100644 cfe/cfe/zlib/zlib.3 create mode 100644 cfe/cfe/zlib/zlib.h create mode 100644 cfe/cfe/zlib/zutil.c create mode 100644 cfe/cfe/zlib/zutil.h create mode 100755 cfe/docs/cfe.pdf (limited to 'cfe') diff --git a/cfe/build/broadcom/bcm63xx_ram/Makefile b/cfe/build/broadcom/bcm63xx_ram/Makefile new file mode 100755 index 0000000..970da8f --- /dev/null +++ b/cfe/build/broadcom/bcm63xx_ram/Makefile @@ -0,0 +1,76 @@ + +CFG_MLONG64 ?= 0 +CFG_LITTLE ?= 0 # Mindbender +CFG_RELOC ?= 0 +CFG_UNCACHED ?= 0 # Mindbender +CFG_NEWRELOC ?= 0 +CFG_VAPI ?= 0 +CFG_BOOTRAM ?= 0 +CFG_RAMAPP ?= 1 +CFG_BOARDNAME = "BCM9$(BRCM_CHIP)" +CFG_PCI = 0 +CFG_ZLIB = 0 # enable zlib + +COMPRESS ?= cmplzma + +TOP = ../../../cfe +ARCH = mips +CPU = bcmcore +BOARD = bcm63xx_ram + +HOSTTOOLS = ../../../../hostTools +SHARED_DIR = ../../../../shared +BOARDPARMS_DIR = $(SHARED_DIR)/opensource/boardparms/bcm963xx +FLASH_DIR = $(SHARED_DIR)/opensource/flash +BCMSPI_DIR = $(SHARED_DIR)/opensource/spi +INC_SHARED_PUB_PATH = $(SHARED_DIR)/opensource/include/bcm963xx +INC_SHARED_PRIV_PATH = $(SHARED_DIR)/broadcom/include/bcm963xx +ROM_BUILD = ../bcm63xx_rom +ASM_FILE =$(ROM_BUILD)/flashimg.S + +ifeq ($(strip $(CFG_SBP)),1) + CFLAGS += -DUSE_SINGLE_BOARD_PARAM +endif + +include $(TOP)/arch/mips/board/$(BOARD)/src/ram_cfe.mk + +VPATH += ${ARCH_TOP}/board/$(BOARD)/src/html ${BOARDPARMS_DIR} $(BCMSPI_DIR) ${FLASH_DIR} +INCDIRS += -I${INC_SHARED_PUB_PATH} -I${INC_SHARED_PRIV_PATH} + +$(HOSTTOOLS)/$(COMPRESS): + $(MAKE) -C $(HOSTTOOLS) build_cmplzma + +ALL: sanity_check $(HOSTTOOLS)/$(COMPRESS) + find $(SHARED_DIR) -name "*.o" -exec rm -f "{}" ";" + find $(BOARDPARMS_DIR) -name "*.o" -exec rm -f "{}" ";" + ${MAKE} cfe$(BRCM_CHIP) + $(HOSTTOOLS)/$(COMPRESS) -s -c -2 cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin $(ASM_FILE) + +sanity_check: + @if [ "$(BRCM_CHIP)" = "" ]; then \ + echo You must specify chip ID using 'gmake BRCM_CHIP=[6328|6362|6368|6816]'; exit 1; \ + fi + +$(ASM_FILE): cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin + +cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin: $(CRT0OBJS) $(BSPOBJS) $(LIBCFE) + $(GLD) -o cfe$(BRCM_CHIP) -Map cfe$(BRCM_CHIP).map $(LDFLAGS) $(CRT0OBJS) $(BSPOBJS) -L. -lcfe $(LDLIBS) + $(OBJDUMP) -d cfe$(BRCM_CHIP) > cfe$(BRCM_CHIP).dis + $(OBJCOPY) --output-target=binary cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin +ifeq ($(strip $(INC_NAND_FLASH_DRIVER)),1) + printf "0: %08x%08x%08x" `$(OBJDUMP) -x cfe$(BRCM_CHIP) | sed -n -e "/start address/{s?start address ??p}" -e "/LOAD off/{s?^ *LOAD off.*vaddr ??; s? paddr .*??p}" -e "/ _end/{s? g.* _end??; s?^...?0x000?p}"` | xxd -r > cferamhdr.bin; \ + cat cferamhdr.bin cfe$(BRCM_CHIP).bin > cfe$(BRCM_CHIP)ram.bin; \ + rm cferamhdr.bin +endif + +clean : + rm -f *.o *~ cfe* + rm -f build_date.c + rm -f libcfe.a + rm -f $(ASM_FILE) + +distclean : clean + + + + diff --git a/cfe/build/broadcom/bcm63xx_rom/Makefile b/cfe/build/broadcom/bcm63xx_rom/Makefile new file mode 100755 index 0000000..819cb21 --- /dev/null +++ b/cfe/build/broadcom/bcm63xx_rom/Makefile @@ -0,0 +1,160 @@ + +CFG_MLONG64 ?= 0 +CFG_LITTLE ?= 0 # Mindbender +CFG_RELOC ?= 0 +CFG_UNCACHED ?= 0 # Mindbender +CFG_NEWRELOC ?= 0 +CFG_VAPI ?= 0 +CFG_BOOTRAM ?= 0 +CFG_RAMAPP ?= 0 # EPI +CFG_BOARDNAME = "BCM9$(BRCM_CHIP)" +CFG_PCI ?= 0 +CFG_ZLIB ?= 0 # enable zlib +CFG_SBP ?= 0 # use Single Board Parameter if defined to 1 + +TOP = ../../../cfe +ARCH = mips +CPU = bcmcore +BOARD = bcm63xx_rom + +LINUX_KERNEL_DIR=../../../../kernel/linux +HOSTTOOLS = ../../../../hostTools +TARGETS_DIR = ../../../../targets +SHARED_DIR = ../../../../shared +INC_SHARED_PUB_PATH = $(SHARED_DIR)/opensource/include/bcm963xx +INC_SHARED_PRIV_PATH = $(SHARED_DIR)/broadcom/include/bcm963xx +FLASH_DIR = $(SHARED_DIR)/opensource/flash +BCMSPI_DIR = $(SHARED_DIR)/opensource/spi + +BOOT_DIR = ${ARCH_TOP}/board/$(BOARD)/src +ASM_FILE = flashimg.S +RAM_BUILD = ../bcm63xx_ram + +TOOLS=../../../../uclibc-crosstools-gcc-4.4.2-1/usr/bin/mips-linux- + +include $(TOP)/arch/mips/board/$(BOARD)/src/rom_cfe.mk + +VPATH += ${FLASH_DIR} $(BCMSPI_DIR) +INCDIRS += -I${ARCH_TOP}/board/bcm63xx_ram/include -I${INC_SHARED_PUB_PATH} -I${INC_SHARED_PRIV_PATH} + +BSPOBJS_ROM := $(BSPOBJS) +ifneq ($(strip $(BRCM_IKOS)),y) +BSPOBJS += flashimg.o $(LZMAOBJS) +endif + +export INC_CFI_FLASH_DRIVER INC_SPI_FLASH_DRIVER INC_NAND_FLASH_DRIVER INC_SPI_PROG_NAND + +ALL : sanity_check cfe$(BRCM_CHIP) +ifneq ($(strip $(INC_NAND_FLASH_DRIVER)),1) + gcc -o ${HOSTTOOLS}/addvtoken -I ${INC_SHARED_PUB_PATH} ${HOSTTOOLS}/addvtoken.c + @if [ $(shell find . -name cfe$(BRCM_CHIP).bin -printf '%s\n') -le 65536 ] ; then \ + ${HOSTTOOLS}/addvtoken cfe$(BRCM_CHIP).bin bcm9$(BRCM_CHIP)_cfe.w; \ + else \ + find . -name cfe$(BRCM_CHIP).bin -printf '\nERROR: cfe.bin size, %s, is greater than 65536 maximum size.\n'; \ + rm cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin; \ + fi +endif + @echo done + +untar_check: + @if [ ! -e $(TOP)/api ]; then \ + echo Untarring original CFE source...; \ + (cd ../../.. && tar xfzk cfe*.tar.gz 2> /dev/null || true); \ + fi + +sanity_check: + @if [ "$(BRCM_CHIP)" = "" ]; then \ + echo You must specify chip ID using 'make BRCM_CHIP=[6328|6362|6368|6816]'; exit 1; \ + fi + @if [ ! -e $(TOP)/api ]; then \ + echo Untarring original CFE source...; \ + (cd ../../.. && tar xfzk cfe*.tar.gz 2> /dev/null || true); \ + $(MAKE) BRCM_CHIP=$(BRCM_CHIP) BLD_NAND=$(BLD_NAND); \ + fi + +mksbp: ALL + @echo done + +sbp: + ${MAKE} clean + ${MAKE} CFG_SBP?=1 mksbp + +ifeq ($(strip $(INC_NAND_FLASH_DRIVER)),1) +# Build NAND flash boot loader +cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin : $(CRT0OBJS) $(BSPOBJS_ROM) $(LIBCFE) noflashimg + $(MAKE) -C $(RAM_BUILD) + $(GLD) -o cfe$(BRCM_CHIP)rom -Map cfe$(BRCM_CHIP)rom.map $(LDFLAGS) $(CRT0OBJS) $(BSPOBJS_ROM) noflashimg.o -L. -lcfe $(LDLIBS) + $(OBJCOPY) --output-target=binary cfe$(BRCM_CHIP)rom cfe$(BRCM_CHIP)rom.bin + rm noflashimg.* + +noflashimg: + echo "char *_binArrayStart = (char *) 0, *_binArrayEnd = (char *) 0;" > $@.c; \ + echo "int decompressLZMA(unsigned char *s, unsigned int sl, unsigned char *d, unsigned int dl);" >> $@.c; \ + echo "int decompressLZMA(unsigned char *s, unsigned int sl, unsigned char *d, unsigned int dl){return 0;}" >> $@.c + $(GCC) $(CFLAGS) -o $@.o $@.c + +else +# Build NOR flash boot loader +cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin : $(CRT0OBJS) $(BSPOBJS) $(LIBCFE) $(ASM_FILE) + $(GLD) -o cfe$(BRCM_CHIP) -Map cfe$(BRCM_CHIP).map $(LDFLAGS) $(CRT0OBJS) $(BSPOBJS) -L. -lcfe $(LDLIBS) + $(OBJDUMP) -d cfe$(BRCM_CHIP) > cfe$(BRCM_CHIP).dis + $(OBJCOPY) --output-target=binary cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin + +$(ASM_FILE) : $(TOP)/arch/mips/board/bcm63xx_ram/src + rm -f $(ASM_FILE) + $(MAKE) -C $(RAM_BUILD) +endif + + +clean : untar_check + rm -f *.o *~ cfe* *.w *.srec + rm -f build_date.c + rm -f noflashimg.c >& /dev/null + rm -f libcfe.a + $(MAKE) -C $(RAM_BUILD) clean + +distclean : clean + +release : untar_check + $(MAKE) clean + $(MAKE) BRCM_CHIP=6328 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + $(MAKE) BRCM_CHIP=6328 BLD_NAND=1 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + cp -f $(RAM_BUILD)/cfe*ram.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + $(MAKE) BRCM_CHIP=6362 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + $(MAKE) BRCM_CHIP=6362 BLD_NAND=1 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + cp -f $(RAM_BUILD)/cfe*ram.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + $(MAKE) BRCM_CHIP=6368 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + $(MAKE) BRCM_CHIP=6368 BLD_NAND=1 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + cp -f $(RAM_BUILD)/cfe*ram.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + $(MAKE) BRCM_CHIP=6816 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + $(MAKE) BRCM_CHIP=6816 BLD_NAND=1 + cp -f cfe*.bin $(TARGETS_DIR)/cfe + cp -f $(RAM_BUILD)/cfe*ram.bin $(TARGETS_DIR)/cfe + $(MAKE) clean + +CFE_RAM_START_ADDR := $(OBJDUMP) -f $(RAM_BUILD)/cfe$(BRCM_CHIP) | grep start | cut -d'x' -f2 +VMLINUX_START_ADDR := $(OBJDUMP) -f $(LINUX_KERNEL_DIR)/vmlinux | grep start | cut -d'x' -f2 + +# Must be called from base Linux build directory. +ikos_finish: + @xxd -g4 cfe$(BRCM_CHIP) | sed -e "s/694b6f31/$(shell $(CFE_RAM_START_ADDR))/" | xxd -r > cfe$(BRCM_CHIP).tmp + @mv cfe$(BRCM_CHIP).tmp cfe$(BRCM_CHIP) + @xxd -g4 $(RAM_BUILD)/cfe$(BRCM_CHIP) | sed -e "s/694b6f32/$(shell $(VMLINUX_START_ADDR))/" | xxd -r > $(RAM_BUILD)/cfe$(BRCM_CHIP).tmp + @mv $(RAM_BUILD)/cfe$(BRCM_CHIP).tmp $(RAM_BUILD)/cfe$(BRCM_CHIP) + $(OBJCOPY) --output-target=binary cfe$(BRCM_CHIP) cfe$(BRCM_CHIP).bin + $(OBJCOPY) --output-target=srec $(RAM_BUILD)/cfe$(BRCM_CHIP) cferam$(BRCM_CHIP).srec + diff --git a/cfe/cfe/api/Makefile b/cfe/cfe/api/Makefile new file mode 100644 index 0000000..9f2eb7c --- /dev/null +++ b/cfe/cfe/api/Makefile @@ -0,0 +1,47 @@ +TOOLS_PREFIX = sb1-elf- +CPPFLAGS = -I../include +CFLAGS = -O2 -fomit-frame-pointer \ + -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror + +CC = $(TOOLS_PREFIX)gcc +AR = $(TOOLS_PREFIX)ar + +all: cfe_api.a cfe_api.o + +API_OBJS = \ + api_close.o \ + api_common.o \ + api_cpu_start.o \ + api_cpu_stop.o \ + api_enumenv.o \ + api_enummem.o \ + api_exit.o \ + api_flushcache.o \ + api_getdevinfo.o \ + api_getenv.o \ + api_getfwinfo.o \ + api_getstdhandle.o \ + api_getticks.o \ + api_inpstat.o \ + api_ioctl.o \ + api_open.o \ + api_read.o \ + api_readblk.o \ + api_setenv.o \ + api_strlen.o \ + api_write.o \ + api_writeblk.o + +cfe_api.a: $(API_OBJS) + $(AR) cru cfe_api.a $? + +$(API_OBJS): api_%.o: cfe_api.c Makefile cfe_api.h cfe_api_int.h + $(CC) -c -o $@ -DCFE_API_$* $(CPPFLAGS) $(CFLAGS) $< + +cfe_api.o: cfe_api.c Makefile cfe_api.h cfe_api_int.h + $(CC) -c -o $@ -DCFE_API_ALL $(CPPFLAGS) $(CFLAGS) $< + +.PHONY: clean + +clean: + rm -f *.o *.a *~ diff --git a/cfe/cfe/api/cfe_api.c b/cfe/cfe/api/cfe_api.c new file mode 100644 index 0000000..70cb3d2 --- /dev/null +++ b/cfe/cfe/api/cfe_api.c @@ -0,0 +1,534 @@ +/* $Id: cfe_api.c,v 1.17 2003/02/07 17:27:56 cgd Exp $ */ + +/* + * Copyright 2000, 2001, 2002 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and copied only + * in accordance with the following terms and conditions. Subject to these + * conditions, you may download, copy, install, use, modify and distribute + * modified or unmodified copies of this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce and + * retain this copyright notice and list of conditions as they appear in + * the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Broadcom Corporation. The "Broadcom Corporation" name may not be + * used to endorse or promote products derived from this software + * without the prior written permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE + * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* ********************************************************************* + * + * Broadcom Common Firmware Environment (CFE) + * + * Device Function stubs File: cfe_api.c + * + * This module contains device function stubs (small routines to + * call the standard "iocb" interface entry point to CFE). + * There should be one routine here per iocb function call. + * + * Authors: Mitch Lichtenberg, Chris Demetriou + * + ********************************************************************* */ + +#include "cfe_api.h" +#include "cfe_api_int.h" + +/* Cast from a native pointer to a cfe_xptr_t and back. */ +#define XPTR_FROM_NATIVE(n) ((cfe_xptr_t) (intptr_t) (n)) +#define NATIVE_FROM_XPTR(x) ((void *) (intptr_t) (x)) + +#ifdef CFE_API_IMPL_NAMESPACE +#define cfe_iocb_dispatch(a) __cfe_iocb_dispatch(a) +#endif +int cfe_iocb_dispatch(cfe_xiocb_t *xiocb); + +#if defined(CFE_API_common) || defined(CFE_API_ALL) +/* + * Declare the dispatch function with args of "intptr_t". + * This makes sure whatever model we're compiling in + * puts the pointers in a single register. For example, + * combining -mlong64 and -mips1 or -mips2 would lead to + * trouble, since the handle and IOCB pointer will be + * passed in two registers each, and CFE expects one. + */ + +static int (*cfe_dispfunc)(intptr_t handle, intptr_t xiocb) = 0; +static cfe_xuint_t cfe_handle = 0; + +int +cfe_init(cfe_xuint_t handle, cfe_xuint_t ept) +{ + cfe_dispfunc = NATIVE_FROM_XPTR(ept); + cfe_handle = handle; + return 0; +} + +int +cfe_iocb_dispatch(cfe_xiocb_t *xiocb) +{ + if (!cfe_dispfunc) return -1; + return (*cfe_dispfunc)((intptr_t)cfe_handle, (intptr_t)xiocb); +} +#endif /* CFE_API_common || CFE_API_ALL */ + +#if defined(CFE_API_close) || defined(CFE_API_ALL) +int +cfe_close(int handle) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = 0; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; + +} +#endif /* CFE_API_close || CFE_API_ALL */ + +#if defined(CFE_API_cpu_start) || defined(CFE_API_ALL) +int +cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t); + xiocb.plist.xiocb_cpuctl.cpu_number = cpu; + xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START; + xiocb.plist.xiocb_cpuctl.gp_val = gp; + xiocb.plist.xiocb_cpuctl.sp_val = sp; + xiocb.plist.xiocb_cpuctl.a1_val = a1; + xiocb.plist.xiocb_cpuctl.start_addr = (long)fn; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} +#endif /* CFE_API_cpu_start || CFE_API_ALL */ + +#if defined(CFE_API_cpu_stop) || defined(CFE_API_ALL) +int +cfe_cpu_stop(int cpu) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t); + xiocb.plist.xiocb_cpuctl.cpu_number = cpu; + xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_STOP; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} +#endif /* CFE_API_cpu_stop || CFE_API_ALL */ + +#if defined(CFE_API_enumenv) || defined(CFE_API_ALL) +int +cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_ENV_SET; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); + xiocb.plist.xiocb_envbuf.enum_idx = idx; + xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name); + xiocb.plist.xiocb_envbuf.name_length = namelen; + xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val); + xiocb.plist.xiocb_envbuf.val_length = vallen; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} +#endif /* CFE_API_enumenv || CFE_API_ALL */ + +#if defined(CFE_API_enummem) || defined(CFE_API_ALL) +int +cfe_enummem(int idx, int flags, cfe_xuint_t *start, cfe_xuint_t *length, + cfe_xuint_t *type) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = flags; + xiocb.xiocb_psize = sizeof(xiocb_meminfo_t); + xiocb.plist.xiocb_meminfo.mi_idx = idx; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + + *start = xiocb.plist.xiocb_meminfo.mi_addr; + *length = xiocb.plist.xiocb_meminfo.mi_size; + *type = xiocb.plist.xiocb_meminfo.mi_type; + + return 0; +} +#endif /* CFE_API_enummem || CFE_API_ALL */ + +#if defined(CFE_API_exit) || defined(CFE_API_ALL) +int +cfe_exit(int warm, int status) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_RESTART; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0; + xiocb.xiocb_psize = sizeof(xiocb_exitstat_t); + xiocb.plist.xiocb_exitstat.status = status; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} +#endif /* CFE_API_exit || CFE_API_ALL */ + +#if defined(CFE_API_flushcache) || defined(CFE_API_ALL) +int +cfe_flushcache(int flg) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = flg; + xiocb.xiocb_psize = 0; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} +#endif /* CFE_API_flushcache || CFE_API_ALL */ + +#if defined(CFE_API_getdevinfo) || defined(CFE_API_ALL) +int +cfe_getdevinfo(char *name) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_GETINFO; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = 0; + xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name); + xiocb.plist.xiocb_buffer.buf_length = cfe_strlen(name); + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + return xiocb.plist.xiocb_buffer.buf_devflags; +} +#endif /* CFE_API_getdevinfo || CFE_API_ALL */ + +#if defined(CFE_API_getenv) || defined(CFE_API_ALL) +int +cfe_getenv(char *name, char *dest, int destlen) +{ + cfe_xiocb_t xiocb; + + *dest = 0; + + xiocb.xiocb_fcode = CFE_CMD_ENV_GET; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); + xiocb.plist.xiocb_envbuf.enum_idx = 0; + xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name); + xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name); + xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(dest); + xiocb.plist.xiocb_envbuf.val_length = destlen; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} +#endif /* CFE_API_getenv || CFE_API_ALL */ + +#if defined(CFE_API_getfwinfo) || defined(CFE_API_ALL) +int +cfe_getfwinfo(cfe_fwinfo_t *info) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_GETINFO; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_fwinfo_t); + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + + info->fwi_version = xiocb.plist.xiocb_fwinfo.fwi_version; + info->fwi_totalmem = xiocb.plist.xiocb_fwinfo.fwi_totalmem; + info->fwi_flags = xiocb.plist.xiocb_fwinfo.fwi_flags; + info->fwi_boardid = xiocb.plist.xiocb_fwinfo.fwi_boardid; + info->fwi_bootarea_va = xiocb.plist.xiocb_fwinfo.fwi_bootarea_va; + info->fwi_bootarea_pa = xiocb.plist.xiocb_fwinfo.fwi_bootarea_pa; + info->fwi_bootarea_size = xiocb.plist.xiocb_fwinfo.fwi_bootarea_size; +#if 0 + info->fwi_reserved1 = xiocb.plist.xiocb_fwinfo.fwi_reserved1; + info->fwi_reserved2 = xiocb.plist.xiocb_fwinfo.fwi_reserved2; + info->fwi_reserved3 = xiocb.plist.xiocb_fwinfo.fwi_reserved3; +#endif + + return 0; +} +#endif /* CFE_API_getfwinfo || CFE_API_ALL */ + +#if defined(CFE_API_getstdhandle) || defined(CFE_API_ALL) +int +cfe_getstdhandle(int flg) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = flg; + xiocb.xiocb_psize = 0; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + return xiocb.xiocb_handle; + +} +#endif /* CFE_API_getstdhandle || CFE_API_ALL */ + +#if defined(CFE_API_getticks) || defined(CFE_API_ALL) +int64_t +#ifdef CFE_API_IMPL_NAMESPACE +__cfe_getticks(void) +#else +cfe_getticks(void) +#endif +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_time_t); + xiocb.plist.xiocb_time.ticks = 0; + + cfe_iocb_dispatch(&xiocb); + + return xiocb.plist.xiocb_time.ticks; + +} +#endif /* CFE_API_getticks || CFE_API_ALL */ + +#if defined(CFE_API_inpstat) || defined(CFE_API_ALL) +int +cfe_inpstat(int handle) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_inpstat_t); + xiocb.plist.xiocb_inpstat.inp_status = 0; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + return xiocb.plist.xiocb_inpstat.inp_status; + +} +#endif /* CFE_API_inpstat || CFE_API_ALL */ + +#if defined(CFE_API_ioctl) || defined(CFE_API_ALL) +int +cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer, int length, + int *retlen, cfe_xuint_t offset) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = offset; + xiocb.plist.xiocb_buffer.buf_ioctlcmd = ioctlnum; + xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer); + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + if (retlen) + *retlen = xiocb.plist.xiocb_buffer.buf_retlen; + return xiocb.xiocb_status; +} +#endif /* CFE_API_ioctl || CFE_API_ALL */ + +#if defined(CFE_API_open) || defined(CFE_API_ALL) +int +cfe_open(char *name) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = 0; + xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name); + xiocb.plist.xiocb_buffer.buf_length = cfe_strlen(name); + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + return xiocb.xiocb_handle; +} +#endif /* CFE_API_open || CFE_API_ALL */ + +#if defined(CFE_API_read) || defined(CFE_API_ALL) +int +cfe_read(int handle, unsigned char *buffer, int length) +{ + return cfe_readblk(handle, 0, buffer, length); +} +#endif /* CFE_API_read || CFE_API_ALL */ + +#if defined(CFE_API_readblk) || defined(CFE_API_ALL) +int +cfe_readblk(int handle, cfe_xint_t offset, unsigned char *buffer, int length) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_READ; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = offset; + xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer); + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + return xiocb.plist.xiocb_buffer.buf_retlen; +} +#endif /* CFE_API_readblk || CFE_API_ALL */ + +#if defined(CFE_API_setenv) || defined(CFE_API_ALL) +int +cfe_setenv(char *name, char *val) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_ENV_SET; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = 0; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_envbuf_t); + xiocb.plist.xiocb_envbuf.enum_idx = 0; + xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name); + xiocb.plist.xiocb_envbuf.name_length = cfe_strlen(name); + xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val); + xiocb.plist.xiocb_envbuf.val_length = cfe_strlen(val); + + cfe_iocb_dispatch(&xiocb); + + return xiocb.xiocb_status; +} +#endif /* CFE_API_setenv || CFE_API_ALL */ + +#if (defined(CFE_API_strlen) || defined(CFE_API_ALL)) \ + && !defined(CFE_API_STRLEN_CUSTOM) +int +cfe_strlen(char *name) +{ + int count = 0; + + while (*name++) + count++; + + return count; +} +#endif /* CFE_API_strlen || CFE_API_ALL */ + +#if defined(CFE_API_write) || defined(CFE_API_ALL) +int +cfe_write(int handle, unsigned char *buffer, int length) +{ + return cfe_writeblk(handle, 0, buffer, length); +} +#endif /* CFE_API_write || CFE_API_ALL */ + +#if defined(CFE_API_writeblk) || defined(CFE_API_ALL) +int +cfe_writeblk(int handle, cfe_xint_t offset, unsigned char *buffer, int length) +{ + cfe_xiocb_t xiocb; + + xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE; + xiocb.xiocb_status = 0; + xiocb.xiocb_handle = handle; + xiocb.xiocb_flags = 0; + xiocb.xiocb_psize = sizeof(xiocb_buffer_t); + xiocb.plist.xiocb_buffer.buf_offset = offset; + xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer); + xiocb.plist.xiocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&xiocb); + + if (xiocb.xiocb_status < 0) + return xiocb.xiocb_status; + return xiocb.plist.xiocb_buffer.buf_retlen; +} +#endif /* CFE_API_writeblk || CFE_API_ALL */ diff --git a/cfe/cfe/api/cfe_api.h b/cfe/cfe/api/cfe_api.h new file mode 100644 index 0000000..ea598f0 --- /dev/null +++ b/cfe/cfe/api/cfe_api.h @@ -0,0 +1,192 @@ +/* $Id: cfe_api.h,v 1.30 2003/02/07 17:27:56 cgd Exp $ */ + +/* + * Copyright 2000, 2001, 2002 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and copied only + * in accordance with the following terms and conditions. Subject to these + * conditions, you may download, copy, install, use, modify and distribute + * modified or unmodified copies of this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce and + * retain this copyright notice and list of conditions as they appear in + * the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Broadcom Corporation. The "Broadcom Corporation" name may not be + * used to endorse or promote products derived from this software + * without the prior written permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE + * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* ********************************************************************* + * + * Broadcom Common Firmware Environment (CFE) + * + * Device function prototypes File: cfe_api.h + * + * This file contains declarations for doing callbacks to + * cfe from an application. It should be the only header + * needed by the application to use this library + * + * Authors: Mitch Lichtenberg, Chris Demetriou + * + ********************************************************************* */ + +#ifndef CFE_API_H +#define CFE_API_H + +/* + * Apply customizations here for different OSes. These need to: + * * typedef uint64_t, int64_t, intptr_t, uintptr_t. + * * define cfe_strlen() if use of an existing function is desired. + * * define CFE_API_IMPL_NAMESPACE if API functions are to use + * names in the implementation namespace. + * Also, optionally, if the build environment does not do so automatically, + * CFE_API_* can be defined here as desired. + */ +/* Begin customization. */ +#include "lib_types.h" +/* End customization. */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* Seal indicating CFE's presence, passed to user program. */ +#define CFE_EPTSEAL 0x43464531 + +#define CFE_MI_RESERVED 0 /* memory is reserved, do not use */ +#define CFE_MI_AVAILABLE 1 /* memory is available */ + +#define CFE_FLG_WARMSTART 0x00000001 +#define CFE_FLG_FULL_ARENA 0x00000001 +#define CFE_FLG_ENV_PERMANENT 0x00000001 + +#define CFE_CPU_CMD_START 1 +#define CFE_CPU_CMD_STOP 0 + +#define CFE_STDHANDLE_CONSOLE 0 + +#define CFE_DEV_NETWORK 1 +#define CFE_DEV_DISK 2 +#define CFE_DEV_FLASH 3 +#define CFE_DEV_SERIAL 4 +#define CFE_DEV_CPU 5 +#define CFE_DEV_NVRAM 6 +#define CFE_DEV_CLOCK 7 +#define CFE_DEV_OTHER 8 +#define CFE_DEV_MASK 0x0F + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 + +#define CFE_FWI_64BIT 0x00000001 +#define CFE_FWI_32BIT 0x00000002 +#define CFE_FWI_RELOC 0x00000004 +#define CFE_FWI_UNCACHED 0x00000008 +#define CFE_FWI_MULTICPU 0x00000010 +#define CFE_FWI_FUNCSIM 0x00000020 +#define CFE_FWI_RTLSIM 0x00000040 + +typedef struct { + int64_t fwi_version; /* major, minor, eco version */ + int64_t fwi_totalmem; /* total installed mem */ + int64_t fwi_flags; /* various flags */ + int64_t fwi_boardid; /* board ID */ + int64_t fwi_bootarea_va; /* VA of boot area */ + int64_t fwi_bootarea_pa; /* PA of boot area */ + int64_t fwi_bootarea_size; /* size of boot area */ +} cfe_fwinfo_t; + + +/* + * cfe_strlen is handled specially: If already defined, it has been + * overridden in this environment with a standard strlen-like function. + */ +#ifdef cfe_strlen +# define CFE_API_STRLEN_CUSTOM +#else +# ifdef CFE_API_IMPL_NAMESPACE +# define cfe_strlen(a) __cfe_strlen(a) +# endif +int cfe_strlen(char *name); +#endif + +/* + * Defines and prototypes for functions which take no arguments. + */ +#ifdef CFE_API_IMPL_NAMESPACE +int64_t __cfe_getticks(void); +#define cfe_getticks() __cfe_getticks() +#else +int64_t cfe_getticks(void); +#endif + +/* + * Defines and prototypes for the rest of the functions. + */ +#ifdef CFE_API_IMPL_NAMESPACE +#define cfe_close(a) __cfe_close(a) +#define cfe_cpu_start(a,b,c,d,e) __cfe_cpu_start(a,b,c,d,e) +#define cfe_cpu_stop(a) __cfe_cpu_stop(a) +#define cfe_enumenv(a,b,d,e,f) __cfe_enumenv(a,b,d,e,f) +#define cfe_enummem(a,b,c,d,e) __cfe_enummem(a,b,c,d,e) +#define cfe_exit(a,b) __cfe_exit(a,b) +#define cfe_flushcache(a) __cfe_cacheflush(a) +#define cfe_getdevinfo(a) __cfe_getdevinfo(a) +#define cfe_getenv(a,b,c) __cfe_getenv(a,b,c) +#define cfe_getfwinfo(a) __cfe_getfwinfo(a) +#define cfe_getstdhandle(a) __cfe_getstdhandle(a) +#define cfe_init(a,b) __cfe_init(a,b) +#define cfe_inpstat(a) __cfe_inpstat(a) +#define cfe_ioctl(a,b,c,d,e,f) __cfe_ioctl(a,b,c,d,e,f) +#define cfe_open(a) __cfe_open(a) +#define cfe_read(a,b,c) __cfe_read(a,b,c) +#define cfe_readblk(a,b,c,d) __cfe_readblk(a,b,c,d) +#define cfe_setenv(a,b) __cfe_setenv(a,b) +#define cfe_write(a,b,c) __cfe_write(a,b,c) +#define cfe_writeblk(a,b,c,d) __cfe_writeblk(a,b,c,d) +#endif /* CFE_API_IMPL_NAMESPACE */ + +int cfe_close(int handle); +int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1); +int cfe_cpu_stop(int cpu); +int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen); +int cfe_enummem(int idx, int flags, uint64_t *start, uint64_t *length, + uint64_t *type); +int cfe_exit(int warm,int status); +int cfe_flushcache(int flg); +int cfe_getdevinfo(char *name); +int cfe_getenv(char *name, char *dest, int destlen); +int cfe_getfwinfo(cfe_fwinfo_t *info); +int cfe_getstdhandle(int flg); +int cfe_init(uint64_t handle,uint64_t ept); +int cfe_inpstat(int handle); +int cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer, + int length, int *retlen, uint64_t offset); +int cfe_open(char *name); +int cfe_read(int handle, unsigned char *buffer, int length); +int cfe_readblk(int handle, int64_t offset, unsigned char *buffer, int length); +int cfe_setenv(char *name, char *val); +int cfe_write(int handle, unsigned char *buffer, int length); +int cfe_writeblk(int handle, int64_t offset, unsigned char *buffer, + int length); + +#endif /* CFE_API_H */ diff --git a/cfe/cfe/api/cfe_api_int.h b/cfe/cfe/api/cfe_api_int.h new file mode 100644 index 0000000..4bac86d --- /dev/null +++ b/cfe/cfe/api/cfe_api_int.h @@ -0,0 +1,168 @@ +/* $Id: cfe_api_int.h,v 1.22 2003/02/07 17:27:56 cgd Exp $ */ + +/* + * Copyright 2000, 2001, 2002 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and copied only + * in accordance with the following terms and conditions. Subject to these + * conditions, you may download, copy, install, use, modify and distribute + * modified or unmodified copies of this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce and + * retain this copyright notice and list of conditions as they appear in + * the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Broadcom Corporation. The "Broadcom Corporation" name may not be + * used to endorse or promote products derived from this software + * without the prior written permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE + * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* ********************************************************************* + * + * Broadcom Common Firmware Environment (CFE) + * + * Device function prototypes File: cfe_api_int.h + * + * This header defines all internal types and macros for the + * library. This is stuff that's not exported to an app + * using the library. + * + * Authors: Mitch Lichtenberg, Chris Demetriou + * + ********************************************************************* */ + +#ifndef CFE_API_INT_H +#define CFE_API_INT_H + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_CMD_FW_GETINFO 0 +#define CFE_CMD_FW_RESTART 1 +#define CFE_CMD_FW_BOOT 2 +#define CFE_CMD_FW_CPUCTL 3 +#define CFE_CMD_FW_GETTIME 4 +#define CFE_CMD_FW_MEMENUM 5 +#define CFE_CMD_FW_FLUSHCACHE 6 + +#define CFE_CMD_DEV_GETHANDLE 9 +#define CFE_CMD_DEV_ENUM 10 +#define CFE_CMD_DEV_OPEN 11 +#define CFE_CMD_DEV_INPSTAT 12 +#define CFE_CMD_DEV_READ 13 +#define CFE_CMD_DEV_WRITE 14 +#define CFE_CMD_DEV_IOCTL 15 +#define CFE_CMD_DEV_CLOSE 16 +#define CFE_CMD_DEV_GETINFO 17 + +#define CFE_CMD_ENV_ENUM 20 +#define CFE_CMD_ENV_GET 22 +#define CFE_CMD_ENV_SET 23 +#define CFE_CMD_ENV_DEL 24 + +#define CFE_CMD_MAX 32 + +#define CFE_CMD_VENDOR_USE 0x8000 /* codes above this are for customer use */ + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef uint64_t cfe_xuint_t; +typedef int64_t cfe_xint_t; +typedef int64_t cfe_xptr_t; + +typedef struct xiocb_buffer_s { + cfe_xuint_t buf_offset; /* offset on device (bytes) */ + cfe_xptr_t buf_ptr; /* pointer to a buffer */ + cfe_xuint_t buf_length; /* length of this buffer */ + cfe_xuint_t buf_retlen; /* returned length (for read ops) */ + cfe_xuint_t buf_ioctlcmd; /* IOCTL command (used only for IOCTLs) */ +} xiocb_buffer_t; + +#define buf_devflags buf_ioctlcmd /* returned device info flags */ + +typedef struct xiocb_inpstat_s { + cfe_xuint_t inp_status; /* 1 means input available */ +} xiocb_inpstat_t; + +typedef struct xiocb_envbuf_s { + cfe_xint_t enum_idx; /* 0-based enumeration index */ + cfe_xptr_t name_ptr; /* name string buffer */ + cfe_xint_t name_length; /* size of name buffer */ + cfe_xptr_t val_ptr; /* value string buffer */ + cfe_xint_t val_length; /* size of value string buffer */ +} xiocb_envbuf_t; + +typedef struct xiocb_cpuctl_s { + cfe_xuint_t cpu_number; /* cpu number to control */ + cfe_xuint_t cpu_command; /* command to issue to CPU */ + cfe_xuint_t start_addr; /* CPU start address */ + cfe_xuint_t gp_val; /* starting GP value */ + cfe_xuint_t sp_val; /* starting SP value */ + cfe_xuint_t a1_val; /* starting A1 value */ +} xiocb_cpuctl_t; + +typedef struct xiocb_time_s { + cfe_xint_t ticks; /* current time in ticks */ +} xiocb_time_t; + +typedef struct xiocb_exitstat_s { + cfe_xint_t status; +} xiocb_exitstat_t; + +typedef struct xiocb_meminfo_s { + cfe_xint_t mi_idx; /* 0-based enumeration index */ + cfe_xint_t mi_type; /* type of memory block */ + cfe_xuint_t mi_addr; /* physical start address */ + cfe_xuint_t mi_size; /* block size */ +} xiocb_meminfo_t; + +typedef struct xiocb_fwinfo_s { + cfe_xint_t fwi_version; /* major, minor, eco version */ + cfe_xint_t fwi_totalmem; /* total installed mem */ + cfe_xint_t fwi_flags; /* various flags */ + cfe_xint_t fwi_boardid; /* board ID */ + cfe_xint_t fwi_bootarea_va; /* VA of boot area */ + cfe_xint_t fwi_bootarea_pa; /* PA of boot area */ + cfe_xint_t fwi_bootarea_size; /* size of boot area */ + cfe_xint_t fwi_reserved1; + cfe_xint_t fwi_reserved2; + cfe_xint_t fwi_reserved3; +} xiocb_fwinfo_t; + +typedef struct cfe_xiocb_s { + cfe_xuint_t xiocb_fcode; /* IOCB function code */ + cfe_xint_t xiocb_status; /* return status */ + cfe_xint_t xiocb_handle; /* file/device handle */ + cfe_xuint_t xiocb_flags; /* flags for this IOCB */ + cfe_xuint_t xiocb_psize; /* size of parameter list */ + union { + xiocb_buffer_t xiocb_buffer; /* buffer parameters */ + xiocb_inpstat_t xiocb_inpstat; /* input status parameters */ + xiocb_envbuf_t xiocb_envbuf; /* environment function parameters */ + xiocb_cpuctl_t xiocb_cpuctl; /* CPU control parameters */ + xiocb_time_t xiocb_time; /* timer parameters */ + xiocb_meminfo_t xiocb_meminfo; /* memory arena info parameters */ + xiocb_fwinfo_t xiocb_fwinfo; /* firmware information */ + xiocb_exitstat_t xiocb_exitstat; /* Exit Status */ + } plist; +} cfe_xiocb_t; + +#endif /* CFE_API_INT_H */ diff --git a/cfe/cfe/api/cfe_error.h b/cfe/cfe/api/cfe_error.h new file mode 100644 index 0000000..6301c56 --- /dev/null +++ b/cfe/cfe/api/cfe_error.h @@ -0,0 +1,101 @@ +/* $Id: cfe_error.h,v 1.3 2003/02/07 17:27:56 cgd Exp $ */ + +/* + * Copyright 2000, 2001, 2002 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and copied only + * in accordance with the following terms and conditions. Subject to these + * conditions, you may download, copy, install, use, modify and distribute + * modified or unmodified copies of this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce and + * retain this copyright notice and list of conditions as they appear in + * the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Broadcom Corporation. The "Broadcom Corporation" name may not be + * used to endorse or promote products derived from this software + * without the prior written permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE + * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* ********************************************************************* + * + * Broadcom Common Firmware Environment (CFE) + * + * Error codes File: cfe_error.h + * + * CFE's global error code list is here. + * + * Author: Mitch Lichtenberg + * + ********************************************************************* */ + + +#define CFE_OK 0 +#define CFE_ERR -1 /* generic error */ +#define CFE_ERR_INV_COMMAND -2 +#define CFE_ERR_EOF -3 +#define CFE_ERR_IOERR -4 +#define CFE_ERR_NOMEM -5 +#define CFE_ERR_DEVNOTFOUND -6 +#define CFE_ERR_DEVOPEN -7 +#define CFE_ERR_INV_PARAM -8 +#define CFE_ERR_ENVNOTFOUND -9 +#define CFE_ERR_ENVREADONLY -10 + +#define CFE_ERR_NOTELF -11 +#define CFE_ERR_NOT32BIT -12 +#define CFE_ERR_WRONGENDIAN -13 +#define CFE_ERR_BADELFVERS -14 +#define CFE_ERR_NOTMIPS -15 +#define CFE_ERR_BADELFFMT -16 +#define CFE_ERR_BADADDR -17 + +#define CFE_ERR_FILENOTFOUND -18 +#define CFE_ERR_UNSUPPORTED -19 + +#define CFE_ERR_HOSTUNKNOWN -20 + +#define CFE_ERR_TIMEOUT -21 + +#define CFE_ERR_PROTOCOLERR -22 + +#define CFE_ERR_NETDOWN -23 +#define CFE_ERR_NONAMESERVER -24 + +#define CFE_ERR_NOHANDLES -25 +#define CFE_ERR_ALREADYBOUND -26 + +#define CFE_ERR_CANNOTSET -27 +#define CFE_ERR_NOMORE -28 +#define CFE_ERR_BADFILESYS -29 +#define CFE_ERR_FSNOTAVAIL -30 + +#define CFE_ERR_INVBOOTBLOCK -31 +#define CFE_ERR_WRONGDEVTYPE -32 +#define CFE_ERR_BBCHECKSUM -33 +#define CFE_ERR_BOOTPROGCHKSUM -34 + +#define CFE_ERR_LDRNOTAVAIL -35 + +#define CFE_ERR_NOTREADY -36 + +#define CFE_ERR_GETMEM -37 +#define CFE_ERR_SETMEM -38 + +#define CFE_ERR_NOTCONN -39 +#define CFE_ERR_ADDRINUSE -40 diff --git a/cfe/cfe/applets/Makefile b/cfe/cfe/applets/Makefile new file mode 100644 index 0000000..42e1e4f --- /dev/null +++ b/cfe/cfe/applets/Makefile @@ -0,0 +1,64 @@ + +CFG_MLONG64=0 + +CFE_DIRS = ../include ../arch/mips/cpu/sb1250/include ../lib ../verif ../api +CFE_INCLUDES = $(patsubst %,-I%,$(subst :, ,$(CFE_DIRS))) + +VPATH = $(CFE_DIRS) + +INCLUDES = -I. $(CFE_INCLUDES) +COMFLAGS = -g -c -mcpu=sb1 -ffreestanding +CFLAGS = $(INCLUDES) $(COMFLAGS) -O -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -G 0 -DCFE_API_ALL + +GCC = $(TOOLS)sb1-elf-gcc +GLD = $(TOOLS)sb1-elf-ld +OBJCOPY = $(TOOLS)sb1-elf-objcopy + +ifeq (${CFG_MLONG64},1) +CFLAGS += -mlong64 -D__long64 +endif + +LDFLAGS = --script cfe_applet.lds -g + +ifeq (CFG_LITTLE,1) +CFLAGS += -EL +LDFLAGS += -EL +else +CFLAGS += -EB +LDFLAGS += -EB +endif + + +%.o : %.c + $(GCC) $(CFLAGS) -o $@ $< + +%.o : %.S + $(GCC) $(CFLAGS) -o $@ $< + + +LIBOBJS = lib_printf.o lib_string.o cfe_api.o + +all : test vapitest + echo done + +test : test.o minicrt0.o $(LIBOBJS) + $(GLD) -o test.elfraw -Map test.mapraw $(LDFLAGS) minicrt0.o test.o $(LIBOBJS) + $(GLD) -o test.elf -Ttext 0x20000000 -Map test.map $(LDFLAGS) minicrt0.o test.o $(LIBOBJS) + $(OBJCOPY) -O binary test.elfraw test + $(OBJCOPY) -O srec test.elfraw test.srec + +download : download.o minicrt0.o $(LIBOBJS) + $(GLD) -o download.elf -Ttext 0x80001000 -Map download.map $(LDFLAGS) minicrt0.o download.o $(LIBOBJS) + $(OBJCOPY) --strip-unneeded download.elf s.download.elf + gzip --best -c s.download.elf > download.elf.gz + $(GLD) -Tdownload.lds -bbinary -o download.data download.elf.gz + +vapitest : vapitest.o + $(GLD) -o vapitest -Ttext 0x80020000 -Map vapitest.map vapitest.o + $(OBJCOPY) -O srec vapitest vapitest.srec + +clean : + rm -f *.o *~ *.map *.mapraw + rm -f test test.elf test.srec test.elfraw + rm -f *download.elf *.gz + rm -f vapitest vapitest.srec diff --git a/cfe/cfe/applets/README b/cfe/cfe/applets/README new file mode 100644 index 0000000..b622997 --- /dev/null +++ b/cfe/cfe/applets/README @@ -0,0 +1,21 @@ + +This directory contains "applets" - simple programs to let +us test the callbacks into CFE. + +You should be able to compile these programs and load them +via the TFTP loader in CFE, and when run, they will call +the APIs in CFE to display messages and such. + +The files cfe_api.c, cfe_api.h, and cfe_api_int.h are versions +of the same files from ../applets, customized to build with this +stand-alone build environment. Typically you won't want to copy +these. Instead, you'll want to copy the versions in ../applets and +customize them as needed. + +Pay particular attention to the MIPS calling conventions +you are using. In particular, CFE uses 64-bit register +values. If you compile your program with -mips1 or -mips2, +the 64-bit arguments will be passed as 2 32-bt registers. + +In most cases, CFE only uses the lower 32 bits, since +it can be called from either 32 or 64-bit applications. diff --git a/cfe/cfe/applets/cfe_applet.lds b/cfe/cfe/applets/cfe_applet.lds new file mode 100644 index 0000000..e1b33e9 --- /dev/null +++ b/cfe/cfe/applets/cfe_applet.lds @@ -0,0 +1,37 @@ +OUTPUT_ARCH(mips) +ENTRY(__start) +SECTIONS +{ + . = 0x20000000; +/* . = 0x81000000; */ + .text : + { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + *(.fini) + *(.rodata) + _etext = .; + } + + .data : + { + _gp = ALIGN(16) + 0x8000; + _fdata = . ; + *(.data) + CONSTRUCTORS + *(.sdata) + } + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + _end = .; +} diff --git a/cfe/cfe/applets/download.c b/cfe/cfe/applets/download.c new file mode 100644 index 0000000..911c649 --- /dev/null +++ b/cfe/cfe/applets/download.c @@ -0,0 +1,163 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Null device mode driver File: download.c + * + * Small program (placeholder) to download to a 1250 in PCI Device Mode + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_api.h" + +int conhandle; + + +void appletmain(long handle,long vector, + long reserved,long seal); + + + + +/* ********************************************************************* + * console_write(buffer,length) + * + * Write text to the console. If the console is not open and + * we're "saving" text, put the text on the in-memory queue + * + * Input parameters: + * buffer - pointer to data + * length - number of characters to write + * + * Return value: + * number of characters written or <0 if error + ********************************************************************* */ + +static int console_write(unsigned char *buffer,int length) +{ + int res; + + /* + * Do nothing if no console + */ + + if (conhandle == -1) return -1; + + /* + * Write text to device + */ + + for (;;) { + res = cfe_write(conhandle,buffer,length); + if (res < 0) break; + buffer += res; + length -= res; + if (length == 0) break; + } + + if (res < 0) return -1; + return 0; +} + + +/* ********************************************************************* + * console_xprint(str) + * + * printf callback for the console device. the "xprintf" + * routine ends up calling this. This routine also cooks the + * output, turning "\n" into "\r\n" + * + * Input parameters: + * str - string to write + * + * Return value: + * number of characters written + ********************************************************************* */ + +static int console_xprint(const char *str) +{ + int count = 0; + int len; + const char *p; + + /* Convert CR to CRLF as we write things out */ + + while ((p = strchr(str,'\n'))) { + console_write((char *) str,p-str); + console_write("\r\n",2); + count += (p-str); + str = p + 1; + } + + len = strlen(str); + console_write((char *) str, len); + count += len; + + return count; +} + + +void appletmain(long handle,long vector, + long ept,long seal) +{ + void (*reboot)(void) = (void *) (uintptr_t) (int) 0xBFC00000; + char str[100]; + + xprinthook = console_xprint; + + cfe_init(handle,ept); + + conhandle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); + + str[0] = 0; + cfe_getenv("BOOT_CONSOLE",str,sizeof(str)); + + xprintf("\nHello, world. Console = %s\n",str); + + xprintf("\nThis is a null device driver that just restarts CFE\n"); + xprintf("Rebuild the host's CFE to replace it with your driver.\n\n"); + + xprintf("Exiting to CFE\n\n"); + + cfe_exit(CFE_FLG_WARMSTART,0); + + (*reboot)(); +} diff --git a/cfe/cfe/applets/download.lds b/cfe/cfe/applets/download.lds new file mode 100644 index 0000000..7f6e6be --- /dev/null +++ b/cfe/cfe/applets/download.lds @@ -0,0 +1,12 @@ +OUTPUT_FORMAT("elf32-bigmips") +OUTPUT_ARCH("mipssb1") + +SECTIONS +{ + .rodata : + { + download_start = .; + *(.data); + download_end = .; + } +} diff --git a/cfe/cfe/applets/minicrt0.S b/cfe/cfe/applets/minicrt0.S new file mode 100644 index 0000000..937f240 --- /dev/null +++ b/cfe/cfe/applets/minicrt0.S @@ -0,0 +1,95 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Mini startup module for CFE apps File: minicrt0.S + * + * About the most minimal startup routine you can get. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" + +/* + * This module should be linked first! + */ + +#define STACK_SIZE 8192 + + .bss + .comm stack_bottom,STACK_SIZE + .comm __junk,4 + + .text + + .extern appletmain + .globl __start + +__start: + + /* + * Set up our GP (in case we're using it) + * Set up the stack pointer (don't use CFE's stack) + */ + + la gp,_gp + la sp,stack_bottom+STACK_SIZE-32 + + /* + * Zero BSS. No need to do this very efficiently, do it + * 32 bits at a time to ensure we can compile this + * with -mips1. + */ + + la t0,_fbss + la t1,_end + +1: sw zero,0(t0) + add t0,4 + blt t0,t1,1b + + /* + * Jump to main program. Note that we didn't trash A0..A3, + * our application will need them. So, if you add stuff here, + * be sure to preserve the A0..A3 registers for the C code. + */ + + j appletmain + diff --git a/cfe/cfe/applets/test.c b/cfe/cfe/applets/test.c new file mode 100644 index 0000000..9122456 --- /dev/null +++ b/cfe/cfe/applets/test.c @@ -0,0 +1,211 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * API test program File: test.c + * + * Small program to test CFE's external API + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_api.h" + +int conhandle; + + +void appletmain(unsigned long handle,unsigned long vector, + unsigned long reserved,unsigned long seal); + + + + +/* ********************************************************************* + * console_write(buffer,length) + * + * Write text to the console. If the console is not open and + * we're "saving" text, put the text on the in-memory queue + * + * Input parameters: + * buffer - pointer to data + * length - number of characters to write + * + * Return value: + * number of characters written or <0 if error + ********************************************************************* */ + +static int console_write(unsigned char *buffer,int length) +{ + int res; + + /* + * Do nothing if no console + */ + + if (conhandle == -1) return -1; + + /* + * Write text to device + */ + + for (;;) { + res = cfe_write(conhandle,buffer,length); + if (res < 0) break; + buffer += res; + length -= res; + if (length == 0) break; + } + + if (res < 0) return -1; + return 0; +} + + +/* ********************************************************************* + * console_xprint(str) + * + * printf callback for the console device. the "xprintf" + * routine ends up calling this. This routine also cooks the + * output, turning "\n" into "\r\n" + * + * Input parameters: + * str - string to write + * + * Return value: + * number of characters written + ********************************************************************* */ + +static int console_xprint(const char *str) +{ + int count = 0; + int len; + const char *p; + + /* Convert CR to CRLF as we write things out */ + + while ((p = strchr(str,'\n'))) { + console_write((char *) str,p-str); + console_write("\r\n",2); + count += (p-str); + str = p + 1; + } + + len = strlen(str); + console_write((char *) str, len); + count += len; + + return count; +} + + +#if 0 +static int myxprinthook(const char *str) +{ + int count = 0; + int len; + const char *p; + + /* Convert CR to CRLF as we write things out */ + + while ((p = strchr(str,'\r'))) { + cfe_write(conhandle,(char *) str,p-str+1); + cfe_write(conhandle,"\n",1); + count += (p-str); + str = p + 1; + } + + len = strlen(str); + cfe_write(conhandle,(char *) str, len); + count += len; + + return count; +} +#endif + +void appletmain(unsigned long handle,unsigned long vector, + unsigned long ept,unsigned long seal) +{ + void (*reboot)(void) = (void *) (uintptr_t) (int) 0xBFC00000; + char str[100]; + cfe_fwinfo_t info; + int idx; + int res; + uint64_t start,length,type; + + xprinthook = console_xprint; + + cfe_init(handle,ept); + + conhandle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE); + + str[0] = 0; + cfe_getenv("BOOT_CONSOLE",str,sizeof(str)); + + xprintf("Hello, world. Console = %s\n",str); + xprintf("API Seal = %08X\n",(int)seal); + xprintf("Entrypoint=%08X Handle=%08X\n",(int)ept,(int)handle); + idx = 0; + + cfe_getfwinfo(&info); + xprintf("CFE version: %08llX\n",info.fwi_version); + xprintf("Flags: %08llX\n",info.fwi_flags); + xprintf("Total memory: %08llX\n",info.fwi_totalmem); + xprintf("Board ID: %08llX\n",info.fwi_boardid); + xprintf("Bootarea VA: %08llX\n",info.fwi_bootarea_va); + xprintf("Bootarea PA: %08llX\n",info.fwi_bootarea_pa); + xprintf("Bootarea Size: %08llX\n",info.fwi_bootarea_size); + + xprintf("Memory map:\n"); + for (;;) { + if ((res = cfe_enummem(idx,1,&start,&length,&type) != 0)) break; + xprintf("Memory at %016llX length %016llX type %ld\n", + start,length,type); + idx++; + } + + xprintf("Exiting to CFE\n\n"); + + cfe_exit(CFE_FLG_WARMSTART,0); + + (*reboot)(); + +} diff --git a/cfe/cfe/applets/vapitest.S b/cfe/cfe/applets/vapitest.S new file mode 100644 index 0000000..a57a563 --- /dev/null +++ b/cfe/cfe/applets/vapitest.S @@ -0,0 +1,96 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Verification Test APIs File: vapitest.S + * + * This module contains special low-level routines for use + * by verification programs. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" + + +#include "vapi.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + .text + +LEAF(_start) + + VAPI_LOG_SETBUF(0x80030000,0x80040000) + + + VAPI_LOG_CONST(0x100,0xABCDEF) + VAPI_LOG_REG(0x101,sp) + VAPI_LOG_BUFFER(0x102,testbuf,10) + VAPI_PUTS("Hello world.\n") + VAPI_LOG_SOCSTATE(0x103,SOC_AGENT_DUART) + VAPI_PRINTGPRS(); + VAPI_LOG_CONST(0x1EE,0xEEEEEEEE) + VAPI_LOG_GPRS(0x199) + VAPI_SETLEDS('V','A','P','I') + + VAPI_EXIT_CONST(0) + + +END(_start) + +testbuf: .dword 0x123456789ABCDEF0 + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xFEDCBA9876543210 + + + +/* ********************************************************************* + * End + ********************************************************************* */ + + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm63xx_util.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm63xx_util.h new file mode 100755 index 0000000..273b9c7 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm63xx_util.h @@ -0,0 +1,167 @@ +/*************************************************************************** + * Broadcom Corp. Confidential + * Copyright 2001, 2002 Broadcom Corp. All Rights Reserved. + * + * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED + * SOFTWARE LICENSE AGREEMENT BETWEEN THE USER AND BROADCOM. + * YOU HAVE NO RIGHT TO USE OR EXPLOIT THIS MATERIAL EXCEPT + * SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. + * + *************************************************************************** + * File Name : bcm63xx_util.h + * + * Created on : 04/18/2002 seanl + ***************************************************************************/ + +#if !defined(_BCM63XX_UTIL_H_) +#define _BCM63XX_UTIL_H_ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_ioctl.h" +#include "cfe_error.h" +#include "env_subr.h" +#include "ui_command.h" +#include "cfe.h" +#include "net_ebuf.h" +#include "net_ether.h" +#include "net_api.h" +#include "cfe_fileops.h" +#include "bsp_config.h" +#include "cfe_mem.h" +#include "cfe_loader.h" +#include "addrspace.h" + +#include "dev_bcm63xx_flash.h" +#include "bcm_hwdefs.h" +#include "bcmTag.h" +#include "boardparms.h" +#include "boardparms_voice.h" +#include "bcm_map.h" + +extern unsigned long cfe_sdramsize; + +#define NAND_FLASH_BOOT_IMAGE_NAME "vmlinux.lz" + +#define BOARD_IMAGE_DOWNLOAD_ADDRESS \ + ((cfe_sdramsize > 0x00800000) ? 0x80800000 : 0x80000000) +#define BOARD_IMAGE_DOWNLOAD_SIZE \ + ((cfe_sdramsize > 0x00800000) ? cfe_sdramsize - 0x00800000 : 0x00400000) + +#define MAX_PROMPT_LEN 50 // assume no one wants to type more than 50 chars +#define MAX_MAC_STR_LEN 19 // mac address string 18+1 in regular format +#define PROMPT_DEFINE_LEN 2 +#define MASK_LEN 8 // vxworks like ffffff00 + +typedef struct +{ + char* promptName; + char* errorPrompt; + char promptDefine[PROMPT_DEFINE_LEN]; + char parameter[MAX_PROMPT_LEN]; + int maxValueLength; + int (*func)(char *); + int enabled; +} PARAMETER_SETTING, *PPARAMETER_SETTING; + +#define IP_PROMPT "Invalid ip address. eg. 192.168.1.200[:ffffff00]" +#define RUN_FROM_PROMPT "f = jump to flash; h = tftpd from host" +#define HOST_FN_PROMPT "eg. vmlinux" +#define FLASH_FN_PROMPT "eg. bcm963xx_fs_kernel" +#define BOOT_DELAY_PROMPT "range 0-9, 0=forever prompt" +#define BOOT_PARTITION_PROMPT "1 = latest image, 2 = previous image" +#define AFE_PROMPT "Invalid AFE ID eg. 0x10608100" + +// error input prompts +#define BOARDID_STR_PROMPT "Invalid board ID" +#define MAC_CT_PROMPT "Invalid MAC addresses number: 1 - 32" +#define MAC_ADDR_PROMPT "Invalid MAC address format: eg. 12:34:56:ab:cd:ef or 123456abcdef" +#define PSI_SIZE_PROMPT "Invalid PSI size: (1-64) Kbytes" +#define BACKUP_PSI_PROMPT "Enable Backup PSI (0 or 1)" +#define SYSLOG_SIZE_PROMPT "Invalid System Log size: (0-256) Kbytes" +#define CPU_TP_PROMPT "Invalid thread number: [0|1]" +#define GPON_SN_PROMPT "Invalid GPON Serial Number" +#define GPON_PW_PROMPT "Invalid GPON Password" +#define WPS_DEVICE_PIN_PROMPT "Invalid WPS Device Pin" + +// bootline definition: +// Space is the deliminator of the parameters. Currently supports following parameters: +// t=xxx.xxx.xxx.xxx h=xxx.xxx.xxx.xxx g=xxx.xxx.xxx.xxx r=f/h (run from flash or host) +// f=vmlinux (if r=h) i=bcm963xx_fs_kernel d=3 (default delay, range 0-9, 0=forever prompt) + +#define BOOT_IP_LEN 18 // "t=xxx.xxx.xxx.xxx" +#define BOOT_FILENAME_LEN 50 // "f=vmlinux" + +typedef struct +{ + char boardIp[BOOT_IP_LEN]; + char boardMask[BOOT_IP_LEN]; // set for the board only and ignore for the host/gw. fmt :ffffff00 + char hostIp[BOOT_IP_LEN]; + char gatewayIp[BOOT_IP_LEN]; + char runFrom; + char hostFileName[BOOT_FILENAME_LEN]; + char flashFileName[BOOT_FILENAME_LEN]; + int bootDelay; + char bootPartition; +} BOOT_INFO, *PBOOT_INFO; + +#define LED_OFF 0 +#define LED_ON 1 + +extern void getBootLine(void); +extern void setDefaultBootline(void); +extern int printSysInfo(void); +extern int changeBootLine(void); +extern int changeAfeId(void); +extern void dumpHex(unsigned char *start, int len); +extern BOOT_INFO bootInfo; +extern void enet_init(void); +extern int verifyTag(PFILE_TAG pTag, int verbose); +extern int flashImage(unsigned char *ptr); +extern int writeWholeImage(unsigned char *ptr, int size); + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +extern int bcm63xx_run(int breakIntoCfe); +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +extern int getPartitionFromTag( PFILE_TAG pTag ); +extern PFILE_TAG getTagFromPartition(int imageNumber); +extern PFILE_TAG getBootImageTag(void); +extern int parsexdigit(char str); +extern int setDefaultBoardParam(void); /* Bob added to set default board parameters, 11/01/2010 */ +extern int setBoardParam(void); +extern int setGponBoardParam(void); +extern int setWpsDevicePinBoardParam(void); +extern int setVoiceBoardParam(void); +extern int getBoardParam(void); +extern void displayBoardParam(void); +extern int processPrompt(PPARAMETER_SETTING promptPtr, int promptCt); +extern UINT32 getCrc32(unsigned char *pdata, UINT32 size, UINT32 crc); +extern int yesno(void); +extern int bcm63xx_cfe_rawload(cfe_loadargs_t *la); +extern int bcm63xx_cfe_elfload(cfe_loadargs_t *la); +extern void setGpio (unsigned short led_gpio, unsigned short led_state); +extern void setLed ( unsigned short led, unsigned short led_state ); +extern void setAllLedsOff(void); +extern void setPowerOnLedOn(void); +extern void setBreakIntoCfeLed(void); +extern void softReset(void); +extern void validateNandPartTbl(PNVRAM_DATA pNvramData); +extern void writeNvramData(PNVRAM_DATA pNvramData); +extern int readNvramData(PNVRAM_DATA pNvramData); + +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ +extern int nmrp_led_toggle(void); +extern int power_led_toggle(int state); +extern int verify_board_id(char *buf); +/* Foxconn add end by Jenny Zhao, 07/02/2008*/ +#endif // _BCM63XX_UTIL_H_ + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_common.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_common.h new file mode 100755 index 0000000..136267a --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_common.h @@ -0,0 +1,32 @@ +/* +<:copyright-broadcom + + Copyright (c) 2004 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ +#ifndef __BCM_COMMON_H +#define __BCM_COMMON_H + +#if defined (_BCM96328_) +#include "6328_common.h" +#endif +#if defined (_BCM96362_) +#include "6362_common.h" +#endif +#if defined (_BCM96368_) +#include "6368_common.h" +#endif +#if defined (_BCM96816_) +#include "6816_common.h" +#endif + +#endif diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_cpu.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_cpu.h new file mode 100755 index 0000000..e033936 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_cpu.h @@ -0,0 +1,32 @@ +/* +<:copyright-broadcom + + Copyright (c) 2004 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ +#ifndef __BCM_CPU_H +#define __BCM_CPU_H + +#if defined (_BCM96328_) +#include "6328_cpu.h" +#endif +#if defined (_BCM96362_) +#include "6362_cpu.h" +#endif +#if defined (_BCM96368_) +#include "6368_cpu.h" +#endif +#if defined (_BCM96816_) +#include "6816_cpu.h" +#endif + +#endif diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_map.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_map.h new file mode 100755 index 0000000..0383431 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcm_map.h @@ -0,0 +1,32 @@ +/* +<:copyright-broadcom + + Copyright (c) 2004 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ +#ifndef __BCM_MAP_H +#define __BCM_MAP_H + +#if defined (_BCM96328_) +#include "6328_map.h" +#endif +#if defined (_BCM96362_) +#include "6362_map.h" +#endif +#if defined (_BCM96368_) +#include "6368_map.h" +#endif +#if defined (_BCM96816_) +#include "6816_map.h" +#endif + +#endif diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmmii.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmmii.h new file mode 100755 index 0000000..a33de5c --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmmii.h @@ -0,0 +1,164 @@ +/* +<:copyright-broadcom + + Copyright (c) 2004 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ +#ifndef _BCMMII_H_ +#define _BCMMII_H_ + +#include "dev_bcm63xx_eth.h" + +/*---------------------------------------------------------------------*/ +/* Broadcom PHY MII register address */ +/* use when PhyType is BP_ENET_INTERNAL_PHY */ +/*---------------------------------------------------------------------*/ +#define BCM_PHY_ID_M 0x1F +#define IsExtPhyId(id) ((id & BCM_PHY_ID_M) >= 0x10) +//#define BCM_WAN_PORT 0x40 +//#define IsWanPort(id) (((id) & BCM_WAN_PORT) && ((id) != 0xFF)) + +#define MII_ASR 0x19 +#define MII_INTERRUPT 0x1A +#define MII_RESERVED_1B 0x1B +#define MII_BRCM_TEST 0x1F + +/* MII ASR register. */ +#define MII_ASR_DONE(r) ((r & 0x8000) != 0) +#define MII_ASR_LINK(r) ((r & 0x0004) != 0) +#define MII_ASR_FDX(r) (((r & 0x0700) == 0x0700) || ((r & 0x0700) == 0x0500) || ((r & 0x0700) == 0x0200)) +#define MII_ASR_1000(r) (((r & 0x0700) == 0x0700) || ((r & 0x0700) == 0x0600)) +#define MII_ASR_100(r) (((r & 0x0700) == 0x0500) || ((r & 0x0700) == 0x0300)) +#define MII_ASR_10(r) (((r & 0x0700) == 0x0200) || ((r & 0x0700) == 0x0100)) + +/* Reserved 0x1B register */ +#define MII_RESERVED_1B_ACT_LED 0x0004 + +/* Broadcom Test register. */ +#define MII_BRCM_TEST_SHADOW2_ENABLE 0x0004 + +/* MII Interrupt register. */ +#define MII_INTR_ENABLE 0x4000 + +#define BCM54610_PHYID2 0xBD63 +#define BCM_PHYID_M 0xFFF0 + +#define MII_REGISTER_1C 0x1c + #define MII_1C_WRITE_ENABLE (1 << 15) + #define MII_1C_SHADOW_REG_SEL_S 10 + #define MII_1C_SHADOW_REG_SEL_M 0x1F +#define MII_1C_SHADOW_CLK_ALIGN_CTRL 0x3 + #define GTXCLK_DELAY_BYPASS_DISABLE (1 << 9) +#define MII_1C_SHADOW_LED_CONTROL 0x9 + #define ACT_LINK_LED_ENABLE (1 << 4) +#define MII_1C_EXTERNAL_CONTROL_1 0xB + #define LOM_LED_MODE (1 << 2) + +#define PAGE_CONTROL 0x00 +#define PAGE_SELECT 0xff +#define PAGE_MANAGEMENT 0x02 + +/* Control page registers */ +#define REG_MII_PORT_CONTROL 0x08 +#define REG_SWITCH_MODE 0x0b +#define REG_CONTROL_MII1_PORT_STATE_OVERRIDE 0x0e +#define REG_POWER_DOWN_MODE 0x0f + +/* MII Port Control Register, Page 0x00 Address 0x08 */ +#define REG_MII_PORT_CONTROL_RX_UCST_EN 0x10 +#define REG_MII_PORT_CONTROL_RX_MCST_EN 0x08 +#define REG_MII_PORT_CONTROL_RX_BCST_EN 0x04 + +/* Switch mode register, Page 0x00 Address 0x0b */ +#define REG_SWITCH_MODE_FRAME_MANAGE_MODE 0x01 +#define REG_SWITCH_MODE_SW_FWDG_EN 0x02 + +/* MII1 Port State Override Register Page 0x00 Address 0x0e */ +#define REG_CONTROL_MPSO_MII_SW_OVERRIDE 0x80 +#define REG_CONTROL_MPSO_REVERSE_MII 0x10 +#define REG_CONTROL_MPSO_LP_FLOW_CONTROL 0x08 +#define REG_CONTROL_MPSO_SPEED100 0x04 +#define REG_CONTROL_MPSO_SPEED1000 0x08 +#define REG_CONTROL_MPSO_FDX 0x02 +#define REG_CONTROL_MPSO_LINKPASS 0x01 + +/* Power down mode register Page 0x00 Address 0x0f */ +#define REG_POWER_DOWN_MODE_PORT1_PHY_DISABLE 0x01 +#define REG_POWER_DOWN_MODE_PORT2_PHY_DISABLE 0x02 +#define REG_POWER_DOWN_MODE_PORT3_PHY_DISABLE 0x04 +#define REG_POWER_DOWN_MODE_PORT4_PHY_DISABLE 0x08 +#define REG_POWER_DOWN_MODE_PORT5_PHY_DISABLE 0x10 + +/* Switch control register page 0x0 */ +#define REG_SWITCH_CONTROL 0x20 +#define REG_SWITCH_CONTROL_MII_DUMP_FWD_EN 0x1 + +/* Device ID register page 0x02 */ +#define REG_DEVICE_ID 0x30 +#define REG_GLOBAL_CONFIG 0x00 +#define REG_BRCM_HDR_CTRL 0x03 + +/* Global Configuration Regiater Page 0x02 Address 0x00 */ +#define ENABLE_MII_PORT 0x80 + +/* Broadcom Header Control Register Page 0x02 Address 0x03*/ +#define REG_BRCM_HDR_ENABLE 0x01 + + + +/*---------------------------------------------------------------------*/ +/* 5325 Switch SPI Interface */ +/* use when configuration type is BP_ENET_CONFIG_SPI_SSB_x */ +/*---------------------------------------------------------------------*/ +#define BCM5325_SPI_CMD_LEN 1 +#define BCM5325_SPI_ADDR_LEN 1 +#define BCM5325_SPI_PREPENDCNT (BCM5325_SPI_CMD_LEN+BCM5325_SPI_ADDR_LEN) + +/* 5325 SPI Status Register */ +#define BCM5325_SPI_STS 0xfe + +/* 5325 SPI Status Register definition */ +#define BCM5325_SPI_CMD_RACK 0x20 + +/* 5325 Command Byte definition */ +#define BCM5325_SPI_CMD_READ 0x00 /* bit 0 - Read/Write */ +#define BCM5325_SPI_CMD_WRITE 0x01 /* bit 0 - Read/Write */ +#define BCM5325_SPI_CHIPID_MASK 0x7 /* bit 3:1 - Chip ID */ +#define BCM5325_SPI_CHIPID_SHIFT 1 +#define BCM5325_SPI_CMD_NORMAL 0x60 /* bit 7:4 - Mode */ +#define BCM5325_SPI_CMD_FAST 0x10 /* bit 4 - Mode */ + +/*---------------------------------------------------------------------*/ +/* 5325 Switch Pseudo PHY MII Register */ +/* use when configuration type is BP_ENET_CONFIG_MDIO_PSEUDO_PHY */ +/*---------------------------------------------------------------------*/ +#define PSEUDO_PHY_ADDR 0x1e /* Pseduo PHY address */ + +/* Pseudo PHY MII registers */ +#define REG_PSEUDO_PHY_MII_REG16 0x10 /* register 16 - Switch Register Set Access Control Register */ +#define REG_PSEUDO_PHY_MII_REG17 0x11 /* register 17 - Switch Register Set Read/Write Control Register */ +#define REG_PSEUDO_PHY_MII_REG24 0x18 /* register 24 - Switch Accesss Register bit 15:0 */ +#define REG_PSEUDO_PHY_MII_REG25 0x19 /* register 25 - Switch Accesss Register bit 31:16 */ +#define REG_PSEUDO_PHY_MII_REG26 0x20 /* register 26 - Switch Accesss Register bit 47:32 */ +#define REG_PSEUDO_PHY_MII_REG27 0x21 /* register 27 - Switch Accesss Register bit 63:48 */ + +/*Pseudo PHY MII register 16 Switch Register Set Access Control Register */ +#define REG_PPM_REG16_SWITCH_PAGE_NUMBER_SHIFT 8 /* bit 8..15 - switch page number */ +#define REG_PPM_REG16_MDIO_ENABLE 0x01 /* bit 0 - set MDC/MDIO access enable */ + +/*Pseudo PHY MII register 17 Switch Register Set Read/Write Control Register */ +#define REG_PPM_REG17_REG_NUMBER_SHIFT 8 /* bit 8..15 - switch register number */ +#define REG_PPM_REG17_OP_DONE 0x00 /* bit 0..1 - no operation */ +#define REG_PPM_REG17_OP_WRITE 0x01 /* bit 0..1 - write operation */ +#define REG_PPM_REG17_OP_READ 0x02 /* bit 0..1 - read operation */ + +#endif /* _BCMMII_H_ */ diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmtypes.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmtypes.h new file mode 100755 index 0000000..9359663 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bcmtypes.h @@ -0,0 +1,144 @@ +// +// bcmtypes.h - misc useful typedefs +// +#ifndef BCMTYPES_H +#define BCMTYPES_H + +// These are also defined in typedefs.h in the application area, so I need to +// protect against re-definition. + +#ifndef _TYPEDEFS_H_ +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef unsigned long long uint64; +typedef signed char int8; +typedef signed short int16; +typedef signed long int32; +typedef signed long long int64; +#if !defined(__cplusplus) +typedef int bool; +#endif +#endif + +typedef unsigned char byte; +typedef unsigned long sem_t; + +typedef unsigned long HANDLE,*PULONG,DWORD,*PDWORD; +typedef signed long LONG,*PLONG; + +typedef unsigned int *PUINT; +typedef signed int INT; + +typedef unsigned short *PUSHORT; +typedef signed short SHORT,*PSHORT,WORD,*PWORD; + +typedef unsigned char *PUCHAR; +typedef signed char *PCHAR; + +typedef void *PVOID; + +typedef unsigned char BOOLEAN, *PBOOL, *PBOOLEAN; + +typedef unsigned char BYTE,*PBYTE; + +//#ifndef __GNUC__ +//The following has been defined in Vxworks internally: vxTypesOld.h +//redefine under vxworks will cause error +typedef signed int *PINT; + +typedef signed char INT8; +typedef signed short INT16; +typedef signed long INT32; + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned long UINT32; + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned int UINT; +typedef unsigned long ULONG; + +typedef void VOID; +typedef unsigned char BOOL; + +//#endif /* __GNUC__ */ + + +// These are also defined in typedefs.h in the application area, so I need to +// protect against re-definition. +#ifndef TYPEDEFS_H + +#define MAX_INT16 32767 +#define MIN_INT16 -32768 + +// Useful for true/false return values. This uses the +// Taligent notation (k for constant). +typedef enum +{ + kFalse = 0, + kTrue = 1 +} Bool; + +#endif + +/* macros to protect against unaligned accesses */ + +#if 0 +/* first arg is an address, second is a value */ +#define PUT16( a, d ) { \ + *((byte *)a) = (byte)((d)>>8); \ + *(((byte *)a)+1) = (byte)(d); \ +} + +#define PUT32( a, d ) { \ + *((byte *)a) = (byte)((d)>>24); \ + *(((byte *)a)+1) = (byte)((d)>>16); \ + *(((byte *)a)+2) = (byte)((d)>>8); \ + *(((byte *)a)+3) = (byte)(d); \ +} + +/* first arg is an address, returns a value */ +#define GET16( a ) ( \ + (*((byte *)a) << 8) | \ + (*(((byte *)a)+1)) \ +) + +#define GET32( a ) ( \ + (*((byte *)a) << 24) | \ + (*(((byte *)a)+1) << 16) | \ + (*(((byte *)a)+2) << 8) | \ + (*(((byte *)a)+3)) \ +) +#endif + +#ifndef YES +#define YES 1 +#endif + +#ifndef NO +#define NO 0 +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define READ32(addr) (*(volatile UINT32 *)((ULONG)&addr)) +#define READ16(addr) (*(volatile UINT16 *)((ULONG)&addr)) +#define READ8(addr) (*(volatile UINT8 *)((ULONG)&addr)) + +#endif diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bsp_config.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bsp_config.h new file mode 100755 index 0000000..57e51bb --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/bsp_config.h @@ -0,0 +1,94 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * BSP Configuration file File: bsp_config.h + * + * This module contains global parameters and conditional + * compilation settings for building CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#define CFG_CMT 1 + +#define CFG_INIT_L1 1 /* initialize the L1 cache */ +#define CFG_INIT_L2 0 /* there is no L2 cache */ + +#define CFG_INIT_DRAM 1 /* initialize DRAM controller */ +#define CFG_DRAM_SIZE xxx /* size of DRAM if you don't initialize */ + /* NOTE : Size is in kilobytes. */ + +#define CFG_NETWORK 1 /* define to include network support */ + +#define CFG_FATFS 0 +#define CFG_UI 1 /* Define to enable user interface */ + +#define CFG_MULTI_CPUS 0 /* no multi-cpu support */ + +#define CFG_HEAP_SIZE 1024 /* heap size in kilobytes */ + +#define CFG_STACK_SIZE 8192 /* stack size (bytes, rounded up to K) */ + +#define CFG_SERIAL_BAUD_RATE 115200 /* normal console speed */ + +#define CFG_VENDOR_EXTENSIONS 0 +#define CFG_MINIMAL_SIZE 1 + +/* + * These parameters control the flash driver's sector buffer. + * If you write environment variables or make small changes to + * flash sectors from user applications, you + * need to have the heap big enough to store a temporary sector + * for merging in small changes to flash sectors, so you + * should set CFG_FLASH_ALLOC_SECTOR_BUFFER in that case. + * Otherwise, you can provide an address in unallocated memory + * of where to place the sector buffer. + */ + +#define CFG_FLASH_ALLOC_SECTOR_BUFFER 0 /* '1' to allocate sector buffer from the heap */ +#define CFG_FLASH_SECTOR_BUFFER_ADDR (1*1024*1024-128*1024) /* 1MB - 128K */ +#define CFG_FLASH_SECTOR_BUFFER_SIZE (128*1024) + +/* + * The flash staging buffer is where we store a flash image before we write + * it to the flash. It's too big for the heap. + */ + +#define CFG_FLASH_STAGING_BUFFER_ADDR (1*1024*1024) +#define CFG_FLASH_STAGING_BUFFER_SIZE (1*1024*1024) diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_eth.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_eth.h new file mode 100755 index 0000000..7432231 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_eth.h @@ -0,0 +1,127 @@ +/* +<:copyright-broadcom + + Copyright (c) 2002 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ +#ifndef __BCM63XX_ETH_H +#define __BCM63XX_ETH_H + +#include "bcm_hwdefs.h" +#include "bcm_map.h" +#include "boardparms.h" + +// from linux if_ether.h +#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_HLEN 14 /* Total octets in header. */ +#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ +#define ETH_DATA_LEN 1500 /* Max. octets in payload */ +#define ETH_CRC_LEN 4 /* CRC length */ +// end if_ether.h + +/*---------------------------------------------------------------------*/ +/* specify number of BDs and buffers to use */ +/*---------------------------------------------------------------------*/ +#define NR_TX_BDS 20 +#define NR_RX_BDS 20 +#define ENET_MAX_MTU_SIZE 1522 /* Body(1500) + EH_SIZE(14) + FCS(4) + VLAN(4) */ +#define DMA_MAX_BURST_LENGTH 8 /* in 64 bit words */ +#define ENET_BUF_SIZE ((ENET_MAX_MTU_SIZE + 63) & ~63) +#define DMA_FC_THRESH_LO 5 +#define DMA_FC_THRESH_HI 10 +#define EMAC_TX_WATERMARK 32 + +#define MAKE4(x) ((x[3] & 0xFF) | ((x[2] & 0xFF) << 8) | ((x[1] & 0xFF) << 16) | ((x[0] & 0xFF) << 24)) +#define MAKE2(x) ((x[1] & 0xFF) | ((x[0] & 0xFF) << 8)) + + +#define ERROR(x) xsprintf x +#ifndef ASSERT +#define ASSERT(x) if (x); else ERROR(("assert: "__FILE__" line %d\n", __LINE__)); +#endif + +//#define DUMP_TRACE + +#if defined(DUMP_TRACE) +#define TRACE (x) xprintf x +#else +#define TRACE(x) +#endif + +typedef struct PM_Addr { + uint16 valid; /* 1 indicates the corresponding address is valid */ + unsigned char dAddr[ETH_ALEN];/* perfect match register's destination address */ + unsigned int ref; /* reference count */ +} PM_Addr; +#define MAX_PMADDR 4 /* # of perfect match address */ + +#define NUM_PORTS 1 + +typedef struct gpio_reg_addrs_t { + volatile uint16 *gpio_direction_reg;/* GPIO direction register */ + volatile uint16 *gpio_value_reg; /* GPIO value register */ +} gpio_reg_addrs_t; + +typedef struct ethsw_info_t { + gpio_reg_addrs_t sbh; + uint32 ssl, clk, mosi, miso; /* GPIO mapping */ + int cid, page; /* Current chip ID and page */ +} ethsw_info_t; + +typedef struct bcmenet_softc { + + volatile DmaRegs *dmaCtrl; + + /* transmit variables */ + volatile DmaChannelCfg *txDma; /* location of transmit DMA register set */ + volatile DmaDesc *txBds; /* Memory location of tx Dma BD ring */ + volatile DmaDesc *txFirstBdPtr; /* ptr to first allocated Tx BD */ + volatile DmaDesc *txNextBdPtr; /* ptr to next Tx BD to transmit with */ + volatile DmaDesc *txLastBdPtr; /* ptr to last allocated Tx BD */ + + /* receive variables */ + volatile DmaChannelCfg *rxDma; /* location of receive DMA register set */ + volatile DmaDesc *rxBds; /* Memory location of rx bd ring */ + volatile DmaDesc *rxFirstBdPtr; /* ptr to first allocated rx bd */ + volatile DmaDesc *rxBdReadPtr; /* ptr to next rx bd to be processed */ + volatile DmaDesc *rxLastBdPtr; /* ptr to last allocated rx bd */ + + uint32_t rxBuffers; + uint32_t txBuffers; + + uint16 chipId; /* chip's id */ + uint16 chipRev; /* step */ + uint8_t hwaddr[ETH_ALEN]; + ethsw_info_t ethSwitch; /* external switch */ + ETHERNET_MAC_INFO EnetInfo; + uint32_t dmaPort; + uint32_t linkCheck; +} bcmenet_softc; + + + +#define IncRxBdPtr(x, s) if (x == ((bcmenet_softc *)s)->rxLastBdPtr) \ + x = ((bcmenet_softc *)s)->rxBds; \ + else x++ +#define InctxBdPtr(x, s) if (x == ((bcmenet_softc *)s)->txLastBdPtr) \ + x = ((bcmenet_softc *)s)->txBds; \ + else x++ + +// extern and function prototype + +extern int32_t _getticks(void); + +#ifdef DUMP_DATA +static void hexdump( unsigned char * src, int srclen, int rowlen, int rows ); +#endif + +#endif // __BCM63XX_ETH_H diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_flash.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_flash.h new file mode 100755 index 0000000..d8e7f1d --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/dev_bcm63xx_flash.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Broadcom Corp. Confidential + * Copyright 2001 Broadcom Corp. All Rights Reserved. + * + * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED + * SOFTWARE LICENSE AGREEMENT BETWEEN THE USER AND BROADCOM. + * YOU HAVE NO RIGHT TO USE OR EXPLOIT THIS MATERIAL EXCEPT + * SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. + * + *************************************************************************** + * File Name : dev_bcm63xx_flash.h + * + * Created on : 04/18/2002 seanl + ***************************************************************************/ + +#if !defined(_DEV_BCM63XX_FLASH_) +#define _DEV_BCM63XX_FLASH_ + +#include "bcmtypes.h" +#include "bcm_hwdefs.h" + +// Used for images that do not contain a FILE_TAG record. +#define FLASH_IMAGE_START_ADDR (FLASH_BASE + FLASH_LENGTH_BOOT_ROM) + +// FLASH_ADDR_INFO is now defined in flash_common.h +#include "flash_common.h" + +extern void kerSysFlashInit(void); +extern void kerSysFlashAddrInfoGet(PFLASH_ADDR_INFO pflash_addr_info); +extern int kerSysNvRamSet(unsigned char *string,int strLen,int offset); +extern int kerSysNvRamGet(unsigned char *string,int strLen,int offset); +extern int kerSysBcmImageSet( int flash_start_addr, unsigned char *string, int size, int fWholeImage); +extern int kerSysErasePsi(void); +extern int kerSysEraseNvRam(void); +extern unsigned long kerSysReadFromFlash(void *toaddr, unsigned long fromaddr, unsigned long len); + +#endif /* _DEV_BCM63XX_FLASH_ */ + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/include/jffs2.h b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/jffs2.h new file mode 100755 index 0000000..586fb55 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/include/jffs2.h @@ -0,0 +1,251 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + * + * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $ + * + */ + +#ifndef __LINUX_JFFS2_H__ +#define __LINUX_JFFS2_H__ + +//include + +/* You must include something which defines the C99 uintXX_t types. + We don't do it from here because this file is used in too many + different environments. */ + +/* Values we may expect to find in the 'magic' field */ +#define JFFS2_OLD_MAGIC_BITMASK 0x1984 +#define JFFS2_MAGIC_BITMASK 0x1985 +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ +#define JFFS2_EMPTY_BITMASK 0xffff +#define JFFS2_DIRTY_BITMASK 0x0000 + +#if defined(CONFIG_MTD_BRCMNAND) +/* JFFS2 eraseblock header compat/incompat/rocompat features set */ +#define JFFS2_EBH_COMPAT_FSET 0x00 +#define JFFS2_EBH_INCOMPAT_FSET 0x00 +#define JFFS2_EBH_ROCOMPAT_FSET 0x00 +#endif + +/* Summary node MAGIC marker */ +#define JFFS2_SUM_MAGIC 0x02851885 + +/* We only allow a single char for length, and 0xFF is empty flash so + we don't want it confused with a real length. Hence max 254. +*/ +#define JFFS2_MAX_NAME_LEN 254 + +/* How small can we sensibly write nodes? */ +#define JFFS2_MIN_DATA_LEN 128 + +#define JFFS2_COMPR_NONE 0x00 +#define JFFS2_COMPR_ZERO 0x01 +#define JFFS2_COMPR_RTIME 0x02 +#define JFFS2_COMPR_RUBINMIPS 0x03 +#define JFFS2_COMPR_COPY 0x04 +#define JFFS2_COMPR_DYNRUBIN 0x05 +#define JFFS2_COMPR_ZLIB 0x06 +/* Compatibility flags. */ +#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ +#define JFFS2_NODE_ACCURATE 0x2000 +/* INCOMPAT: Fail to mount the filesystem */ +#define JFFS2_FEATURE_INCOMPAT 0xc000 +/* ROCOMPAT: Mount read-only */ +#define JFFS2_FEATURE_ROCOMPAT 0x8000 +/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 +/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 + +#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) +#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) +#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) + +#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) + +#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) +#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) + +#if defined(CONFIG_MTD_BRCMNAND) +#define JFFS2_NODETYPE_ERASEBLOCK_HEADER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 5) +#endif + +/* XATTR Related */ +#define JFFS2_XPREFIX_USER 1 /* for "user." */ +#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ +#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ +#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ +#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ + +#define JFFS2_ACL_VERSION 0x0001 + +// Maybe later... +//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) + + +#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at + mount time, don't wait for it to + happen later */ +#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific + compression type */ + + +/* These can go once we've made sure we've caught all uses without + byteswapping */ + +typedef struct { + uint32_t v32; +} __attribute__((packed)) jint32_t; + +typedef struct { + uint32_t m; +} __attribute__((packed)) jmode_t; + +typedef struct { + uint16_t v16; +} __attribute__((packed)) jint16_t; + +struct jffs2_unknown_node +{ + /* All start like this */ + jint16_t magic; + jint16_t nodetype; + jint32_t totlen; /* So we can skip over nodes we don't grok */ + jint32_t hdr_crc; +}; + +struct jffs2_raw_dirent +{ + jint16_t magic; + jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t pino; + jint32_t version; + jint32_t ino; /* == zero for unlink */ + jint32_t mctime; + uint8_t nsize; + uint8_t type; + uint8_t unused[2]; + jint32_t node_crc; + jint32_t name_crc; + uint8_t name[0]; +}; + +/* The JFFS2 raw inode structure: Used for storage on physical media. */ +/* The uid, gid, atime, mtime and ctime members could be longer, but + are left like this for space efficiency. If and when people decide + they really need them extended, it's simple enough to add support for + a new type of raw node. +*/ +struct jffs2_raw_inode +{ + jint16_t magic; /* A constant magic number. */ + jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ + jint32_t totlen; /* Total length of this node (inc data, etc.) */ + jint32_t hdr_crc; + jint32_t ino; /* Inode number. */ + jint32_t version; /* Version number. */ + jmode_t mode; /* The file's type or mode. */ + jint16_t uid; /* The file's owner. */ + jint16_t gid; /* The file's group. */ + jint32_t isize; /* Total resultant size of this inode (used for truncations) */ + jint32_t atime; /* Last access time. */ + jint32_t mtime; /* Last modification time. */ + jint32_t ctime; /* Change time. */ + jint32_t offset; /* Where to begin to write. */ + jint32_t csize; /* (Compressed) data size */ + jint32_t dsize; /* Size of the node's data. (after decompression) */ + uint8_t compr; /* Compression algorithm used */ + uint8_t usercompr; /* Compression algorithm requested by the user */ + jint16_t flags; /* See JFFS2_INO_FLAG_* */ + jint32_t data_crc; /* CRC for the (compressed) data. */ + jint32_t node_crc; /* CRC for the raw inode (excluding data) */ + uint8_t data[0]; +}; + +struct jffs2_raw_xattr { + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t xid; /* XATTR identifier number */ + jint32_t version; + uint8_t xprefix; + uint8_t name_len; + jint16_t value_len; + jint32_t data_crc; + jint32_t node_crc; + uint8_t data[0]; +} __attribute__((packed)); + +struct jffs2_raw_xref +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t ino; /* inode number */ + jint32_t xid; /* XATTR identifier number */ + jint32_t xseqno; /* xref sequencial number */ + jint32_t node_crc; +} __attribute__((packed)); + +struct jffs2_raw_summary +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t sum_num; /* number of sum entries*/ + jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ + jint32_t padded; /* sum of the size of padding nodes */ + jint32_t sum_crc; /* summary information crc */ + jint32_t node_crc; /* node crc */ + jint32_t sum[0]; /* inode summary info */ +}; + +#if defined(CONFIG_MTD_BRCMNAND) +struct jffs2_raw_ebh +{ + jint16_t magic; + jint16_t nodetype; /* == JFFS2_NODETYPE_ERASEBLOCK_HEADER */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t node_crc; + uint8_t reserved; /* reserved for future use and alignment */ + uint8_t compat_fset; + uint8_t incompat_fset; + uint8_t rocompat_fset; + jint32_t erase_count; /* the erase count of this erase block */ + jint32_t data[0]; +} __attribute__((packed)); +#endif + +union jffs2_node_union +{ + struct jffs2_raw_inode i; + struct jffs2_raw_dirent d; + struct jffs2_raw_xattr x; + struct jffs2_raw_xref r; + struct jffs2_raw_summary s; + struct jffs2_unknown_node u; +}; + +/* Data payload for device nodes. */ +union jffs2_device_node { + jint16_t old; + jint32_t new; +}; + +#endif /* __LINUX_JFFS2_H__ */ diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/Makefile b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/Makefile new file mode 100755 index 0000000..7320c9d --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/Makefile @@ -0,0 +1,55 @@ +BSPOBJS += \ + dev_bcm63xx_eth.o \ + dev_bcm63xx_uart.o \ + dev_bcm63xx_flash.o \ + flash_api.o \ + flash_common.o \ + bcm63xx_ram_boot.o \ + bcm63xx_devs.o \ + bcm63xx_board.o \ + bcm63xx_cmd.o \ + bcm63xx_util.o \ + bcm63xx_ldr_raw.o \ + bcm63xx_ldr_elf.o \ + bcm63xx_main.o \ + bcm63xx_env_subr.o \ + bcm63xx_net_icmp.o \ + bcm63xx_httpd.o \ + bcmSpiRes.o \ + bcmLegSpi.o \ + boardparms.o \ + boardparms_voice.o + +ifneq ($(strip $(BRCM_CHIP)),6368) +BSPOBJS += \ + bcmHsSpi.o +endif + +BSPOBJS += \ + robosw_reg.o + +ifeq ($(strip ${INC_CFI_FLASH_DRIVER}),1) +BSPOBJS += \ + cfiflash.o +endif + +ifeq ($(strip ${INC_SPI_FLASH_DRIVER}),1) +BSPOBJS += \ + spiflash.o +endif + +ifeq ($(strip ${INC_SPI_PROG_NAND}),1) +BSPOBJS += \ + nandflash.o +endif + +ifeq ($(strip ${INC_NAND_FLASH_DRIVER}),1) +BSPOBJS += \ + nandflash.o +endif + +ifeq ($(strip ${CFG_WEB_SERVER}),1) +BSPOBJS += \ + ul.o \ + ulinfo.o +endif diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_board.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_board.c new file mode 100755 index 0000000..5baa66c --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_board.c @@ -0,0 +1,830 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * bcm63xx_board.c utility functions for bcm63xx board + * + * Created on : 09/25/2002 seanl + * + ********************************************************************* + +<:copyright-broadcom + + Copyright (c) 2002 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ + +#include "bcm63xx_util.h" +#include "foxconnCfg.h" + +#define MAX_BOARD_ID_NAMES 16 +#define MAX_VOICE_BOARD_ID_NAMES 20 + +static char g_boardIdNames[BP_BOARD_ID_LEN * MAX_BOARD_ID_NAMES]; +static int g_numBoardIdNames = 0; + +static char g_voiceBoardIdNames[BP_BOARD_ID_LEN * MAX_VOICE_BOARD_ID_NAMES]; +static int g_numVoiceBoardIdNames = 0; + +static int parsehwaddr(char *, uint8_t *); +static int parseBoardIdStr(char *); +static int parseVoiceBoardIdStr(char *); +static int parsePsiSize(char *); +static int parseBackupPsi(char *tpStr); +static int parseSyslogSize(char *tpStr); +static int parseMainTp(char *); +static int parseMacAddrCount(char *); +static int parseMacAddr(char *); +static int charIsHex(char ch); +static int parseGponSN(char *snStr); +static int parseGponPW(char *pwStr); +static int macNumToStr(unsigned char *, char *); +static void getGponBoardParam(void); +static int gponParamsInitialized(NVRAM_DATA *pNvramData); + +static int parseWpsDevicePin(char *pinStr); +static void getWpsDevicePinBoardParam(void); +#define PARAM_IDX_BOARD_NAME 0 +#define PARAM_IDX_NUM_MAC_ADDR 1 +#define PARAM_IDX_BASE_MAC_ADDR 2 +#define PARAM_IDX_PSI_SIZE 3 +#define PARAM_IDX_ENABLE_BACKUP_PSI 4 +#define PARAM_IDX_SYSLOG_SIZE 5 +#define PARAM_IDX_MAIN_THREAD_NUM 6 + +#define PARAM_IDX_GPON_SN 0 +#define PARAM_IDX_GPON_PW 1 + +#define PARAM_IDX_WPS_DEVICE_PIN 0 + +#define PARAM_IDX_VOICE_BOARD_NAME 0 + +static PARAMETER_SETTING gBoardParam[] = +{ + // prompt name Error Prompt Define Param Validation function + {"Board Id (0-# :", BOARDID_STR_PROMPT, "", "", 2, + parseBoardIdStr, TRUE}, + {"Number of MAC Addresses (1-32) :", MAC_CT_PROMPT, "", "", 2, + parseMacAddrCount, TRUE}, + {"Base MAC Address :", MAC_ADDR_PROMPT, "", "", 17, + parseMacAddr, TRUE}, + {"PSI Size (1-64) KBytes :", PSI_SIZE_PROMPT, "", "", 2, + parsePsiSize, TRUE}, + {"Enable Backup PSI [0|1] :", BACKUP_PSI_PROMPT, "", "", 1, + parseBackupPsi, TRUE}, + {"System Log Size (0-256) KBytes :", SYSLOG_SIZE_PROMPT, "", "", 3, + parseSyslogSize, TRUE}, + {"Main Thread Number [0|1] :", CPU_TP_PROMPT, "", "", 1, + parseMainTp, TRUE}, + {NULL} +}; + +static int gNumBoardParams = (sizeof(gBoardParam) / sizeof(PARAMETER_SETTING))-1; + +static PARAMETER_SETTING gGponBoardParam[] = +{ + // prompt name Error Prompt Define Param Validation function + {"GPON Serial Number :", GPON_SN_PROMPT, "", "", 12, + parseGponSN, TRUE}, + {"GPON Password :", GPON_PW_PROMPT, "", "", 10, + parseGponPW, TRUE}, + {NULL} +}; + +static int gNumGponBoardParams = (sizeof(gGponBoardParam) / sizeof(PARAMETER_SETTING))-1; +static int gGponParamsInitialized = 0; + + +static PARAMETER_SETTING gWpsDevicePinBoardParam[] = +{ + // prompt name Error Prompt Define Param Validation function + {"Device Pin :", WPS_DEVICE_PIN_PROMPT, "", "", 8, + parseWpsDevicePin, TRUE}, + {NULL} +}; + +static int gNumWpsDevicePinBoardParams = (sizeof(gWpsDevicePinBoardParam) / sizeof(PARAMETER_SETTING))-1; +static int gWpsDevicePinInitialized = 0; + +static PARAMETER_SETTING gVoiceBoardParam[] = +{ + // prompt name Error Prompt Define Param Validation function + {"Voice Board Configuration (0-# :", BOARDID_STR_PROMPT, "", "", 2, + parseVoiceBoardIdStr, FALSE}, + {NULL} +}; + +static int gNumVoiceBoardParams = (sizeof(gVoiceBoardParam) / sizeof(PARAMETER_SETTING))-1; +static int gVoiceParamsInitialized = 0; + + +static int parsehwaddr(char *str,uint8_t *hwaddr) +{ + int digit1,digit2; + int idx = 6; + + if (strlen(str) == (MAX_MAC_STR_LEN - 7)) { // no ':' mac input format ie. 021800100801 + while (*str && (idx > 0)) { + digit1 = parsexdigit(*str); + if (digit1 < 0) + return -1; + str++; + if (!*str) + return -1; + digit2 = parsexdigit(*str); + if (digit2 < 0) + return -1; + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + str++; + } + return 0; + } + + if (strlen(str) != MAX_MAC_STR_LEN-2) + return -1; + if (*(str+2) != ':' || *(str+5) != ':' || *(str+8) != ':' || *(str+11) != ':' || *(str+14) != ':') + return -1; + + while (*str && (idx > 0)) { + digit1 = parsexdigit(*str); + if (digit1 < 0) + return -1; + str++; + if (!*str) + return -1; + + if (*str == ':') { + digit2 = digit1; + digit1 = 0; + } + else { + digit2 = parsexdigit(*str); + if (digit2 < 0) + return -1; + str++; + } + + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + + if (*str == ':') + str++; + } + return 0; +} + + +static int parseMacAddr(char * macStr) +{ + unsigned char tmpBuf[MAX_PROMPT_LEN]; + + return (parsehwaddr(macStr, tmpBuf)); +} + + +static int parseBoardIdStr(char *boardIdStr) +{ + int ret = 1; + int boardId; + + if (strlen (boardIdStr) != 0) { + boardId = atoi(boardIdStr); + if (boardId >= 0 && boardId < g_numBoardIdNames) + ret = 0; + } + + return ret; +} + + +static int parseVoiceBoardIdStr(char *boardIdStr) +{ + int ret = 1; + int boardId; + + if (strlen (boardIdStr) != 0) { + boardId = atoi(boardIdStr); + if (boardId >= 0 && boardId < g_numVoiceBoardIdNames) + ret = 0; + } + + return ret; +} + + +static int parseMacAddrCount(char *ctStr) +{ + int count = atoi(ctStr); + + if (count >= 1 && count <= NVRAM_MAC_COUNT_MAX) + return 0; + else + return 1; +} + +static int parsePsiSize(char *tpStr) +{ + int psiSize = atoi(tpStr); + + if (psiSize >= 1 && psiSize <= NVRAM_MAX_PSI_SIZE) + return 0; + else + return 1; +} + +static int parseBackupPsi(char *tpStr) +{ + int enable = atoi(tpStr); + + if (enable == 0 || enable == 1) + return 0; + else + return 1; +} + +static int parseSyslogSize(char *tpStr) +{ + int syslogSize = atoi(tpStr); + + if (syslogSize >= 0 && syslogSize <= NVRAM_MAX_SYSLOG_SIZE) + return 0; + else + return 1; +} + + +static int parseMainTp(char *tpStr) +{ + int tpNum = atoi(tpStr); + + if (tpNum == 0 || tpNum == 1) + return 0; + else + return 1; +} + +static int charIsHex(char ch) +{ + if (((ch >= '0') && (ch <= '9')) || + ((ch >= 'a') && (ch <= 'f')) || + ((ch >= 'A') && (ch <= 'F'))) + return 1; + else + return 0; +} + +static int parseGponSN(char *snStr) +{ + int i; + int ret = 0; + + if(strlen(snStr) == NVRAM_GPON_SERIAL_NUMBER_LEN-1) { + for(i=4; igponSerialNumber[i] != (char)0xFF) && + (pNvramData->gponSerialNumber[i] != '\0')) { + erased = 0; + break; + } + } + + if(erased) { + for(i=0; igponPassword[i] != (char)0xFF) && + (pNvramData->gponPassword[i] != '\0')) { + erased = 0; + break; + } + } + } + + return (erased) ? 0 : 1; +} + +static void getGponBoardParam(void) +{ + NVRAM_DATA nvramData; + int erased; + int i; + int writeNvram = 0; + + readNvramData(&nvramData); + + erased = 1; + for(i=0; iwpsDevicePin[i]) > 0x39) || + ( (unsigned char)(pNvramData->wpsDevicePin[i]) < 0x30) ) { + return 0; + } + } + + return 1; +} + +static void getWpsDevicePinBoardParam(void) +{ + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + + if ( gWpsDevicePinParamsInitialized( &nvramData) ) { + memcpy(gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].parameter, + nvramData.wpsDevicePin, NVRAM_WPS_DEVICE_PIN_LEN); + (gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].parameter)[NVRAM_WPS_DEVICE_PIN_LEN] = + '\0'; + } + else { + /*Set Default Device Pin*/ + memcpy(nvramData.wpsDevicePin, DEFAULT_WPS_DEVICE_PIN, NVRAM_WPS_DEVICE_PIN_LEN); + writeNvramData(&nvramData); + + memcpy(gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].parameter, + nvramData.wpsDevicePin, + NVRAM_WPS_DEVICE_PIN_LEN); + (gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].parameter)[NVRAM_WPS_DEVICE_PIN_LEN] = + '\0'; + } + +} + +int setWpsDevicePinBoardParam(void) +{ + NVRAM_DATA nvramData; + int ret = 0; + + getWpsDevicePinBoardParam(); + + readNvramData(&nvramData); + + if (processPrompt(gWpsDevicePinBoardParam, gNumWpsDevicePinBoardParams)) { + memcpy(nvramData.wpsDevicePin, + gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].parameter, + NVRAM_WPS_DEVICE_PIN_LEN); + // save the buf to nvram + writeNvramData(&nvramData); + ret = 1; + } + + return ret; +} + + +static int voiceParamsInitialized(NVRAM_DATA *pNvramData) +{ + int rc = 0; + NVRAM_DATA nvramData; + readNvramData(&nvramData); + + if ( BpSetBoardId(nvramData.szBoardId) == BP_SUCCESS ) { + if ( BpGetVoipDspConfig( 0 ) == NULL ) { + gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].enabled = FALSE; + } + else { + gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].enabled = TRUE; + rc = 1; + } + } + + return rc; +} + +static void getVoiceBoardParam(void) +{ + NVRAM_DATA nvramData; + char *ptr; + char tmp[10]; + + if (g_numVoiceBoardIdNames == 0) + g_numVoiceBoardIdNames = BpGetVoiceBoardIds(g_voiceBoardIdNames, MAX_VOICE_BOARD_ID_NAMES); + + ptr = strchr(gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].promptName, '#'); + if (ptr != NULL) { + sprintf(tmp, "%d)", g_numVoiceBoardIdNames - 1); + memcpy(ptr, tmp, strlen(tmp)); + } + + readNvramData(&nvramData); + + memcpy(gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].parameter, nvramData.szVoiceBoardId, NVRAM_BOARD_ID_STRING_LEN); + gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].parameter[NVRAM_BOARD_ID_STRING_LEN] = '\0'; +} + +int setVoiceBoardParam(void) +{ + NVRAM_DATA nvramData; + char voiceBoardIdPrompt[1000]; + int i; + char tmp[3]; + char *voiceBoardIdPromptPtr, *savedVoiceBoardIdPromptPtr; + int ret = 0; + + getVoiceBoardParam(); + + readNvramData(&nvramData); + + // Create prompt string with voice board ID name selection + voiceBoardIdPromptPtr = voiceBoardIdPrompt; + for (i = 0; i < g_numVoiceBoardIdNames; i++) { + sprintf (tmp, "%d", i); + sprintf (voiceBoardIdPromptPtr, "%-17s-- %2s\n", &g_voiceBoardIdNames[i * BP_BOARD_ID_LEN], tmp); + voiceBoardIdPromptPtr += strlen(voiceBoardIdPromptPtr); + } + strcpy (voiceBoardIdPromptPtr, gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].promptName); + + // Save existing prompt string + savedVoiceBoardIdPromptPtr = gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].promptName; + // Set newly created prompt string + gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].promptName = voiceBoardIdPrompt; + + // Convert board ID string to numeric value + for (i = 0; i < g_numVoiceBoardIdNames; i++) { + if (!strcmp(gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].parameter, &g_voiceBoardIdNames[i * BP_BOARD_ID_LEN])) { + sprintf(gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].parameter, "%d", i); + } + } + + if (processPrompt(gVoiceBoardParam, gNumVoiceBoardParams)) { + // At least one field was changed + i = atoi(gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].parameter); + strcpy(nvramData.szVoiceBoardId, &g_voiceBoardIdNames[i * BP_BOARD_ID_LEN]); + + // save the buf to nvram + writeNvramData(&nvramData); + ret = 1; + } + + // Convert numeric value of voice board ID to string + gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].promptName = savedVoiceBoardIdPromptPtr; + i = atoi(gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].parameter); + strcpy(gVoiceBoardParam[PARAM_IDX_VOICE_BOARD_NAME].parameter, &g_voiceBoardIdNames[i * BP_BOARD_ID_LEN]); + + return ret; +} + + +// +// getBoardParam: convert the board param data and put them in the gBoardParam struct +// +int getBoardParam(void) +{ + NVRAM_DATA nvramData; + char *ptr; + char tmp[10]; + int ret = 0; + + if (g_numBoardIdNames == 0) + g_numBoardIdNames = BpGetBoardIds(g_boardIdNames, MAX_BOARD_ID_NAMES); + + ptr = strchr(gBoardParam[PARAM_IDX_BOARD_NAME].promptName, '#'); + if (ptr != NULL) { + sprintf(tmp, "%d)", g_numBoardIdNames - 1); + memcpy(ptr, tmp, strlen(tmp)); + } + + readNvramData(&nvramData); + + if(!gGponParamsInitialized) { + gGponParamsInitialized = gponParamsInitialized(&nvramData); + } + + /*WPS Device Pin Initialized?*/ + if(!gWpsDevicePinInitialized) { + gWpsDevicePinInitialized = gWpsDevicePinParamsInitialized(&nvramData); + } + + if (nvramData.ulVersion == -1) { + // Set default values + nvramData.ulVersion = NVRAM_VERSION_NUMBER; + nvramData.szBoardId[0] = '\0'; + nvramData.ulNumMacAddrs = DEFAULT_MAC_NUM; + parsehwaddr(DEFAULT_BOARD_MAC, nvramData.ucaBaseMacAddr); + nvramData.ulMainTpNum = DEFAULT_TP_NUM; + nvramData.szVoiceBoardId[0] = '\0'; + nvramData.ulPsiSize = DEFAULT_PSI_SIZE; + nvramData.backupPsi = 0; + nvramData.ulSyslogSize = 0; + writeNvramData(&nvramData); + } + else if (nvramData.ulVersion != NVRAM_VERSION_NUMBER) { + // When upgrading from older bootloader initialize new fields + printf("*** Upgrading NVRAM (version %d to version %d) ***\n\n", + nvramData.ulVersion, NVRAM_VERSION_NUMBER); + nvramData.ulVersion = NVRAM_VERSION_NUMBER; + if (nvramData.ulMainTpNum == -1) + nvramData.ulMainTpNum = DEFAULT_TP_NUM; + if ((nvramData.ulPsiSize == -1) || (nvramData.ulPsiSize == 0)) + nvramData.ulPsiSize = DEFAULT_PSI_SIZE; + nvramData.szVoiceBoardId[0] = '\0'; + if (nvramData.backupPsi == -1) + nvramData.backupPsi = 0; + if (nvramData.ulSyslogSize == -1) + nvramData.ulSyslogSize = 0; + writeNvramData(&nvramData); + ret = 1; + } + + gVoiceParamsInitialized = voiceParamsInitialized(&nvramData); + + // When backupPsi and syslog were introduced, the NVRAM version number + // was not bumped up. So convert -1 (unitialized) to 0 so it looks better. + if (nvramData.backupPsi == -1) + nvramData.backupPsi = 0; + if (nvramData.ulSyslogSize == -1) + nvramData.ulSyslogSize = 0; + + strcpy(gBoardParam[PARAM_IDX_BOARD_NAME].parameter, nvramData.szBoardId); + sprintf(gBoardParam[PARAM_IDX_NUM_MAC_ADDR].parameter, "%d", nvramData.ulNumMacAddrs); + macNumToStr(nvramData.ucaBaseMacAddr, gBoardParam[PARAM_IDX_BASE_MAC_ADDR].parameter); + sprintf(gBoardParam[PARAM_IDX_PSI_SIZE].parameter, "%d", nvramData.ulPsiSize); + sprintf(gBoardParam[PARAM_IDX_ENABLE_BACKUP_PSI].parameter, "%d", nvramData.backupPsi); + sprintf(gBoardParam[PARAM_IDX_SYSLOG_SIZE].parameter, "%d", nvramData.ulSyslogSize); + sprintf(gBoardParam[PARAM_IDX_MAIN_THREAD_NUM].parameter, "%d", nvramData.ulMainTpNum); + + return ret; +} + +/* Bob added start to set default board parameters, 11/01/2010 */ +int setDefaultBoardParam(void) +{ + NVRAM_DATA nvramData; + int ret = 0; + + if (getBoardParam()) { + /* New NVRAM version */ + return ret; + } + + readNvramData(&nvramData); + + { + // At least one field was changed + nvramData.ulVersion = NVRAM_VERSION_NUMBER; + strcpy(nvramData.szBoardId, "963281TAN"); + strcpy(nvramData.szFirmwareUpgradeBoardId, FOXCONN_BOARD_ID); + nvramData.ulNumMacAddrs = 10; + parsehwaddr("00:00:00:00:00:01", nvramData.ucaBaseMacAddr); + nvramData.ulPsiSize = 24; + nvramData.backupPsi = 0; + nvramData.ulSyslogSize = 0; + nvramData.ulMainTpNum = 0; + + // save the buf to nvram + writeNvramData(&nvramData); + ret = 1; + } + + return ret; +} +/* Bob added end to set default board parameters, 11/01/2010 */ + +// +// setBoardParam: Set the board Id string, mac addresses, psi size, etc... +// +int setBoardParam(void) +{ + char boardIdPrompt[1000]; + NVRAM_DATA nvramData; + int i; + char tmp[3]; + char *boardIdPromptPtr, *savedBoardIdPromptPtr; + int ret = 0; + + if (getBoardParam()) { + /* New NVRAM version */ + return ret; + } + + readNvramData(&nvramData); + + // Create prompt string with board ID name selection + boardIdPromptPtr = boardIdPrompt; + for (i = 0; i < g_numBoardIdNames; i++) { + sprintf (tmp, "%d", i); + sprintf (boardIdPromptPtr, "%-17s------- %2s\n", &g_boardIdNames[i * BP_BOARD_ID_LEN], tmp); + boardIdPromptPtr += strlen(boardIdPromptPtr); + } + strcpy (boardIdPromptPtr, gBoardParam[PARAM_IDX_BOARD_NAME].promptName); + + // Save existing prompt string + savedBoardIdPromptPtr = gBoardParam[PARAM_IDX_BOARD_NAME].promptName; + // Set newly created prompt string + gBoardParam[PARAM_IDX_BOARD_NAME].promptName = boardIdPrompt; + + // Convert board ID string to numeric value + for (i = 0; i < g_numBoardIdNames; i++) { + if (!strcmp(gBoardParam[PARAM_IDX_BOARD_NAME].parameter, &g_boardIdNames[i * BP_BOARD_ID_LEN])) { + sprintf(gBoardParam[PARAM_IDX_BOARD_NAME].parameter, "%d", i); + } + } + + if (processPrompt(gBoardParam, gNumBoardParams)) { + // At least one field was changed + nvramData.ulVersion = NVRAM_VERSION_NUMBER; + + // Convert numeric value of board ID to string + i = atoi(gBoardParam[PARAM_IDX_BOARD_NAME].parameter); + strcpy(nvramData.szBoardId, &g_boardIdNames[i * BP_BOARD_ID_LEN]); + + nvramData.ulNumMacAddrs = atoi(gBoardParam[PARAM_IDX_NUM_MAC_ADDR].parameter); + parsehwaddr(gBoardParam[PARAM_IDX_BASE_MAC_ADDR].parameter, nvramData.ucaBaseMacAddr); + nvramData.ulPsiSize = atoi(gBoardParam[PARAM_IDX_PSI_SIZE].parameter); + nvramData.backupPsi = atoi(gBoardParam[PARAM_IDX_ENABLE_BACKUP_PSI].parameter); + nvramData.ulSyslogSize = atoi(gBoardParam[PARAM_IDX_SYSLOG_SIZE].parameter); + nvramData.ulMainTpNum = atoi(gBoardParam[PARAM_IDX_MAIN_THREAD_NUM].parameter); + + // save the buf to nvram + writeNvramData(&nvramData); + ret = 1; + } + + // restore gBoardParam + // Convert numeric value of board ID to string + gBoardParam[PARAM_IDX_BOARD_NAME].promptName = savedBoardIdPromptPtr; + i = atoi(gBoardParam[PARAM_IDX_BOARD_NAME].parameter); + strcpy(gBoardParam[PARAM_IDX_BOARD_NAME].parameter, &g_boardIdNames[i * BP_BOARD_ID_LEN]); + + if(gGponParamsInitialized) { + printf("\n"); + ret += setGponBoardParam(); + } + + if(gWpsDevicePinInitialized) { + printf("\n"); + ret += setWpsDevicePinBoardParam(); + } + + gVoiceParamsInitialized = voiceParamsInitialized(&nvramData); + + if(gVoiceParamsInitialized) { + printf("\n"); + ret += setVoiceBoardParam(); + } + + return ret; +} + +void displayBoardParam(void) +{ + int i; + + getBoardParam(); + + for (i = 0; i < gNumBoardParams; i++) { + if( gBoardParam[i].enabled ) + printf("%s %s \n", gBoardParam[i].promptName, gBoardParam[i].parameter); + } + + if(gGponParamsInitialized) { + getGponBoardParam(); + + for (i = 0; i < gNumGponBoardParams; i++) + if( gGponBoardParam[i].enabled ) + printf("%s \"%s\" \n", gGponBoardParam[i].promptName, gGponBoardParam[i].parameter); + } + + /*Show WPS Device PIN */ + if(gWpsDevicePinInitialized) { + getWpsDevicePinBoardParam(); + if ( gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].enabled) + printf("%s \"%s\" \n", gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].promptName, \ + gWpsDevicePinBoardParam[PARAM_IDX_WPS_DEVICE_PIN].parameter); + } + + if(gVoiceParamsInitialized) { + getVoiceBoardParam(); + + for (i = 0; i < gNumVoiceBoardParams; i++) + if( gVoiceBoardParam[i].enabled ) + printf("%s %s \n", gVoiceBoardParam[i].promptName, gVoiceBoardParam[i].parameter); + } +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_cmd.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_cmd.c new file mode 100755 index 0000000..111e73f --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_cmd.c @@ -0,0 +1,1878 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * + * bcm63xx board specific routines and commands. + * + * by: seanl + * + * April 1, 2002 + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "bcm63xx_util.h" +#include "flash_api.h" +#include "jffs2.h" + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#include "tftpd.h" + +#include "net_nmrp.h" + + +extern int nmrp_server_detected; +extern unsigned long cfe_sdramsize; +extern int ui_init_tftpdcmds(void); +int verify_checksum(char *buf, unsigned long buf_len, unsigned long chksum); +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) +#define FLASH_STAGING_BUFFER BOARD_IMAGE_DOWNLOAD_ADDRESS +#define FLASH_STAGING_BUFFER_SIZE BOARD_IMAGE_DOWNLOAD_SIZE + +extern int decompressLZMA(unsigned char *in, unsigned insize, unsigned char *out, unsigned outsize); + +// global +int g_processing_cmd = 0; + +char fakeConsole[2] = " "; + +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ +struct image_header +{ + unsigned long magic; /* magic */ + unsigned long header_len; /* Length of header */ + unsigned char reserved[8]; + unsigned long kernel_chksum; /* Kernel image chksum */ + unsigned long rootfs_chksum; /* rootfs image chksum */ + unsigned long kernel_len; /* Length of kernel */ + unsigned long rootfs_len; /* Length of rootfs */ + unsigned long image_chksum; /* checksum across length of image */ + unsigned long header_chksum; /* checksum across length of header */ +}; + +#define swap32(val) \ + ((unsigned int)( \ + (((unsigned int)(val) & (unsigned int)0x000000ffUL)) | \ + (((unsigned int)(val) & (unsigned int)0x0000ff00UL)) | \ + (((unsigned int)(val) & (unsigned int)0x00ff0000UL)) | \ + (((unsigned int)(val) & (unsigned int)0xff000000UL)) )) + +/* pling added 12/04/2008, define the Foxconn board ID length */ +#define FOXCONN_BOARD_ID_LEN 64 +/* Foxconn add end by Jenny Zhao, 07/02/2008*/ + +static int ui_cmd_set_board_param(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int ret = 0; + int i = 0; + int reset = 0; + + if(!argc) + { + reset += setBoardParam(); + } + + while(argc && !ret) + { + if(!strcmp(argv[i], "g")) + { + reset += setGponBoardParam(); + } + else { + /*Setup WPS Device Pin*/ + if(!strcmp(argv[i], "w")) + { + reset += setWpsDevicePinBoardParam(); + } + else + { + ret = -1; + } + } + + argc--; + i++; + } + + if(reset) + softReset(); + + return ret; +} + +static int ui_cmd_reset(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + softReset(); + return 0; +} + +// return 0 if 'y' +int yesno(void) +{ + char ans[5]; + + printf(" (y/n):"); + console_readline ("", ans, sizeof (ans)); + if (ans[0] != 'y') + return -1; + + return 0; +} + +// erase Persistent sector +static int ui_cmd_erase_psi(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + printf("Erase persisten storage data?"); + if (yesno()) + return -1; + + kerSysErasePsi(); + + return 0; +} + +static int ui_cmd_erase_nand(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + +#if (INC_NAND_FLASH_DRIVER==1) + char *flag; + int i, blk_end; + + flag = cmd_getarg(cmd,0); + + if (!flag) + { + printf("'e b' to reinitialize NAND flash or 'e a' to erase kernel\n"); + return 0; + } + + switch (*flag) + { + case 'b': + printf("Reinitialize NAND flash?"); + if (yesno()) + return 0; + printf("\nNow think carefully. Do you really,\n" + "really want to reinitialize the NAND flag?"); + if (yesno()) + return 0; + flash_sector_erase_int(NAND_REINIT_FLASH); + break; + case 'a': + printf("Erase NAND flash? The modem will not be able to boot from " + "flash"); + if (yesno()) + return 0; + + blk_end = flash_get_numsectors(); + for (i = 1; i < blk_end; i++) + { + printf("."); + flash_sector_erase_int(i); + } + printf("\n"); + break; + case 's': + { + extern void dump_spare(void); + dump_spare(); + } + break; + + case 'r': + { + extern unsigned char *mem_topofmem; + unsigned char *buf = (unsigned char *) mem_topofmem + 1024; + char *pszLen = cmd_getarg(cmd, 2); + int len = (pszLen) ? atoi(pszLen) : 64; + char *pszBlk = cmd_getarg(cmd, 1); + if( flash_read_buf(atoi(pszBlk), 0, buf, 16 * 1024) > 0 ) + { + void ui_dumpaddr( unsigned char *pAddr, int nLen ); + printf("block read into buffer at 0x%8.8lx\n", (unsigned long)buf); + ui_dumpaddr(buf, len); /* dump first few bytes */ + } + else + printf("block NOT read into buffer at 0x%8.8lx\n",(unsigned long)buf); + /* Can break into JTAG now to view entire block contents. */ + } + break; + default: + printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom\nusage: e [n/p/a]\n"); + return 0; + } +#elif (INC_SPI_PROG_NAND==1) + char *flag; + int i, blk_end; + + flash_change_flash_type(FLASH_IFC_NAND); + + flag = cmd_getarg(cmd,0); + + if (!flag) + { + printf("'n b' to reinitialize NAND flash or 'n a' to erase kernel on NAND\n"); + goto finish; + } + + switch (*flag) + { + case 'b': + printf("Reinitialize NAND flash?"); + if (yesno()) + goto finish; + printf("\nNow think carefully. Do you really,\n" + "really want to reinitialize the NAND flag?"); + if (yesno()) + goto finish; + flash_sector_erase_int(NAND_REINIT_FLASH); + break; + case 'a': + printf("Erase NAND flash? The modem will not be able to boot from " + "flash"); + if (yesno()) + goto finish; + + blk_end = flash_get_numsectors(); + for (i = 1; i < blk_end; i++) + { + printf("."); + flash_sector_erase_int(i); + } + printf("\n"); + break; + case 's': + { + extern void dump_spare(void); + dump_spare(); + } + break; + + case 'r': + { + extern unsigned char *mem_topofmem; + unsigned char *buf = (unsigned char *) mem_topofmem + 1024; + char *pszBlk = cmd_getarg(cmd, 1); + if( flash_read_buf(atoi(pszBlk), 0, buf, 16 * 1024) > 0 ) + { + void ui_dumpaddr( unsigned char *pAddr, int nLen ); + printf("block read into buffer at 0x%8.8lx\n", (unsigned long)buf); + ui_dumpaddr(buf, 64); /* dump first few bytes */ + } + else + printf("block NOT read into buffer at 0x%8.8lx\n",(unsigned long)buf); + /* Can break into JTAG now to view entire block contents. */ + } + break; + default: + printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom on NAND\nusage: n [n/p/a]\n"); + } +finish: + flash_change_flash_type(FLASH_IFC_SPI); + +#endif + + return 0; +} + +// erase some sectors +static int ui_cmd_erase(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + + //FILE_TAG cfeTag; + PFILE_TAG pTag; + char *flag; + int i, blk_start, blk_end; + + flag = cmd_getarg(cmd,0); + + if (!flag) + { + printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom\nusage: e [n/p/a]\n"); + return 0; + } + + switch (*flag) + { + case 'b': + printf("Erase boot loader?"); + if (yesno()) + return 0; + printf("\nNow think carefully. Do you really,\n" + "really want to erase the boot loader?"); + if (yesno()) + return 0; + flash_sector_erase_int(0); + break; + case 'n': + printf("Erase nvram?"); + if (yesno()) + return 0; + kerSysEraseNvRam(); + softReset(); + break; + case 'a': + + printf("Erase all flash (except bootrom)?"); + if (yesno()) + return 0; + + blk_end = flash_get_numsectors(); + if ((pTag = getTagFromPartition(1)) != NULL) + blk_start = flash_get_blk(atoi(pTag->rootfsAddress) + BOOT_OFFSET); + else // just erase all after cfe + { + FLASH_ADDR_INFO flash_info; + + kerSysFlashAddrInfoGet(&flash_info); + for( blk_start = 0, i = 0; i 0 ) + { + for (i = blk_start; i < blk_end; i++) + { + printf("."); + flash_sector_erase_int(i); + } + printf("\n"); + } + + /* Preserve the NVRAM fields that are used in the 'b' command. */ + softReset(); + break; + case 'p': + ui_cmd_erase_psi(cmd,argc,argv); + break; + default: + printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom\nusage: e [n/p/a]\n"); + return 0; + } + + return 0; +} + + +static int loadRaw(char *hostImageName, uint8_t *ptr) +{ + cfe_loadargs_t la; + int res; + + printf("Loading %s ...\n", hostImageName); + + // tftp only + la.la_filesys = "tftp"; + la.la_filename = hostImageName; + la.la_device = NULL; + la.la_address = (long)ptr; + la.la_options = NULL; + la.la_maxsize = FLASH_STAGING_BUFFER_SIZE; + la.la_flags = LOADFLG_SPECADDR; + + res = bcm63xx_cfe_rawload(&la); + if (res < 0) + { + ui_showerror(res, "Loading failed."); + return res; + } + printf("Finished loading %d bytes\n", res); + + return res; +} + +// flash the image +static int ui_cmd_flash_image(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; + char *imageName; + int res; + uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); + + g_processing_cmd = 1; + + imageName = cmd_getarg(cmd, 0); + + if (imageName) + { + if (strchr(imageName, ':')) + strcpy(hostImageName, imageName); + else + { + strcpy(hostImageName, bootInfo.hostIp); + strcat(hostImageName, ":"); + strcat(hostImageName, imageName); + } + } + else // use default flash file name + { + strcpy(hostImageName, bootInfo.hostIp); + strcat(hostImageName, ":"); + strcat(hostImageName, bootInfo.flashFileName); + } + + if ((res = loadRaw(hostImageName, ptr)) < 0) + { + g_processing_cmd = 0; + return res; + } + + // check and flash image + res = flashImage(ptr); + + if( res == 0 ) + { + char *p; + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + + for( p = nvramData.szBootline; p[2] != '\0'; p++ ) { + if( p[0] == 'r' && p[1] == '=' && p[2] == 'h' ) + { + /* Change boot source to "boot from flash". */ + p[2] = 'f'; + writeNvramData(&nvramData); + break; + } + } + softReset(); + } + + g_processing_cmd = 0; + return( res ); +} + +static int ui_cmd_write_chk_image(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; + char *imageName; + uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); + int res; + struct image_header *header; + unsigned long image_len, image_chksum; + + unsigned long header_len = 0; + unsigned long board_id_len = 0; + char board_id[FOX_BOARD_ID_MAX_LEN]; + uint8_t *tmp; + + g_processing_cmd = 1; + + imageName = cmd_getarg(cmd, 0); + if (!imageName) + return ui_showusage(cmd); + + if (strchr(imageName, ':')) + strcpy(hostImageName, imageName); + else + { + strcpy(hostImageName, bootInfo.hostIp); + strcat(hostImageName, ":"); + strcat(hostImageName, imageName); + } + + if ((res = loadRaw(hostImageName, ptr)) < 0) + { + g_processing_cmd = 0; + return res; + } + + /* check chk file */ + header = (struct image_header *)ptr; + header_len = swap32(header->header_len); + image_len = swap32(header->kernel_len); + image_chksum = swap32(header->kernel_chksum); + board_id_len = header_len - sizeof(struct image_header); + + memset(board_id, 0, sizeof(board_id)); + memcpy(board_id, header+1, board_id_len); + + printf("total:%d header:%d kernel:%d \n", res, header_len, image_len); + + tmp = ptr; + ptr += header_len; + res -= header_len; + + if (verify_checksum((char*)ptr, image_len, image_chksum)) { + printf("fail to comapre checksum ... \n "); + return CFE_ERR_BADIMAGE; + } + + memcpy(tmp, ptr, res); + + // check and flash image + res = writeWholeImage(tmp, res); + + printf("Finished flashing image.\n"); +/* + if (res == 0) + { + softReset(); + } +*/ + g_processing_cmd = 0; + return( res ); +} + +// write the whole image +static int ui_cmd_write_whole_image(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; + char *imageName; + uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); + int res; + + g_processing_cmd = 1; + + imageName = cmd_getarg(cmd, 0); + if (!imageName) + return ui_showusage(cmd); + + if (strchr(imageName, ':')) + strcpy(hostImageName, imageName); + else + { + strcpy(hostImageName, bootInfo.hostIp); + strcat(hostImageName, ":"); + strcat(hostImageName, imageName); + } + + if ((res = loadRaw(hostImageName, ptr)) < 0) + { + g_processing_cmd = 0; + return res; + } + + // check and flash image + res = writeWholeImage(ptr, res); + + printf("Finished flashing image.\n"); + + if (res == 0) + { + softReset(); + } + + g_processing_cmd = 0; + return( res ); +} + + +static int ui_cmd_flash_router_image(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; + char *imageName; + uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); + +#if (INC_NAND_FLASH_DRIVER==1) + uint8_t *tmp; +#endif + + int res; + + char board_id[FOX_BOARD_ID_MAX_LEN]; //Silver + int update=0; + char board_id_test[PROJECT_ID_LEN]; + +#if (INC_NAND_FLASH_DRIVER==1) + NVRAM_DATA nvramData; +#endif + + imageName = cmd_getarg(cmd, 0); + if (!imageName) + return ui_showusage(cmd); + + if (strchr(imageName, ':')) + strcpy(hostImageName, imageName); + else + { + strcpy(hostImageName, ""); + strcat(hostImageName, ":"); + strcat(hostImageName, ""); + } + + set_tftpd_state(TFTPD_STATE_WAIT_IMAGE); + if ((res = loadRaw(hostImageName, ptr)) < 0) { + printf("fail to load raw file ... \n"); + return res; + } + + if ( nmrp_server_detected == 0) + { + set_tftpd_state(TFTPD_STATE_OFF); // Foxconn added to turn on RED. + setPowerOnLedOn(); // Foxconn added to turn on RED. + } + + /* Foxconn add start by Jenny Zhao, 07/02/2008*/ + if (1) { + struct image_header *header; + unsigned long image_len, image_chksum; + + unsigned long header_len = 0; + unsigned long board_id_len = 0; + + header = (struct image_header *)ptr; + header_len = swap32(header->header_len); + image_len = swap32(header->kernel_len); + image_chksum = swap32(header->kernel_chksum); + /* Check Board ID first */ + board_id_len = header_len - sizeof(struct image_header); + memset(board_id, 0, sizeof(board_id)); + //for(i=0;i>> kerSysBcmImageSet= 0x%x\n", FLASH_IMAGE_START_ADDR); +#if (INC_NAND_FLASH_DRIVER==1) + memcpy(tmp, ptr, res); + if ((res = writeWholeImage(tmp, res) )!= 0) +#else + if ((res = kerSysBcmImageSet(FLASH_IMAGE_START_ADDR, ptr, res, 0)) != 0) +#endif + printf("Failed to flash image. Error: %d\n", res); + else + { + /* Foxconn added start, Silver Shih for burn board Id */ + if( strlen(board_id) < FOX_BOARD_ID_MAX_LEN) + { + if(strcmp(board_id_test, board_id) != 0) + //if (strcmp((char *)BOARD_DATA_ADDR, board_id) != 0) + { + //printf("board id not match, addr:0x%x\n", BOARD_DATA_ADDR); + //5 is indicated to burn board id +#if (INC_NAND_FLASH_DRIVER==0) + kerSysBcmImageSet(BOARD_DATA_ADDR, (unsigned char *)board_id, strlen(board_id)+1 , 5); +#endif + } + } + /* Foxconn added end, Silver Shih for burn board Id */ + + update=1; + printf("Finished flashing image in NMRP mode.\n"); + } + } + /* Foxconn added start pling 12/04/2008, for 'tftpd' */ +#if (INC_NAND_FLASH_DRIVER==0) + else if ((res = kerSysBcmImageSet(FLASH_IMAGE_START_ADDR, ptr, res, 0)) != 0) + printf("Failed to flash image. Error: %d\n", res); +#endif + else + printf("finishing flash image for flashimage command ... \n"); + + /* Foxconn added end pling 12/04/2008 */ + if (res == 0) + { + char *p; + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + + memcpy(nvramData.szFirmwareUpgradeBoardId, board_id, strlen(board_id)); + + for( p = nvramData.szBootline; p[2] != '\0'; p++ ) { + if( p[0] == 'r' && p[1] == '=' && p[2] == 'h' ) + { + /* Change boot source to "boot from flash". */ + p[2] = 'f'; + //writeNvramData(&nvramData); + break; + } + } + writeNvramData(&nvramData); + // softReset(); //remove by EricHuang + } + + if (nmrp_server_detected==1 && update==1) //NMRP mode + { + // Restore to factory default. + printf("try to restore to default, addr=0x%x\n", BOARD_FOXNVRAM_ADDR); +#if (INC_NAND_FLASH_DRIVER==0) + kerSysBcmImageSet(BOARD_FOXNVRAM_ADDR, (unsigned char *)"", 0x10000 , 5); +#endif + } + + return( res ); +} + +/************************************************************************ + * cfe_go(la) + * + * Starts a previously loaded program. cfe_loadargs.la_entrypt + * must be set to the entry point of the program to be started + * + * Input parameters: + * la - loader args + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_go(cfe_loadargs_t *la) +{ + if (la->la_entrypt == 0) { + xprintf("No program has been loaded.\n"); + return; + } + + if (net_getparam(NET_DEVNAME)) { + xprintf("Closing network.\n"); + net_uninit(); + } + + xprintf("Starting program at 0x%p\n",la->la_entrypt); + + setPowerOnLedOn(); + + cfe_start(la->la_entrypt); +} + +static int bootImage(char *fileSys, char *device, int zflag, char *imageName) +{ + cfe_loadargs_t la; + int res; + + // elf only + la.la_filesys = fileSys; + la.la_filename = imageName; + la.la_device = device; + la.la_options = 0; + la.la_maxsize = 0; + la.la_address = 0; + la.la_flags = zflag; + + res = bcm63xx_cfe_elfload(&la); + if (res != 0) + return res; + + if (la.la_flags & LOADFLG_NOISY) + xprintf("Entry at 0x%p\n",la.la_entrypt); + if ((la.la_flags & LOADFLG_EXECUTE) && (la.la_entrypt != 0)) { + cfe_go(&la); + } + + return res; +} + +// Compressed image head format in Big Endia: +// 1) Text Start address: 4 bytes +// 2) Program Entry point: 4 bytes +// 3) Compress image Length: 4 bytes +// 4) Compress data starts: compressed data +static int bootCompressedImage(unsigned int *puiCmpImage, int retry) +{ + unsigned char *pucSrc; + unsigned char *pucDst; + unsigned char *pucEntry; + unsigned int dataLen; + int ret = 0; + cfe_loadargs_t la; + + if( (unsigned long) puiCmpImage > FLASH_BASE ) + { + /* Boot compressed image from flash. */ + unsigned int *puiOrigCmpImage = puiCmpImage; + unsigned int *puiNewCmpImage = NULL; + unsigned int *puiOldCmpImage = NULL; + unsigned int *puiFs = NULL; + PFILE_TAG pTag1 = getTagFromPartition(1); + PFILE_TAG pTag2 = getTagFromPartition(2); + PFILE_TAG pCurTag = NULL; + unsigned int *puiImg= NULL; + int nImgLen = 0; + unsigned long ulCrc, ulImgCrc; + + if( pTag1 && pTag2 ) + { + /* Two images are on flash. Determine which one is being booted. */ + PFILE_TAG pNewTag = NULL; + PFILE_TAG pOldTag = NULL; + int seq1 = atoi(pTag1->imageSequence); + int seq2 = atoi(pTag2->imageSequence); + + if( seq1 > seq2 ) + { + pNewTag = pTag1; + pOldTag = pTag2; + } + else + { + pNewTag = pTag2; + pOldTag = pTag1; + } + + puiNewCmpImage = (unsigned int *) + (atoi(pNewTag->kernelAddress) + BOOT_OFFSET); + puiOldCmpImage = (unsigned int *) + (atoi(pOldTag->kernelAddress) + BOOT_OFFSET); + + if( puiOrigCmpImage == puiOldCmpImage ) + { + printf("Booting from previous image (0x%8.8lx) ...\n", + (unsigned long) atoi(pOldTag->rootfsAddress) + + BOOT_OFFSET - TAG_LEN); + pCurTag = pOldTag; + } + else + { + printf("Booting from latest image (0x%8.8lx) ...\n", + (unsigned long) atoi(pNewTag->rootfsAddress) + + BOOT_OFFSET - TAG_LEN); + pCurTag = pNewTag; + } + } + else + if( pTag1 || pTag2 ) + { + /* Only one image on flash. */ + pCurTag = (pTag1) ? pTag1 : pTag2; + printf("Booting from only image (0x%8.8lx) ...\n", + (unsigned long) atoi(pCurTag->rootfsAddress) + + BOOT_OFFSET - TAG_LEN); + } + else + { + /* No image on flash. */ + printf("No valid boot image\n"); + ret = -1; + } + + if( ret == 0 ) + { + /* Copy compressed image to SDRAM. */ + extern unsigned char *mem_topofmem; + FLASH_ADDR_INFO info; + unsigned char *pDest = (unsigned char *) mem_topofmem + 1024; + unsigned char *pImgEnd; + + kerSysFlashAddrInfoGet( &info ); + pImgEnd = flash_get_memptr( info.flash_meta_start_blk ); + kerSysReadFromFlash( pDest, (unsigned long) puiCmpImage, + (unsigned long) pImgEnd - (unsigned long) puiCmpImage ); + + puiCmpImage = (unsigned int *) pDest; + + /* Copy file system to SDRAM. */ + pDest += (unsigned long) pImgEnd - (unsigned long) + puiOrigCmpImage + 1024; + kerSysReadFromFlash( pDest, (unsigned long) + atoi(pCurTag->rootfsAddress) + BOOT_OFFSET, + atoi(pCurTag->rootfsLen)); + + puiFs = (unsigned int *) pDest; + + pucDst = (unsigned char *) *puiCmpImage; + pucEntry = (unsigned char *) *(puiCmpImage + 1); + dataLen = (unsigned int) *(puiCmpImage + 2); + pucSrc = (unsigned char*) (puiCmpImage + 3); + + printf("Code Address: 0x%08X, Entry Address: 0x%08x\n", + (unsigned int) pucDst, (unsigned int) pucEntry); + + + /* Check Linux file system CRC */ + ulImgCrc = *(unsigned long *) (pCurTag->imageValidationToken + + CRC_LEN); + if( ulImgCrc ) + { + if( puiFs ) + puiImg = puiFs; + else + { + puiImg = (unsigned int *) (atoi(pCurTag->rootfsAddress) + + BOOT_OFFSET); + } + nImgLen = atoi(pCurTag->rootfsLen); + + ulCrc = CRC32_INIT_VALUE; + ulCrc = getCrc32((unsigned char *) puiImg, (UINT32) nImgLen, ulCrc); + if( ulCrc != ulImgCrc) + { + printf("Linux file system CRC error. Corrupted image?\n"); + ret = -1; + } + } + + /* Check Linux kernel CRC */ + ulImgCrc = *(unsigned long *) (pCurTag->imageValidationToken + + (CRC_LEN * 2)); + if( ulImgCrc ) + { + puiImg = (unsigned int *) puiCmpImage; + nImgLen = atoi(pCurTag->kernelLen); + + ulCrc = CRC32_INIT_VALUE; + ulCrc = getCrc32((unsigned char *) puiImg, (UINT32) nImgLen, ulCrc); + if( ulCrc != ulImgCrc) + { + printf("Linux kernel CRC error. Corrupted image?\n"); + ret = -1; + } + } + + if( ret == 0 ) + { + ret = decompressLZMA(pucSrc, dataLen, pucDst, 23*1024*1024); + if (ret != 0) + printf("Failed to decompress image. Corrupted image?\n"); + } + + if (ret != 0) + { + /* Try to boot from the other flash image, if one exists. */ + if( retry == TRUE && pTag1 && pTag2 ) + { + int blk = 0; + unsigned char *pBase = flash_get_memptr(0); + unsigned int *flash_addr_kernel; + FLASH_ADDR_INFO flash_info; + + /* The boot image is bad. Erase the sector with the tag so + * the image is not tried in subsequent boots. + */ + kerSysFlashAddrInfoGet(&flash_info); + if( pCurTag == pTag1 ) + { + blk = flash_get_blk((int)(pBase + + flash_info.flash_rootfs_start_offset)); + } + else + if( pCurTag == pTag2 ) + { + blk = flash_get_blk((int) (pBase + + (flash_get_total_size()/2))); + } + + if( blk ) + flash_sector_erase_int(blk); + + /* Boot from the other flash image. */ + if( puiOrigCmpImage == puiOldCmpImage ) + flash_addr_kernel = puiNewCmpImage; + else + flash_addr_kernel = puiOldCmpImage; + + ret = bootCompressedImage( flash_addr_kernel, FALSE ); + } + } + else + { + printf("Decompression OK!\n"); + la.la_entrypt = (long) pucEntry; + printf("Entry at 0x%p\n",la.la_entrypt); + cfe_go(&la); // never return... + } + + } + } + else + { + /* Boot compressed image that was downloaded to RAM. */ + pucDst = (unsigned char *) *puiCmpImage; + pucEntry = (unsigned char *) *(puiCmpImage + 1); + dataLen = (unsigned int) *(puiCmpImage + 2); + pucSrc = (unsigned char*) (puiCmpImage + 3); + + printf("Code Address: 0x%08X, Entry Address: 0x%08x\n", + (unsigned int) pucDst, (unsigned int) pucEntry); + + ret = decompressLZMA(pucSrc, dataLen, pucDst, 23*1024*1024); + if (ret == 0) + { + printf("Decompression OK!\n"); + la.la_entrypt = (long) pucEntry; + printf("Entry at 0x%p\n",la.la_entrypt); + cfe_go(&la); // never return... + } + else + printf("Failed on decompression. Corrupted image?\n"); + } + + return ret; +} + +static int bootNandImageFromRootfs(int start_blk, int end_blk) +{ + extern unsigned char *mem_topofmem; + char fname[] = NAND_FLASH_BOOT_IMAGE_NAME; + int fname_len = strlen(fname); + int len = flash_get_sector_size(0); + unsigned char *buf = (unsigned char *) mem_topofmem + 1024; + unsigned char *pDest = (unsigned char *) buf + len; + unsigned long *pulDest = (unsigned long *) pDest; + unsigned char *p; + unsigned long version = 0; + unsigned long ino = 0; + int i, done; + struct jffs2_raw_dirent *pdir; + struct jffs2_raw_inode *pino; + int ret = 0; + + /* Find the directory entry. */ + for( i = start_blk, done = 0; i < end_blk && done == 0; i++ ) + { + if( flash_read_buf(i, 0, buf, len) > 0 ) + { + p = buf; + while( p < buf + len ) + { + pdir = (struct jffs2_raw_dirent *) p; + if( je16_to_cpu(pdir->magic) == JFFS2_MAGIC_BITMASK ) + { + if( je16_to_cpu(pdir->nodetype) == JFFS2_NODETYPE_DIRENT && + fname_len == pdir->nsize && + !memcmp(fname, pdir->name, fname_len) ) + { + if( je32_to_cpu(pdir->version) > version ) + { + if( (ino = je32_to_cpu(pdir->ino)) != 0 ) + { + version = je32_to_cpu(pdir->version); + + /* Setting 'done = 1' assumes there is only one + * version of the directory entry. This may not + * be correct if the file is updated after it + * was initially flashed. + * + * TBD. Look for a higher version of the + * directory entry without searching the entire + * flash part. + */ + done = 1; + break; + } + } + } + + p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; + } + else + break; + } + } + } + + if( version ) + { + unsigned char *pucSrc; + unsigned char *pucDst; + unsigned char *pucEntry; + unsigned int dataLen; + unsigned long cur_isize = 0; + + /* Get the file contents. */ + for( i = start_blk, done = 0; i < end_blk && done == 0; i++ ) + { + if( flash_read_buf(i, 0, buf, len) > 0 ) + { + p = buf; + while( p < buf + len ) + { + pino = (struct jffs2_raw_inode *) p; + if( je16_to_cpu(pino->magic) == JFFS2_MAGIC_BITMASK ) + { + if(je16_to_cpu(pino->nodetype)==JFFS2_NODETYPE_INODE && + je32_to_cpu(pino->ino) == ino) + { + unsigned long size = je32_to_cpu(pino->dsize); + unsigned long ofs = je32_to_cpu(pino->offset); + unsigned long isize = je32_to_cpu(pino->isize); + + if( size ) + { + memcpy(pDest + ofs, pino->data, size); + if( (cur_isize += size) >= isize ) + { + done = 1; + break; + } + } + } + + p += (je32_to_cpu(pino->totlen) + 0x03) & ~0x03; + } + else + break; + } + } + } + + pucDst = (unsigned char *) *pulDest; + pucEntry = (unsigned char *) *(pulDest + 1); + dataLen = (unsigned int) *(pulDest + 2); + pucSrc = (unsigned char *) (pulDest + 3); + + ret = decompressLZMA(pucSrc, dataLen, pucDst, 23*1024*1024); + if (ret != 0) + printf("Failed to decompress image. Corrupted image?\n"); + else + { + cfe_loadargs_t la; + + /* Save the rootfs offset of the rootfs that the Linux image + * is loaded from at the memory location before the Linux load + * address. The Linux image uses this value to determine the + * the rootfs to use. + */ + *(unsigned long *) (pucDst - 4) = (start_blk * len) / 1024; + + printf("Decompression OK!\n"); + la.la_entrypt = (long) pucEntry; + printf("Entry at 0x%p\n",la.la_entrypt); + cfe_go(&la); // never return... + } + } + else + printf("ERROR: A JFFS2 directory entry for %s was not found.\n",fname); + + return( ret ); +} + +static int bootNandImage(void) +{ + int ret = -1; + char *msgA, *msgB; + PFILE_TAG pTag1 = getTagFromPartition(1); + PFILE_TAG pTag2 = getTagFromPartition(2); + int seq1 = (pTag1) ? atoi(pTag1->imageSequence) : -1; + int seq2 = (pTag2) ? atoi(pTag2->imageSequence) : -1; + int start_blk, end_blk, rootfsA, rootfsB; + int len = flash_get_sector_size(0) / 1024; + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + validateNandPartTbl(&nvramData); + + if( pTag1 && pTag2 ) + { + if( bootInfo.bootPartition == BOOT_LATEST_IMAGE ) + { + msgA = "Booting from latest image (0x%8.8lx) ...\n"; + msgB = "Booting from previous image (0x%8.8lx) ...\n"; + rootfsA = (seq2 > seq1) ? NP_ROOTFS_2 : NP_ROOTFS_1; + } + else /* Boot from the previous image. */ + { + msgA = "Booting from previous image (0x%8.8lx) ...\n"; + msgB = "Booting from latest image (0x%8.8lx) ...\n"; + rootfsA = (seq2 <= seq1) ? NP_ROOTFS_2 : NP_ROOTFS_1; + } + + rootfsB = (rootfsA == NP_ROOTFS_2) ? NP_ROOTFS_1 : NP_ROOTFS_2; + start_blk = nvramData.ulNandPartOfsKb[rootfsA] / len; + end_blk = start_blk + + (nvramData.ulNandPartSizeKb[rootfsA] / len); + printf(msgA, FLASH_BASE + (nvramData.ulNandPartOfsKb[rootfsA] * 1024)); + if( (ret = bootNandImageFromRootfs(start_blk, end_blk)) != 0 ) + { + start_blk = nvramData.ulNandPartOfsKb[rootfsB] / len; + end_blk = start_blk + + (nvramData.ulNandPartSizeKb[rootfsB] / len); + printf(msgB, FLASH_BASE+(nvramData.ulNandPartOfsKb[rootfsB]*1024)); + if( (ret = bootNandImageFromRootfs(start_blk, end_blk)) != 0 ) + printf("Unable to boot image.\n"); + } + } + else + { + if( pTag1 ) + rootfsA = NP_ROOTFS_1; + else + if( pTag2 ) + rootfsA = NP_ROOTFS_2; + + if( pTag1 || pTag2 ) + { + start_blk = nvramData.ulNandPartOfsKb[rootfsA] / len; + end_blk = start_blk + + (nvramData.ulNandPartSizeKb[rootfsA] / len); + printf("Booting from only image (0x%8.8lx) ...\n", + FLASH_BASE + (nvramData.ulNandPartOfsKb[rootfsA] * 1024)); + if( (ret = bootNandImageFromRootfs(start_blk, end_blk)) != 0 ) + printf("Unable to boot image.\n"); + } + else + printf("No image found.\n"); + } + + return( ret ); +} + +static int autoRun(char *imageName) +{ + char ipImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; + int ret; + + if (bootInfo.runFrom == 'f' && !imageName) + { + if (!imageName) + { + if( flash_get_flash_type() != FLASH_IFC_NAND ) + { + PFILE_TAG pTag = getBootImageTag(); + int flash_addr_kernel = atoi(pTag->kernelAddress) + BOOT_OFFSET; + + ret = bootCompressedImage((unsigned int *)flash_addr_kernel, TRUE); + } + else + ret = bootNandImage(); + } + else + printf("Image name not allowed for boot from flash.\n"); + } + else // loading from host + { + if (imageName) + { + if (strchr(imageName, ':')) + strcpy(ipImageName, imageName); + else + { + strcpy(ipImageName, bootInfo.hostIp); + strcat(ipImageName, ":"); + strcat(ipImageName, imageName); + } + } + else // use default host file name + { + strcpy(ipImageName, bootInfo.hostIp); + strcat(ipImageName, ":"); + strcat(ipImageName, bootInfo.hostFileName); + } + + // try uncompressed image first + ret = bootImage("tftp", "eth0", LOADFLG_EXECUTE | LOADFLG_NOISY, ipImageName); + + if( ret == CFE_ERR_NOTELF ) + { + uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); + // next try as a compressed image + printf("Retry loading it as a compressed image.\n"); + if ((ret = loadRaw(ipImageName, ptr)) > 0) + bootCompressedImage((unsigned int *) ptr, TRUE); + } + } + + return ret; +} + + +// run program from compressed image in flash or from tftped program from host +static int ui_cmd_run_program(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int ret; + + if( getBootImageTag() || bootInfo.runFrom == 'r' ) + { + char *imageName; + + imageName = cmd_getarg(cmd, 0); + g_processing_cmd = 1; + ret = autoRun(imageName); + } + else + { + printf("ERROR: There is not a valid image to boot from.\n"); + ret = CFE_ERR_FILENOTFOUND; + } + + return( ret ); +} + + +static int ui_cmd_print_system_info(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + return printSysInfo(); +} + +static int ui_cmd_change_bootline(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + return changeBootLine(); +} + +static int ui_cmd_set_afe_id(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + return changeAfeId(); +} + +void ui_dumpaddr( unsigned char *pAddr, int nLen ); +void ui_dumpaddr( unsigned char *pAddr, int nLen ) +{ + static char szHexChars[] = "0123456789abcdef"; + char szLine[80]; + char *p = szLine; + unsigned char ch, *q; + int i = 0, j, size = 0; + unsigned long ul; + unsigned short us; + + if( ((unsigned long) pAddr & 0xff000000) == 0xff000000 || + ((unsigned long) pAddr & 0xff000000) == 0xb0000000 ) + { + if (nLen == 2) { + pAddr = (unsigned char *) ((unsigned long) pAddr & ~0x01); + } else if (nLen != 1) { + /* keeping the old logic as is. */ + if( ((unsigned long) pAddr & 0x03) != 0 ) + nLen += 4; + pAddr = (unsigned char *) ((unsigned long) pAddr & ~0x03); + } + } + while( nLen > 0 ) + { + sprintf( szLine, "%8.8lx: ", (unsigned long) pAddr ); + p = szLine + strlen(szLine); + + if( ((unsigned long) pAddr & 0xff000000) == 0xff000000 || + ((unsigned long) pAddr & 0xff000000) == 0xb0000000 ) + { + for(i = 0; i < 6 && nLen > 0; i += sizeof(long), nLen -= sizeof(long)) + { + if (nLen == 1) { + q = pAddr; + size = 1; + } else if (nLen == 2) { + us = *(unsigned short *)pAddr; + q = (unsigned char *) &us; + size = 2; + } else { + ul = *(unsigned long *) &pAddr[i]; + q = (unsigned char *) &ul; + size = sizeof(long); + } + for( j = 0; j < size; j++ ) + { + *p++ = szHexChars[q[j] >> 4]; + *p++ = szHexChars[q[j] & 0x0f]; + } + *p++ = ' '; + } + } + else + { + for(i = 0; i < 16 && nLen > 0; i++, nLen-- ) + { + ch = pAddr[i]; + + *p++ = szHexChars[ch >> 4]; + *p++ = szHexChars[ch & 0x0f]; + *p++ = ' '; + } + } + + for( j = 0; j < 16 - i; j++ ) + *p++ = ' ', *p++ = ' ', *p++ = ' '; + + *p++ = ' ', *p++ = ' ', *p++ = ' '; + + for( j = 0; j < i; j++ ) + { + ch = pAddr[j]; + *p++ = (ch >= ' ' && ch <= '~') ? ch : '.'; + } + + *p++ = '\0'; + printf( "%s\r\n", szLine ); + + pAddr += i; + } + printf( "\r\n" ); +} /* ui_dumpaddr */ + +static int ui_cmd_dump_mem(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *pszAddr = cmd_getarg(cmd, 0); + char *pszLen = cmd_getarg(cmd, 1); + if( pszAddr && pszLen ) + ui_dumpaddr((unsigned char *) xtoi(pszAddr), atoi(pszLen)); + else + printf("dm address_in_hex length_in_decimal\n"); + + return( 0 ); +} + +static int ui_cmd_set_mem(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *pszAddr = cmd_getarg(cmd, 0); + char *pszValue = cmd_getarg(cmd, 1); + char *pszSize = cmd_getarg(cmd, 2); + if( pszAddr && pszValue && pszSize ) + { + unsigned long ulAddr = (unsigned long) xtoi(pszAddr); + unsigned long ulValue = (unsigned long) atoi(pszValue); + int nSize = atoi(pszSize); + unsigned long *pul = (unsigned long *) ulAddr; + unsigned short *pus = (unsigned short *) ulAddr; + unsigned char *puc = (unsigned char *) ulAddr; + switch( nSize ) + { + case 4: + *pul = (unsigned long) ulValue; + break; + + case 2: + *pus = (unsigned short) ulValue; + break; + + case 1: + *puc = (unsigned char) ulValue; + break; + + default: + printf("sm address_in_hex value_in_hex size_4_2_or_1"); + break; + } + + ui_dumpaddr((unsigned char *) ulAddr, 4); + } + else + printf("sm address_in_hex value_in_hex size_4_2_or_1"); + + return( 0 ); +} + +static int ui_cmd_check_mem(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + #define RAM_BASE_ADDRESS 0xa0000000 + #define BOOT_CODE_SIZE 256 * 1024 // 256KB + #define CFE_MEM_SPACE 0xa0400000 + #define CFE_MEM_SIZE 4*1024*1024 // 4MB + #define MEMORY_SIZE 32*1024*1024 // 32MB + #define MAGIC_NUMBER 0xacacacac + + #define NAND_SECTOR_SIZE (16*1024) // 16KB + #define NAND_TEST_SIZE (30*1024*1024) // 30MB + + unsigned char *addr = NULL; + int pass=1; + +#if 0 + unsigned int buf1[NAND_SECTOR_SIZE/4]; + unsigned int buf2[NAND_SECTOR_SIZE/4]; + int i, j; +#endif + + printf("Verifying DRAM access...\n"); + for(addr=(unsigned char *)(RAM_BASE_ADDRESS+BOOT_CODE_SIZE); addr< (unsigned char *)(RAM_BASE_ADDRESS+MEMORY_SIZE); addr+=4) + { + if( addr< (unsigned char *)CFE_MEM_SPACE || addr > (unsigned char *)CFE_MEM_SPACE+CFE_MEM_SIZE ) + { + *(unsigned long *)addr = MAGIC_NUMBER; + } + } + + for(addr=(unsigned char *)(RAM_BASE_ADDRESS+BOOT_CODE_SIZE); addr< (unsigned char *)(RAM_BASE_ADDRESS+MEMORY_SIZE); addr+=4) + { + if( addr< (unsigned char *)CFE_MEM_SPACE || addr > (unsigned char *)CFE_MEM_SPACE+CFE_MEM_SIZE ) + { + if( *(unsigned long *)addr != MAGIC_NUMBER ) + pass=0; + } + } + if(pass) + printf("DRAM check OK!!!!\n"); + else + printf("DRAM check NG!!!!\n"); + +#if 0 + //printf("Verifying NAND flash access...\n"); + pass=1; + + for(i=0; i0) + offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_2] * 1024; + else + offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_1] * 1024; + + printf("Verifying NAND flash access from 0x%08x...\n", FLASH_BASE+offset); + + for(i=0; i -- if no filename, tftped from host with file name in 'Default host flash file name'", + ""); + + cmd_addcmd("c", + ui_cmd_change_bootline, + NULL, + "Change booline parameters", + "", + ""); + + cmd_addcmd("p", + ui_cmd_print_system_info, + NULL, + "Print boot line and board parameter info", + "", + ""); + + cmd_addcmd("r", + ui_cmd_run_program, + NULL, + "Run program from flash image or from host depend on [f/h] flag", + "eg. r [[hostip:]filenaem] if no filename, use the file name in 'Default host run file name'", + ""); + +#if (INC_SPI_PROG_NAND==1) + cmd_addcmd("n", + ui_cmd_erase_nand, + NULL, + "Erase NAND flash", + "e [a]", + ""); +#else + if( flash_get_flash_type() == FLASH_IFC_NAND ) + cmd_addcmd("e", + ui_cmd_erase_nand, + NULL, + "Erase NAND flash", + "e [a]", + ""); + else +#endif + cmd_addcmd("e", + ui_cmd_erase, + NULL, + "Erase [n]vram or [a]ll flash except bootrom", + "e [n/a]", + ""); + + cmd_addcmd("w", + ui_cmd_write_whole_image, + NULL, + "Write the whole image start from beginning of the flash", + "eg. w [hostip:]whole_image_file_name", + ""); + + cmd_addcmd("chw", + ui_cmd_write_chk_image, + NULL, + "Write chkw image start from beginning of the flash", + "eg. chkw [hostip:]whole_image_file_name", + ""); + + cmd_addcmd("dm", + ui_cmd_dump_mem, + NULL, + "Dump memory or registers.", + "eg. dm address_in_hex length_in_decimal", + ""); + + cmd_addcmd("sm", + ui_cmd_set_mem, + NULL, + "Set memory or registers.", + "eg. sm address_in_hex value_in_hex size_4_2_or_1", + ""); + + cmd_addcmd("nmrp", + ui_cmd_nmrp, + NULL, + "start memory or registers.", + "eg. nmrp ", + ""); + + cmd_addcmd("fr", + ui_cmd_flash_read, + NULL, + "read data from flash.", + "eg. fr addr ", + ""); + + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + cmd_addcmd("checkmem", + ui_cmd_check_mem, + NULL, + "Check memory.", + "Check memory.", + ""); + + ui_init_tftpdcmds(); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + return 0; +} + + +static int runDelay(int delayCount) +{ + int goAuto = 0; + + if (delayCount == 0) + return goAuto; + + printf("*** Press any key to stop auto run (%d seconds) ***\n", delayCount); + printf("Auto run second count down: %d", delayCount); + + cfe_sleep(CFE_HZ/8); // about 1/4 second + + while (1) + { + printf("\b%d", delayCount); + cfe_sleep(CFE_HZ); // about 1 second + if (console_status()) + break; + if (--delayCount == 0) + { + goAuto = 1; + break; + } + } + printf("\b%d\n", delayCount); + + return goAuto; +} + + +int bcm63xx_run(int breakIntoCfe) +{ + int goAuto; + + ui_init_bcm63xx_cmds(); + printSysInfo(); + enet_init(); + + goAuto = runDelay(bootInfo.bootDelay); + if (!breakIntoCfe && runDelay(bootInfo.bootDelay)) + { + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + if(_start_nmrp() != 0) + autoRun(NULL); // never returns + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + } + return goAuto; +} + + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_devs.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_devs.c new file mode 100755 index 0000000..ac75083 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_devs.c @@ -0,0 +1,734 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Board device initialization File: bcm94710_devs.c + * + * This is the "C" part of the board support package. The + * routines to create and initialize the console, wire up + * device drivers, and do other customization live here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * XX Copyright 2000,2001 + * Broadcom Corporation. All rights reserved. + * + * BROADCOM PROPRIETARY AND CONFIDENTIAL + * + * This software is furnished under license and may be used and + * copied only in accordance with the license. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_printf.h" + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#include "lib_string.h" +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +#include "cfe_timer.h" +#include "cfe.h" +#include "bcm_map.h" +#include "bcm_hwdefs.h" +#include "bcmTag.h" +#include "dev_bcm63xx_flash.h" +#include "bcm63xx_util.h" +#include "flash_api.h" + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#include "tftpd.h" +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +static int checkForResetToDefaultHold( unsigned short rstToDfltIrq ); + +/* Foxconn added start , 1/29/2010 */ +#include "gpio_drv.h" +#include "foxconnCfg.h" + +typedef enum +{ + kGpioInactive, + kGpioActive +} GPIO_STATE_t; +static int test_led_control(int on_off); +int power_led_toggle(int state); +int nmrp_led_toggle(void); +int verify_board_id(char *buf); +int verify_checksum(char *buf, unsigned long buf_len, unsigned long chksum); +#define NR_LED 24 +/* Foxconn added end , 1/29/2010 */ + +/* ********************************************************************* + * Devices we're importing + ********************************************************************* */ + +extern cfe_driver_t bcm63xx_uart; +extern cfe_driver_t bcm63xx_enet; + +/* ********************************************************************* + * board_console_init() + * + * Add the console device and set it to be the primary + * console. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void board_console_init(void) +{ + /* Add the serial port driver. */ + cfe_add_device(&bcm63xx_uart,0,0,0); + + cfe_set_console( "uart0" ); +} + + +/* ********************************************************************* + * board_device_init() + * + * Initialize and add other devices. Add everything you need + * for bootstrap here, like disk drives, flash memory, UARTs, + * network controllers, etc. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void board_device_init(void) +{ + unsigned short GPIOOverlays; + + kerSysFlashInit(); + +#if defined (_BCM96328_) + if( BpGetGPIOverlays(&GPIOOverlays) == BP_SUCCESS ) { + /* Start with all HW LEDs disabled */ + LED->ledHWDis |= 0xFFFFFF; + if (GPIOOverlays & BP_OVERLAY_SERIAL_LEDS) { + GPIO->PinMuxSel |= PINMUX_SERIAL_LED_DATA; + GPIO->PinMuxSel |= PINMUX_SERIAL_LED_CLK; + LED->ledInit |= LED_SERIAL_LED_EN; + } + /* Enable LED controller to drive GPIO */ + /* foxconn modified start to let hardware control only act LEDs, Bob, 08/04/2010 */ + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_0) { + GPIO->PinMuxSel |= PINMUX_EPHY0_ACT_LED; + //GPIO->GPIOMode |= (1 << EPHY0_SPD_LED); + //LED->ledHWDis &= ~(1 << EPHY0_SPD_LED); + } + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_1) { + GPIO->PinMuxSel |= PINMUX_EPHY1_ACT_LED; + //GPIO->GPIOMode |= (1 << EPHY1_SPD_LED); + //LED->ledHWDis &= ~(1 << EPHY1_SPD_LED); + } + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_2) { + GPIO->PinMuxSel |= PINMUX_EPHY2_ACT_LED; + //GPIO->GPIOMode |= (1 << EPHY2_SPD_LED); + //LED->ledHWDis &= ~(1 << EPHY2_SPD_LED); + } + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_3) { + GPIO->PinMuxSel |= PINMUX_EPHY3_ACT_LED; + //GPIO->GPIOMode |= (1 << EPHY3_SPD_LED); + //LED->ledHWDis &= ~(1 << EPHY3_SPD_LED); + } + /* foxconn modified end, Bob, 08/04/2010 */ + } +#endif + +#if defined (_BCM96362_) + if( BpGetGPIOverlays(&GPIOOverlays) == BP_SUCCESS ) { + /* Start with all HW LEDs disabled */ + LED->ledHWDis |= 0xFFFFFF; + if (GPIOOverlays & BP_OVERLAY_SERIAL_LEDS) { + GPIO->GPIOMode |= (GPIO_MODE_SERIAL_LED_CLK | GPIO_MODE_SERIAL_LED_DATA); + LED->ledInit |= LED_SERIAL_LED_EN; + } + /* Map HW LEDs to LED controller inputs and enable LED controller to drive GPIO */ + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_0) { + LED->ledLinkActSelHigh |= ((1 << (LED_ENET0 - 4)) << LED_4_LINK_SHIFT); + GPIO->LEDCtrl |= (1 << LED_ENET0); + LED->ledHWDis &= ~(1 << LED_ENET0); + } + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_1) { + LED->ledLinkActSelHigh |= ((1 << (LED_ENET1 - 4)) << LED_5_LINK_SHIFT); + GPIO->LEDCtrl |= (1 << LED_ENET1); + LED->ledHWDis &= ~(1 << LED_ENET1); + } + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_2) { + LED->ledLinkActSelHigh |= ((1 << (LED_ENET2 - 4)) << LED_6_LINK_SHIFT); + GPIO->LEDCtrl |= (1 << LED_ENET2); + LED->ledHWDis &= ~(1 << LED_ENET2); + } + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_3) { + LED->ledLinkActSelHigh |= ((1 << (LED_ENET3 - 4)) << LED_7_LINK_SHIFT); + GPIO->LEDCtrl |= (1 << LED_ENET3); + LED->ledHWDis &= ~(1 << LED_ENET3); + } + } +#endif + +#if defined (_BCM96368_) + TIMER->WDResetCount = 50000; // Assert reset for 1ms only. If reset asserted for too + // long chip reboots twice + if( BpGetGPIOverlays(&GPIOOverlays) == BP_SUCCESS ) { + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_0) { + GPIO->GPIOMode |= GPIO_MODE_EPHY0_LED; + GPIO->GPIODir |= GPIO_MODE_EPHY0_LED; + } + + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_1) { + GPIO->GPIOMode |= GPIO_MODE_EPHY1_LED; + GPIO->GPIODir |= GPIO_MODE_EPHY1_LED; + } + + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_2) { + GPIO->GPIOMode |= GPIO_MODE_EPHY2_LED; + GPIO->GPIODir |= GPIO_MODE_EPHY2_LED; + } + + if (GPIOOverlays & BP_OVERLAY_EPHY_LED_3) { + GPIO->GPIOMode |= GPIO_MODE_EPHY3_LED; + GPIO->GPIODir |= GPIO_MODE_EPHY3_LED; + } + + if (GPIOOverlays & BP_OVERLAY_SERIAL_LEDS) { + GPIO->GPIOMode |= (GPIO_MODE_SERIAL_LED_CLK | GPIO_MODE_SERIAL_LED_DATA); + GPIO->GPIODir |= (GPIO_MODE_SERIAL_LED_CLK | GPIO_MODE_SERIAL_LED_DATA); + GPIO->SerialLed = 0xffffffff; + } + } + + /* These blocks will be enabled by the appropriate driver if they are + * compiled into a router image. + */ + PERF->blkEnables &= ~(USBH_CLK_EN | PCM_CLK_EN | SAR_CLK_EN | USBD_CLK_EN); +#endif + +#if defined (_BCM96816_) + TIMER->WDResetCount = 50000; // Assert reset for 1ms only. If reset asserted for too + // long chip reboots twice + + if( BpGetGPIOverlays(&GPIOOverlays) == BP_SUCCESS ) { + if (GPIOOverlays & BP_OVERLAY_GPHY_LED_0) { + GPIO->GPIOMode |= GPIO_MODE_GPHY0_LED; + GPIO->GPIODir |= GPIO_MODE_GPHY0_LED; + } + + if (GPIOOverlays & BP_OVERLAY_GPHY_LED_1) { + GPIO->GPIOMode |= GPIO_MODE_GPHY1_LED; + GPIO->GPIODir |= GPIO_MODE_GPHY1_LED; + } + + if (GPIOOverlays & BP_OVERLAY_SERIAL_LEDS) { + GPIO->GPIOMode |= (GPIO_MODE_SERIAL_LED_CLK | GPIO_MODE_SERIAL_LED_DATA); + GPIO->GPIODir |= (GPIO_MODE_SERIAL_LED_CLK | GPIO_MODE_SERIAL_LED_DATA); + GPIO->SerialLed = 0xffffffff; + } + + if (GPIOOverlays & BP_OVERLAY_MOCA_LED) { + GPIO->GPIOMode |= GPIO_MODE_MOCA_LED; + GPIO->GPIODir |= GPIO_MODE_MOCA_LED; + } + } + + MISC->miscMoCARst &= ~(MISC_MOCA_RST_REF_DIV2RST | MISC_MOCA_RST_REF_FBDIVRST); + MISC->miscMoCARst &= ~MISC_MOCA_RST_REF_VCRST; + MISC->miscMoCARst &= ~(MISC_MOCA_RST_REF_OUTDIV_RESET_M_MASK | MISC_MOCA_RST_REF_MDIV2RST); + MISC->miscMoCACtl |= (7 << MISC_MOCA_CTL_REF_QP_ICTRL_SHIFT); + MISC->miscMoCARst &= ~MISC_MOCA_RST_REF_LD_RESET_STRT; + PERF->softResetB &= ~(SOFT_RST_MOCA_CPU | SOFT_RST_MOCA_SYS | SOFT_RST_MOCA); +#endif + +#if defined (_BCM96328_) || defined (_BCM96362_) + LED->ledInit &= ~LED_FAST_INTV_MASK; + LED->ledInit |= (LED_INTERVAL_20MS * 4) << LED_FAST_INTV_SHIFT; +#else + /* Set blink rate for hardware LEDs. */ + GPIO->LEDCtrl &= ~LED_INTERVAL_SET_MASK; + GPIO->LEDCtrl |= LED_INTERVAL_SET_80MS; +#endif + + /* Add the ethernet driver. */ + cfe_add_device( &bcm63xx_enet, 0, 0, 0); +} + + +void setGpio (unsigned short led_gpio, unsigned short led_state) +{ +#if 0 + unsigned short gpio_state; + + if (((led_gpio & BP_ACTIVE_LOW) && (led_state == LED_ON)) || + (!(led_gpio & BP_ACTIVE_LOW) && (led_state == LED_OFF))) + gpio_state = 0; + else + gpio_state = 1; +#endif + + GPIO->GPIODir |= GPIO_NUM_TO_MASK(led_gpio); + if( led_state ) + GPIO->GPIOio |= GPIO_NUM_TO_MASK(led_gpio); + else + GPIO->GPIOio &= ~GPIO_NUM_TO_MASK(led_gpio); +} + + +/* ********************************************************************* + * board_final_init() + * + * Do any final initialization, such as adding commands to the + * user interface. + * + * If you don't want a user interface, put the startup code here. + * This routine is called just before CFE starts its user interface. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void board_final_init(void) +{ + unsigned short rstToDfltIrq; + int breakIntoCfe = 0; + + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + int goAuto; + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + setAllLedsOff(); + setPowerOnLedOn(); + setGpio(GPIO_POWER_RED_LED, GPIO_POWER_RED_LED_ON); +#if (INC_SPI_PROG_NAND==1) + rstToDfltIrq = 1 ; + breakIntoCfe = rstToDfltIrq; +#else + if( (bootInfo.runFrom == 'f') && getBootImageTag() == NULL ) { + setBreakIntoCfeLed(); + printf("** Flash image not found. **\n\n"); + kerSysErasePsi(); + breakIntoCfe = 1; + } + + if( BpGetResetToDefaultExtIntr( &rstToDfltIrq ) == BP_SUCCESS ) { + if (checkForResetToDefaultHold( rstToDfltIrq )) { + kerSysErasePsi(); + /* Reset the default bootline if the board IP address has changed. */ + if (strcmp(bootInfo.boardIp, DEFAULT_BOARD_IP) != 0) { + setDefaultBootline(); + } + /* Foxconn modified start pling 09/09/2008 */ + /* just load default, don't break into console */ + //breakIntoCfe = 1; + printf("\n** Load default! **\n\n"); + /* Foxconn modified end pling 09/09/2008 */ + } + } +#endif + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + goAuto = bcm63xx_run(breakIntoCfe); + setBreakIntoCfeLed(); + if(goAuto) + { + ui_docommand("tftpd"); + } + /* Foxconn add end by Cliff Wang, 03/23/2010 */ +} + +/* ********************************************************************* + * Miscellaneous Board Functions + ********************************************************************* */ + +/* ********************************************************************* + * checkForResetToDefaultHold() + * + * Determines if the user is holding the reset to default button. + * + * Input parameters: + * Reset to default irq# + * + * Return value: + * 1 - break into the CFE, 0 - continue boot sequence + ********************************************************************* */ +#if (INC_SPI_PROG_NAND==0) +static int checkForResetToDefaultHold( unsigned short rstToDfltIrq ) +{ + const int nBreakIntoCfeDelay = 5; + int ret = 0; + int i; + uint32 irqBit; + volatile uint32 *extIrqReg; + + extIrqReg = &PERF->ExtIrqCfg; + irqBit = 1 << (rstToDfltIrq + EI_STATUS_SHFT); + +#if defined(_BCM96368_) + if (rstToDfltIrq >= BP_EXT_INTR_4 && rstToDfltIrq <= BP_EXT_INTR_5) { + extIrqReg = &PERF->ExtIrqCfg1; + irqBit = 1 << (rstToDfltIrq - BP_EXT_INTR_4 + EI_STATUS_SHFT); + } +#endif + + /* Loop while the reset to default button is depressed. */ + for(i = 0; !(*extIrqReg & irqBit); i++) { + if (i == nBreakIntoCfeDelay) { + setBreakIntoCfeLed(); + printf("\n*** Break into CFE console ***\n\n"); + ret = 1; + break; + } + cfe_sleep(CFE_HZ); + } + + return( ret ); +} +#endif +/* ********************************************************************* + * setLed(led_gpio, led_state) + * + * Turns on an LED. + * + * Input parameters: + * LED purpose + * LED State + * + * Return value: + * nothing + ********************************************************************* */ + +void setLed (unsigned short led_gpio, unsigned short led_state) +{ + unsigned short gpio_state; + + if (((led_gpio & BP_ACTIVE_LOW) && (led_state == LED_ON)) || + (!(led_gpio & BP_ACTIVE_LOW) && (led_state == LED_OFF))) + gpio_state = 0; + else + gpio_state = 1; + +#if defined(_BCM96328_) + /* Enable LED controller to drive this GPIO */ + if (!(led_gpio & BP_GPIO_SERIAL)) + GPIO->GPIOMode |= GPIO_NUM_TO_MASK(led_gpio); +#endif + +#if defined(_BCM96362_) + /* Enable LED controller to drive this GPIO */ + if (!(led_gpio & BP_GPIO_SERIAL)) + GPIO->LEDCtrl |= GPIO_NUM_TO_MASK(led_gpio); +#endif + +#if defined(_BCM96328_) || defined(_BCM96362_) + LED->ledMode &= ~(LED_MODE_MASK << GPIO_NUM_TO_LED_MODE_SHIFT(led_gpio)); + if( gpio_state ) + LED->ledMode |= (LED_MODE_OFF << GPIO_NUM_TO_LED_MODE_SHIFT(led_gpio)); + else + LED->ledMode |= (LED_MODE_ON << GPIO_NUM_TO_LED_MODE_SHIFT(led_gpio)); + +#else + if (led_gpio & BP_GPIO_SERIAL) { + while (GPIO->SerialLedCtrl & SER_LED_BUSY); + if( gpio_state ) + GPIO->SerialLed |= GPIO_NUM_TO_MASK(led_gpio); + else + GPIO->SerialLed &= ~GPIO_NUM_TO_MASK(led_gpio); + } + else { + GPIO->GPIODir |= GPIO_NUM_TO_MASK(led_gpio); + if( gpio_state ) + GPIO->GPIOio |= GPIO_NUM_TO_MASK(led_gpio); + else + GPIO->GPIOio &= ~GPIO_NUM_TO_MASK(led_gpio); + } +#endif +} + +/* ********************************************************************* + * setAllLedsOff() + * + * Turns off all board LEDs on init + * + * Input parameters: + * LED purpose + * + * Return value: + * nothing + ********************************************************************* */ + +void setAllLedsOff(void) +{ + unsigned short gpio; + + if( BpGetAdslLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetAdslFailLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetSecAdslLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetSecAdslFailLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetWirelessSesLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetHpnaLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetWanDataLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetWanErrorLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetBootloaderPowerOnLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetBootloaderStopLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetVoipLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetVoip1LedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetVoip2LedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetPotsLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetGponLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetMoCALedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetGponFailLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetMoCAFailLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); +} + +/* ********************************************************************* + * setPowerOnLedOn() + * + * Turns on the Power LED. + * + * Input parameters: + * LED purpose + * + * Return value: + * nothing + ********************************************************************* */ + +void setPowerOnLedOn(void) +{ + unsigned short gpio; + if( BpGetBootloaderStopLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + if( BpGetBootloaderPowerOnLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_ON ); +} + + +/* ********************************************************************* + * setBreakIntoCfeLed() + * + * Turns on the alarm LED. + * + * Input parameters: + * LED purpose + * + * Return value: + * nothing + ********************************************************************* */ + +void setBreakIntoCfeLed(void) +{ + unsigned short gpio; + if( BpGetBootloaderStopLedGpio( &gpio ) == BP_SUCCESS ) { + setLed( gpio, LED_ON ); + if( BpGetBootloaderPowerOnLedGpio( &gpio ) == BP_SUCCESS ) + setLed( gpio, LED_OFF ); + } +} + +/* ********************************************************************* + * softReset() + * + * Resets the board. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void softReset(void) +{ + printf( "\nResetting board...\n" ); +#if defined (_BCM96816_) + /* Work around reset issues */ + HVG->reg_hvg_cha_misc |= HVG_SOFT_INIT_0; + HVG->reg_hvg_chb_misc |= HVG_SOFT_INIT_0; +#endif + +#if defined(_BCM96328_) + TIMER->SoftRst |= SOFT_RESET; +#else + PERF->pll_control |= SOFT_RESET; // soft reset mips +#if defined(_BCM96368_) || defined(_BCM96816_) + PERF->pll_control = 0; +#endif +#endif + while (1); +} + +/* Foxconn added start , 1/29/2010 */ +extern int nmrp_server_detected; + +int test_led_control(int on_off) +{ + // unsigned short gpio; + int tftpd_state = get_tftpd_state(); + + if (tftpd_state == TFTPD_STATE_OFF) + { + setGpio(GPIO_POWER_RED_LED, GPIO_POWER_RED_LED_ON); //turn red power led + } + else if ( (tftpd_state == TFTPD_STATE_WAIT_IMAGE) || (tftpd_state == TFTPD_STATE_WRITE_IMAGE) ) + { + if (on_off==1) + { + setGpio(GPIO_POWER_RED_LED, GPIO_POWER_RED_LED_ON); + } + else + { + setGpio(GPIO_POWER_RED_LED, GPIO_POWER_RED_LED_OFF); + } + } + + return 0; +} + +int power_led_toggle(int state) +{ + test_led_control(state); + return 0; +} + +int nmrp_led_toggle(void) +{ + static int led_state = 0; + + /* Foxconn added end for U12H154 */ + + if (led_state == 0) + { + led_state = 1; + setGpio(18, 1); + } + else + { + led_state = 0; + setGpio(18, 0); + } + + return 0; +} + + +static unsigned long calculate_checksum (int action, char *s, int size) +{ + static unsigned long c0, c1; + unsigned long checksum, b; + int i; + switch (action) + { + case 0: + c0 = c1 = 0; + break; + + case 1: + for (i = 0; i < size; i++) + { + c0 += s[i] & 0xff; + c1 += c0; + /* check the lan/wan ports status, Foxconn added by EricHuang, 10/24/2006 */ + if ((i % 90000) == 0) + { + printf("."); +// bcm_robo_check_link_status(); + } + } + break; + + case 2: + b = (c0 & 65535) + ((c0 >> 16) & 65535); + c0 = ((b >> 16) + b) & 65535; + + b = (c1 & 65535) + ((c1 >> 16) & 65535); + c1 = ((b >> 16) + b) & 65535; + + checksum = ((c1 << 16) | c0); + + return checksum; + } + return 0; +} + +int verify_checksum(char *buf, unsigned long buf_len, unsigned long chksum) +{ + unsigned long cal_chksum = 0; + + xprintf("Loading ."); + calculate_checksum (0, NULL, 0); + calculate_checksum (1, buf, buf_len); + cal_chksum = calculate_checksum (2, NULL, 0); + printf("\n"); + + + if (cal_chksum != chksum) { + xprintf("Image chksum: 0x%08X\n", chksum); + xprintf("Calc chksum: 0x%08X\n", cal_chksum); + return -1; + } + +#ifdef _DEBUG + //printf("verify_checksum calculate_checksum = 0x%08X\n", cal_chksum); + //printf("verify_checksum image_chksum = 0x%08X\n", chksum); +#endif + + return 0; +} + +int verify_board_id(char *buf) +{ + /* char *board_id = ( char *)BOARD_DATA_ADDR; */ + char board_id[PROJECT_ID_LEN]; + + kerSysReadFromFlash(board_id, BOARD_DATA_ADDR, PROJECT_ID_LEN); + + if(nmrp_server_detected==1) // in NMRP mode + { + if (strncmp(buf, board_id, PROJECT_ID_LEN) != 0) + { + printf("verify_board_id failed: (%s)\n", buf); + return -1; + } + } + else + { + if (strcmp(buf, board_id) != 0) + { + /* Foxconn removed start pling 12/10/2008 */ + /* Don't check board ID in 'tftpd' mode */ + printf("verify_board_id failed: (%s)\n", buf); + //return -1; + /* Foxconn removed end pling 12/10/2008 */ + } + } + return 0; +} + +/* Foxconn added end , 1/29/2010 */ + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_env_subr.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_env_subr.c new file mode 100755 index 0000000..3ce3a28 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_env_subr.c @@ -0,0 +1,277 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Environment variable subroutines File: env_subr.c + * + * This module contains routines to muck with environment variables + * (manage the list, read/write to nvram, etc.) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "env_subr.h" +///#include "nvram_subr.h" + +#include "cfe_error.h" +#include "cfe.h" + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef struct cfe_envvar_s { + queue_t qb; + int flags; + char *name; + char *value; + /* name and value go here */ +} cfe_envvar_t; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +queue_t env_envvars = {&env_envvars,&env_envvars}; +extern unsigned int cfe_startflags; + +/* ********************************************************************* + * env_findenv(name) + * + * Locate an environment variable in the in-memory list + * + * Input parameters: + * name - name of env var to find + * + * Return value: + * cfe_envvar_t pointer, or NULL if not found + ********************************************************************* */ + +static cfe_envvar_t *env_findenv(const char *name) +{ + queue_t *qb; + cfe_envvar_t *env; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + env = (cfe_envvar_t *) qb; + if (strcmp(env->name,name) == 0) break; + } + + if (qb == &env_envvars) return NULL; + + return (cfe_envvar_t *) qb; + +} + +/* ********************************************************************* + * env_enum(idx,name,namelen,val,vallen) + * + * Enumerate environment variables. This routine locates + * the nth environment variable and copies its name and value + * to user buffers. + * + * The namelen and vallen variables must be preinitialized to + * the maximum size of the output buffer. + * + * Input parameters: + * idx - variable index to find (starting with zero) + * name,namelen - name buffer and length + * val,vallen - value buffer and length + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_enum(int idx,char *name,int *namelen,char *val,int *vallen) +{ + queue_t *qb; + cfe_envvar_t *env; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + if (idx == 0) break; + idx--; + } + + if (qb == &env_envvars) return CFE_ERR_ENVNOTFOUND; + env = (cfe_envvar_t *) qb; + + *namelen = xstrncpy(name,env->name,*namelen); + *vallen = xstrncpy(val,env->value,*vallen); + + return 0; + +} + +/* ********************************************************************* + * env_envtype(name) + * + * Return the type of the environment variable + * + * Input parameters: + * name - name of environment variable + * + * Return value: + * flags, or <0 if error occured + ********************************************************************* */ +int env_envtype(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (env) { + return env->flags; + } + + return CFE_ERR_ENVNOTFOUND; +} + + + +/* ********************************************************************* + * env_delenv(name) + * + * Delete an environment variable + * + * Input parameters: + * name - environment variable to delete + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_delenv(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (!env) return 0; + + if (!(env->flags & ENV_FLG_READONLY)) { + q_dequeue((queue_t *) env); + KFREE(env); + return 0; + } + + return CFE_ERR_ENVNOTFOUND; +} + +/* ********************************************************************* + * env_getenv(name) + * + * Retrieve the value of an environment variable + * + * Input parameters: + * name - name of environment variable to find + * + * Return value: + * value, or NULL if variable is not found + ********************************************************************* */ + +char *env_getenv(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (env) { + return env->value; + } + + return NULL; +} + + +/* ********************************************************************* + * env_setenv(name,value,flags) + * + * Set the value of an environment variable + * + * Input parameters: + * name - name of variable + * value - value of variable + * flags - flags for variable (ENV_FLG_xxx) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_setenv(const char *name,char *value,int flags) +{ + cfe_envvar_t *env; + int namelen; + + env = env_findenv(name); + if (env) { + if (!(flags & ENV_FLG_ADMIN)) { + if (env->flags & ENV_FLG_READONLY) return CFE_ERR_ENVREADONLY; + } + q_dequeue((queue_t *) env); + KFREE(env); + } + + namelen = strlen(name); + + env = KMALLOC(sizeof(cfe_envvar_t) + namelen + 1 + strlen(value) + 1,0); + if (!env) return CFE_ERR_NOMEM; + + env->name = (char *) (env+1); + env->value = env->name + namelen + 1; + env->flags = (flags & ENV_FLG_MASK); + + strcpy(env->name,name); + strcpy(env->value,value); + + q_enqueue(&env_envvars,(queue_t *) env); + + return 0; +} +int env_save(void) +{ + return 0; +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c new file mode 100755 index 0000000..dcd5b0a --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_httpd.c @@ -0,0 +1,1031 @@ +/* milli_httpd - pretty small HTTP server +** A combination of +** micro_httpd - really small HTTP server +** and +** mini_httpd - small HTTP server +** +** Copyright 1999,2000 by Jef Poskanzer . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#if (CFG_WEB_SERVER==1) + +/** Includes. **/ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" +#include "cfe_error.h" +#include "cfe.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" + +#include "bsp_config.h" + +#include "bcmTag.h" +#include "bcm63xx_util.h" + + +/** Externs. **/ + +extern char ul_html[]; +extern char ulinfo_html[]; +extern int ul_html_size; +extern int ulinfo_html_size; + +extern int g_console_abort; +extern int g_processing_cmd; + +/** Defines. **/ + +#define SERVER_NAME "micro_httpd" +#define SERVER_URL "http://www.acme.com/software/micro_httpd/" +#define SERVER_PORT 80 +#define PROTOCOL "HTTP/1.0" +#define POST_DATA_START (unsigned char *) \ + BOARD_IMAGE_DOWNLOAD_ADDRESS +#define SOCKET_CLOSED -100 +#define NUM_SOCKETS 4 + +/* Return codes from cfe_web_gets. */ +#define WEB_GETS_DONE 1 +#define WEB_GETS_PENDING 2 +#define WEB_GETS_ERROR 3 + +/* HTTP states. */ +#define HTTP_INITIAL 0 +#define HTTP_READ_FIRST_HDR 1 +#define HTTP_READ_REMAINING_HDRS 2 +#define HTTP_READ_POST_DATA 3 + +/* HTTP POST status */ +#define UPLOAD_OK '0' +#define UPLOAD_FAIL_NO_MEM '1' +#define UPLOAD_FAIL_NO_FILENAME '2' +#define UPLOAD_FAIL_ILLEGAL_IMAGE '3' +#define UPLOAD_FAIL_IMAGE_TOOBIG '4' +#define UPLOAD_FAIL_CORRUPT_IMAGE '5' +#define UPLOAD_FAIL_FLASH '6' +#define UPLOAD_FATAL '7' +#define UPLOAD_PENDING '8' +#define UPLOAD_TCP_ERROR '9' + +/* HTTP upload image formats. */ +#define NO_IMAGE_FORMAT 0 +#define BROADCOM_IMAGE_FORMAT 1 +#define FLASH_IMAGE_FORMAT 2 + + +/** Structs. **/ + +typedef struct +{ + int s; + int state; + int web_buf_idx; + int post_content_length; + char web_first_buf[128]; + char web_buf[256]; +} SOCKET_INFO, *PSOCKET_INFO; + +typedef struct +{ + char *wp_name; + char *wp_content_buf; + int *wp_content_size; + char *wp_mime_type; +} WEB_PAGE_MAP, *PWEB_PAGE_MAP; + + +/** Globals. **/ + +static int g_listen_idx = 0; +static unsigned char *g_image_start = NULL; +static int g_image_len = 0; +static int g_image_format = NO_IMAGE_FORMAT; +static int g_post_data_in_progress = 0; +static int g_post_data_idx = 0; + +static SOCKET_INFO g_socket_info[NUM_SOCKETS]; + +static WEB_PAGE_MAP g_web_page_map[] = + { + {"/", ul_html, &ul_html_size, "text/html"}, + {"/upload.html", ul_html, &ul_html_size, "text/html"}, + {"/uploadinfo.html", ulinfo_html, &ulinfo_html_size, "text/html"}, + {NULL, NULL, 0, NULL} + }; + + +/** Prototypes. **/ + +int cfe_web_check(void); +void cfe_web_fg_process(void); +void cfe_web_poll(void *x); +static void cfe_web_listen( int *listen_idx_ptr ); +static void cfe_web_bg_process(PSOCKET_INFO si); +static int cfe_web_gets( char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int s ); +static int read_first_hdr(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr); +static int read_remaining_hdrs(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr, int *content_length_ptr); +static char read_post_data( int s, unsigned char *post_data_start, + int content_length, int *post_data_idx_ptr ); +static char parse_post_data( int s, unsigned char *post_data_start, + int post_data_length, unsigned char **image_start_ptr, int *image_len_ptr, + int *image_format_ptr ); +static void send_error( int s, int status, char* title, char* extra_header, + char* text ); +static void send_error( int s, int status, char* title, char* extra_header, + char* text ); +static void send_headers( int s, int status, char* title, char* extra_header, + char* mime_type ); +static void send_page( int s, char *path, int send_headers_flag, + char **substs, int num_substs ); +static int cfe_web_tcp_send( int s, char *buf, int size ); +void * memmove(void * dest,const void *src,size_t count); + + +/*************************************************************************** + * Function Name: cfe_web_check + * Description : Checks if an image has been downloaded through an HTTP POST + * request and is ready to be written to flash memory. + * Returns : 1 - image is ready to be flashed, 0 - nothing to do + ***************************************************************************/ +int cfe_web_check(void) +{ + return( (g_image_format != NO_IMAGE_FORMAT) ? 1 : 0 ); +} /* cfe_web_check */ + + +/*************************************************************************** + * Function Name: cfe_web_process + * Description : Calls the appropriate functions to write an image to + * flash memory. + * Returns : None. + ***************************************************************************/ +void cfe_web_fg_process(void) +{ + /* Wait so the uploadinfo web page can be displayed on the browser. */ + cfe_sleep(CFE_HZ * 2); + if( g_image_format == BROADCOM_IMAGE_FORMAT ) + flashImage( g_image_start ); + else + if( g_image_format == FLASH_IMAGE_FORMAT ) + writeWholeImage( g_image_start, g_image_len ); + + if( g_image_format != NO_IMAGE_FORMAT ) + softReset(); + +} /* cfe_web_process */ + + +/*************************************************************************** + * Function Name: cfe_web_poll + * Description : The entry point function that is called in the background + * at polled intervals. It listens for and processes HTTP + * requests. + * Returns : None. + ***************************************************************************/ +void cfe_web_poll(void *x) +{ + static int first_time = 1; + static int in_cfe_web_poll = 0; + + PSOCKET_INFO si; + int i; + + if( in_cfe_web_poll == 0 ) + { + in_cfe_web_poll = 1; + + /* If this is the first time that this function was called, initialize + * the socket info data array. + */ + if( first_time == 1 ) + { + first_time = 0; + for( i = 0, si = g_socket_info; i < NUM_SOCKETS; i++, si++ ) + { + si->s = SOCKET_CLOSED; + si->state = HTTP_READ_FIRST_HDR; + si->web_buf_idx = 0; + si->post_content_length = 0; + } + } + + /* Check the connection state of each socket. */ + for( i = 0, si = g_socket_info; i < NUM_SOCKETS; i++, si++ ) + { + cfe_web_listen( &g_listen_idx ); + if( si->s >= 0 ) + { + unsigned int connflag; + tcp_status( si->s, &connflag, NULL, NULL ); + if( connflag == TCPSTATUS_CONNECTED ) + { + cfe_web_bg_process( si ); + POLL(); + } + else + if( connflag == TCPSTATUS_NOTCONN ) + { + console_log("web warning: Unexpected TCP disconnect."); + tcp_close(si->s); + si->s = SOCKET_CLOSED; + si->state = HTTP_READ_FIRST_HDR; + si->web_buf_idx = 0; + } + } + } + + in_cfe_web_poll = 0; + } +} /* cfe_web_poll */ + + +/*************************************************************************** + * Function Name: cfe_web_listen + * Description : This function checks to see if TCP listen can be issued + * on the HTTP port and issues the listen if it can. + * Returns : None. + ***************************************************************************/ +static void cfe_web_listen( int *listen_idx_ptr ) +{ + static int port = SERVER_PORT; + + int listen_idx = *listen_idx_ptr; + PSOCKET_INFO si = &g_socket_info[listen_idx]; + + /* If a TCP socket has been opened, check its connection status. */ + if( si->s >= 0 ) + { + unsigned int connflag; + tcp_status( si->s, &connflag, NULL, NULL ); + + /* If the socket is connection, set the next socket index to listen for + * a TCP connection. + */ + if( connflag == TCPSTATUS_CONNECTED ) + { + listen_idx = (listen_idx + 1) % NUM_SOCKETS; + si = &g_socket_info[listen_idx]; + } + } + + /* If the TCP socket has not been opened, open it and listen for a TCP + * connection. + */ + if( si->s == SOCKET_CLOSED ) + { + /* Open the socket in non-blocking mode. */ + POLL(); + if( (si->s = tcp_socket()) >= 0 ) + { + console_log("web info: Waiting for connection on socket %d.", si->s); + if( tcp_listen(si->s, port) != 0 ) + console_log("web error: listen error on %d.", si->s); + } + else + { + console_log("web error %d: Could not create TCP socket.", si->s); + si->s = SOCKET_CLOSED; + } + } + + *listen_idx_ptr = listen_idx; +} /* cfe_web_listen */ + + +/*************************************************************************** + * Function Name: cfe_web_bg_process + * Description : This function processes an HTTP request on a socket. + * Returns : None. + ***************************************************************************/ +static void cfe_web_bg_process(PSOCKET_INFO si) +{ + char post_subst[] = {UPLOAD_FATAL, '\0'}; + char *post_substs[] = {post_subst}; + int close_tcp = 0; + + switch( si->state ) + { + case HTTP_READ_FIRST_HDR: + if( read_first_hdr( si->s, si->web_first_buf, + sizeof(si->web_first_buf), &si->web_buf_idx, &close_tcp ) == 0 ) + { + /* Not all of the first header has been read yet. Try again later.*/ + break; + } + + /* The first header has been read. */ + si->state = HTTP_READ_REMAINING_HDRS; + + /* fall thru */ + + case HTTP_READ_REMAINING_HDRS: + if( read_remaining_hdrs( si->s, si->web_buf, sizeof(si->web_buf), + &si->web_buf_idx, &close_tcp, &si->post_content_length ) ) + { + if( g_processing_cmd == 0 ) + { + char *method = NULL; + char *path = NULL; + char *ptr = (char *) si->web_first_buf; + + method = gettoken(&ptr); + if( method ) + path = gettoken(&ptr); + + /* Process the HTTP request. Only GET and POST are supported. */ + if( method && path ) + { + if( !strcmpi( method, "get" ) ) + { + send_page( si->s, path, 1, NULL, 0 ); + close_tcp = 1; + } + else + { + if( !strcmpi( method, "post" ) ) + { + if( g_post_data_in_progress == 0 ) + { + g_post_data_in_progress = 1; + si->state = HTTP_READ_POST_DATA; + } + else + { + send_error( si->s, 501, "Upload Busy", + (char*) 0, + "An image is already being uploaded." ); + close_tcp = 1; + } + } + else + { + send_error( si->s, 501, "Not Implemented", + (char*) 0, + "That method is not implemented." ); + close_tcp = 1; + } + } + } + else + { + send_error( si->s, 400, "Bad Request", (char *) 0, + "Can't parse request." ); + close_tcp = 1; + } + } + else + { + /* A download and flash image command is being executed from + * the serial port console. + */ + send_error( si->s, 400, "Bad Request", (char *) 0, + "Console command is in progress." ); + close_tcp = 1; + } + } + + if( si->state != HTTP_READ_POST_DATA ) + break; + + case HTTP_READ_POST_DATA: + /* Read the post data, which contains an image to flash, into low + * memory. + */ + if( (post_subst[0] = read_post_data( si->s, POST_DATA_START, + si->post_content_length, &g_post_data_idx )) == UPLOAD_OK ) + { + /* Verify that the post data is a valid image to flash. */ + post_subst[0] = parse_post_data( si->s, POST_DATA_START, + g_post_data_idx, (unsigned char **) &g_image_start, &g_image_len, + &g_image_format ); + } + + switch( post_subst[0] ) + { + case UPLOAD_PENDING: + break; + + case UPLOAD_TCP_ERROR: + close_tcp = 1; + g_post_data_in_progress = 0; + g_post_data_idx = 0; + break; + + case UPLOAD_OK: + /* Notify foreground to abort the console input so it can + * write the image to flash memory. + */ + g_console_abort = 1; + + send_page(si->s, "/uploadinfo.html", 0, post_substs, 1); + close_tcp = 1; + g_post_data_idx = 0; + break; + + default: + /* The image was downloaded OK but there was a problem with it + * so it could not be written to flash memory. + */ + send_page(si->s, "/uploadinfo.html", 0, post_substs, 1); + close_tcp = 1; + g_post_data_in_progress = 0; + g_post_data_idx = 0; + break; + } + break; + } + + /* Close the socket if the HTTP transaction is done. */ + if( close_tcp ) + { + POLL(); + tcp_close(si->s); + si->s = SOCKET_CLOSED; + si->state = HTTP_READ_FIRST_HDR; + si->web_buf_idx = 0; + si->post_content_length = 0; + } +} /* cfe_web_poll */ + + +/*************************************************************************** + * Function Name: cfe_web_gets + * Description : Reads from a socket up to a or . The socket + * is non-blocking. + * Returns : WEB_GETS_DONE - Complete line was read. + * WEB_GETS_PENDING - Line partially read. + * WEB_GETS_ERROR - Socket error. + ***************************************************************************/ +static int cfe_web_gets( char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int s ) +{ + int ret = WEB_GETS_PENDING; + unsigned char ch; + int web_buf_idx = *web_buf_idx_ptr; + char *p = web_buf + web_buf_idx; + int continue_reading = 1; + + while( web_buf_idx < web_buf_size && continue_reading ) + { + switch( tcp_recv( s, &ch, 1 ) ) + { + case 0: /* no characters are available to receive */ + continue_reading = 0; + break; + + case 1: /* character was read */ + if( ch == '\n' ) + { + *p = '\0'; + continue_reading = 0; + ret = WEB_GETS_DONE; + } + else + if( ch != '\r' ) + { + *p++ = ch; + web_buf_idx++; + } + break; + + default: + continue_reading = 0; + ret = WEB_GETS_ERROR; + break; + } + } + + if( web_buf_idx == web_buf_size ) + { + web_buf[web_buf_idx - 1] = '\0'; + ret = WEB_GETS_DONE; + } + + *web_buf_idx_ptr = web_buf_idx; + + return( ret ); +} /* cfe_web_gets */ + + +/*************************************************************************** + * Function Name: read_first_hdr + * Description : This function reads the first HTTP header which contains + * the method (GET, POST), path and protocol. For example, + * GET /upload.html HTTP/1.1 + * Returns : 1 - First header was read, 0 - was not read. + ***************************************************************************/ +static int read_first_hdr(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr) +{ + int ret = 0; + int sts = cfe_web_gets( web_buf, web_buf_size, web_buf_idx_ptr, s ); + + switch( sts ) + { + case WEB_GETS_DONE: + /* The first HTTP header has been read into web_buf. */ + *web_buf_idx_ptr = 0; + ret = 1; + break; + + case WEB_GETS_ERROR: + console_log("web error: TCP read error."); + *close_tcp_ptr = 1; + break; + } + + return( ret ); +} /* read_first_hdr */ + + +/*************************************************************************** + * Function Name: read_remaining_hdrs + * Description : This function reads the remaining HTTP headers. + * Returns : 1 - Remaining headers were read, 0 - were not read. + ***************************************************************************/ +static int read_remaining_hdrs(int s, char *web_buf, int web_buf_size, + int *web_buf_idx_ptr, int *close_tcp_ptr, int *content_length_ptr) +{ + int ret = 0; + int sts = WEB_GETS_DONE; + + while( sts == WEB_GETS_DONE ) + { + sts = cfe_web_gets( web_buf, web_buf_size, web_buf_idx_ptr, s ); + switch( sts ) + { + case WEB_GETS_DONE: + if( *web_buf_idx_ptr == 0 ) + { + /* The remaining HTTP headers have been read. */ + ret = 1; + sts = WEB_GETS_PENDING; + } + else + { + char *p2 = web_buf; + char *p1 = gettoken(&p2); + if( !strcmpi( p1, "Content-Length:" ) ) + *content_length_ptr=atoi(p2); + *web_buf_idx_ptr = 0; + } + break; + + case WEB_GETS_ERROR: + console_log("web error: TCP read error."); + *close_tcp_ptr = 1; + break; + } + } + + return( ret ); +} /* read_remaining_hdrs */ + + +/*************************************************************************** + * Function Name: read_post_data + * Description : This function reads HTTP POST data which is the contents of + * a new image to write to flash memory. + * Returns : UPLOAD_OK - all data read + * UPLOAD_PENDING - not all data read + * UPLOAD_TCP_ERROR - TCP error + ***************************************************************************/ +static char read_post_data( int s, unsigned char *post_data_start, + int content_length, int *post_data_idx_ptr ) +{ + char ret = UPLOAD_PENDING; + int post_data_idx = *post_data_idx_ptr; + int len; + + do + { + len = tcp_recv( s, (unsigned char*)(post_data_start + post_data_idx), + content_length - post_data_idx ); + post_data_idx += len; + POLL(); + cfe_web_listen( &g_listen_idx ); + } while( len > 0 && post_data_idx < content_length ); + + *post_data_idx_ptr = post_data_idx; + + if( len < 0 ) + { + console_log("web error: TCP read error receiving post data."); + ret = UPLOAD_TCP_ERROR; + } + else + if( post_data_idx == content_length ) + ret = UPLOAD_OK; + + return( ret ); +} /* read_post_data */ + + +/*************************************************************************** + * Function Name: parse_post_data + * Description : This function parses HTTP POST data which is the contents of + * a new image to write to flash memory. + * Returns : UPLOAD_OK or UPLOAD_xxx error + ***************************************************************************/ +static char parse_post_data( int s, unsigned char *post_data_start, + int post_data_length, unsigned char **image_start_ptr, int *image_len_ptr, + int *image_format_ptr ) +{ + char ret = UPLOAD_OK; + unsigned char *p = post_data_start; + int boundary_size = 0; + + /* Convert the start boundary field into a string. It will be compared + * against the end boundary field below. + */ + while( *p != '\r' && *p != '\n' && + ((int) p - (int) post_data_start) < post_data_length ) + { + p++; + } + + if( *p == '\r' || *p == '\n' ) + { + *p++ = '\0'; + boundary_size = strlen((char*)post_data_start); + } + else + { + console_log("web error: HTTP POST start bound field not found."); + ret = UPLOAD_FATAL; + } + + /* Verify that a filename has been entered. */ + if( ret == UPLOAD_OK ) + { + unsigned char *fname = NULL; + while( memcmp( p, "\r\n\r\n", strlen("\r\n\r\n") ) ) + { + if( *p == 'f' && !memcmp( p, "filename=", strlen("filename=" ) ) ) + { + p += strlen("filename="); + fname = p + 1; + if( p[0] == '"' && p[1] != '"' ) + { + p++; + while( *p != '"' && *p != '\r' && *p != '\n' ) + p++; + *p = '\0'; + } + else + { + console_log("web error: HTTP POST filename not specified."); + ret = UPLOAD_FAIL_NO_FILENAME; + } + break; + } + + p++; + } + + if( fname == NULL ) + { + console_log("web error: HTTP POST filename field not found."); + ret = UPLOAD_FATAL; + } + } + + /* Find the start of the image which starts after two consecutive + * carriage return, linefeed pairs. + */ + if( ret == UPLOAD_OK ) + { + while( memcmp( p, "\r\n\r\n", strlen("\r\n\r\n") ) ) + p++; + + p += strlen("\r\n\r\n"); + if( p[0] != '\r' || p[1] != '\n' || + memcmp(p + 2, post_data_start, boundary_size ) ) + { + *image_start_ptr = p; + } + else + { + console_log("web error: HTTP POST no image data."); + ret = UPLOAD_FAIL_ILLEGAL_IMAGE; + } + } + + /* Find the end of the image which contains the same boundary field as + * at the start of the buffer. + */ + if( ret == UPLOAD_OK ) + { + p = post_data_start + post_data_length - 1; + while( *p == '\r' || *p == '\n' || *p == '-' ) + p--; + p[1] = '\0'; + p -= boundary_size + 1; + if( !memcmp( p + strlen("\r\n"), post_data_start, boundary_size ) ) + *image_len_ptr = (int) p - (int) *image_start_ptr; + else + { + console_log("web error: HTTP POST end bound field not found."); + ret = UPLOAD_FATAL; + } + } + + /* Verify that the image is (or should be) a Broadcom flash format file or + * a flash image format. + */ + if( ret == UPLOAD_OK ) + { + /* Align the image on a 16 byte boundary */ + if( ((unsigned long) *image_start_ptr & 0x0f) != 0 ) + { + unsigned char *dest = (unsigned char *) + ((unsigned long) *image_start_ptr & ~0x0f); + unsigned char *src = *image_start_ptr; + memmove( dest, src, *image_len_ptr ); + *image_start_ptr = dest; + } + + /* Check if the first part of the image is the Broadcom defined TAG + * record. + */ + if( verifyTag( (FILE_TAG *) *image_start_ptr, 0 ) == -1 ) + { + /* It is not a Broadcom flash format file. Now check if it is a + * flash image format file. A flash image format file must have a + * CRC at the end of the image. + */ + unsigned char *image_ptr = *image_start_ptr; + unsigned long image_len = (unsigned long) *image_len_ptr - TOKEN_LEN; + unsigned long crc = CRC32_INIT_VALUE; + + crc = getCrc32(image_ptr, image_len, crc); + if (memcmp(&crc, image_ptr + image_len, CRC_LEN) == 0) + { + console_log("web info: Upload %lu bytes, flash image format.", + *image_len_ptr); + *image_format_ptr = FLASH_IMAGE_FORMAT; + } + else + { + console_log("web info: Upload %lu bytes, invalid image format.", + *image_len_ptr); + ret = UPLOAD_FAIL_ILLEGAL_IMAGE; + } + } + else + { + console_log("web info: Upload %lu bytes, Broadcom image format.", + *image_len_ptr); + *image_format_ptr = BROADCOM_IMAGE_FORMAT; + } + } + + return( ret ); +} /* parse_post_data */ + + +/*************************************************************************** + * Function Name: send_error + * Description : This function sends an HTTP error response to the browser. + * Returns : None. + ***************************************************************************/ +static void send_error( int s, int status, char* title, char* extra_header, + char* text ) +{ + int tcpret = 0; + char buf[128]; + send_headers( s, status, title, extra_header, "text/html" ); + sprintf( (char *) buf, "%d %s\n" + "

%d %s

\n", status, title, status, + title ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( (char *) buf, "%s\n", text ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( (char *) buf, "
\n
%s
\n" + "\n", SERVER_URL, SERVER_NAME ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + + if( tcpret < 0 ) + console_log("web error: TCP write error sending error response."); +} /* send_error */ + + +/*************************************************************************** + * Function Name: send_headers + * Description : This function sends an HTTP response to the browser. + * Returns : None. + ***************************************************************************/ +static void send_headers( int s, int status, char* title, char* extra_header, + char* mime_type ) +{ + int tcpret = 0; + char buf[128]; + unsigned long secs = (unsigned long) cfe_ticks / CFE_HZ; + + sprintf( buf, "%s %d %s\r\n", PROTOCOL, status, title ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( buf, "Server: %s\r\n", SERVER_NAME ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + sprintf( buf, "Date: Thu, 01 Jan 1970 %2.2d:%2.2d:%2.2d GMT\r\n", + secs / 3600, (secs % 3600) / 60, secs % 60 ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + if ( extra_header != (char*) 0 ) + { + sprintf( buf, "%s\r\n", extra_header ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + } + if ( mime_type != (char*) 0 ) + { + sprintf( buf, "Content-Type: %s\r\n", mime_type ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + } + sprintf( buf, "Connection: close\r\n\r\n" ); + tcpret = tcp_send( s, (unsigned char*)buf, strlen(buf) ); + + if( tcpret < 0 ) + console_log("web error: TCP write error sending header."); +} /* send_headers */ + + +/*************************************************************************** + * Function Name: send_page + * Description : This function sends a web page to the browser. + * Returns : None. + ***************************************************************************/ +static void send_page( int s, char *path, int send_headers_flag, + char **substs, int num_substs ) +{ + PWEB_PAGE_MAP map; + + /* Find the specified web page. */ + for( map = g_web_page_map; map->wp_name; map++ ) + { + if( !strcmp( map->wp_name, path ) ) + { + /* Found the web page. */ + char *p2 = NULL; + char *p = (char *) map->wp_content_buf; + int size = *map->wp_content_size; + int i = 0; + + if( send_headers_flag ) + send_headers( s, 200, "Ok", (char *) 0, map->wp_mime_type ); + + /* Make substitutions. */ + while( i < num_substs && (p2 = strnchr( p, '<', size )) != NULL ) + { + if( p2[1] == '%' ) + { + /* Found a substituion pattern. Send up to that point. */ + if( cfe_web_tcp_send( s, p, (int) (p2 - p) ) < 0 ) + break; + + /* Send substitution value. */ + if( cfe_web_tcp_send( s, substs[i], strlen(substs[i]) ) < 0 ) + break; + + i++; + + /* Skip to end of substitution pattern. */ + p = p2 + 2; /* skip '<%' */ + while( p[0] != '%' || p[1] != '>' ) + p++; + p += 2; /* skip '%.' */ + } + else + { + /* Was not a substitution pattern. Send up that point. */ + p2++; + if( cfe_web_tcp_send( s, p, (int) (p2 - p) ) < 0 ) + break; + + p = p2; + } + + size = *map->wp_content_size - ((int)p-(int)map->wp_content_buf); + } + + /* Send remaining part of web page after the last substitution. */ + cfe_web_tcp_send( s, p, size ); + + break; /* for loop */ + } + } + + if( map->wp_name == NULL ) + send_error( s, 404, "Not Found", (char*) 0, "File not found." ); +} /* send_page */ + + +/*************************************************************************** + * Function Name: cfe_web_tcp_send + * Description : Sends data on a TCP non blocking connection and waits for + * it to finish. + * Returns : > 0 - bytes send, < 0 - TCP error + ***************************************************************************/ +static int cfe_web_tcp_send( int s, char *buf, int size ) +{ + int i, len = 0; + + for( i = 0; i < size; i += len ) + { + POLL(); + cfe_web_listen( &g_listen_idx ); + len = tcp_send( s, (unsigned char*)(buf + i), size - i ); + if( len < 0 ) + { + console_log("web error: TCP write error sending a web page."); + break; + } + } + + return( len ); +} /* cfe_web_tcp_send */ + + +/** + * 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; +} + +#else + +/*************************************************************************** + * Function Name: Functions stubs. + * Description : Used when the web server is not compiled into the CFE. + * Returns : None. + ***************************************************************************/ + +int cfe_web_check(void); +void cfe_web_fg_process(void); +void cfe_web_poll(void *x); + +int cfe_web_check(void) +{ + return(0); +} + +void cfe_web_fg_process(void) +{ +} + +void cfe_web_poll(void *x) +{ +} + +#endif + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_elf.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_elf.c new file mode 100755 index 0000000..fb3f122 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_elf.c @@ -0,0 +1,388 @@ + +//********** for boot -elf thing from cfe_ldr_elf.c +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * ELF Program Loader File: cfe_ldr_elf.c + * + * This program parses ELF executables and loads them into memory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_mem.h" + +#include "cfe.h" +#include "cfe_loader.h" +#include "cfe_fileops.h" +#include "elf.h" + +#include "cfe_boot.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +int bcm63xx_cfe_elfload(cfe_loadargs_t *la); + +const cfe_loader_t elfloader = { + "elf", + bcm63xx_cfe_elfload, + 0}; + +/* ********************************************************************* + * readprogsegment(fsctx,ref,addr,size) + * + * Read a program segment, generally corresponding to one + * section of the file. + * + * Input parameters: + * fsctx - file I/O dispatch + * ref - reference data for open file handle + * addr - target virtual address + * size - size of region to read + * + * Return value: + * Number of bytes copied or <0 if error occured + ********************************************************************* */ + +static int readprogsegment(fileio_ctx_t *fsctx,void *ref, + void *addr,int size,int flags) +{ + int res; + +#ifdef __long64 + if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size); +#else + if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size); +#endif + + res = fs_read(fsctx,ref,addr,size); + + if (res < 0) return CFE_ERR_IOERR; + if (res != size) return CFE_ERR_BADELFFMT; + + return size; +} + + +/* ********************************************************************* + * readclearbss(addr,size) + * + * Process a BSS section, zeroing memory corresponding to + * the BSS. + * + * Input parameters: + * addr - address to zero + * size - length of area to zero + * + * Return value: + * number of zeroed bytes or <0 if error occured + ********************************************************************* */ + +static int readclearbss(void *addr,int size,int flags) +{ + +#ifdef __long64 + if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size); +#else + if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size); +#endif + + if (size > 0) memset(addr,0,size); + return size; +} + + +/* ********************************************************************* + * elfgetshdr(ops,ref,ep) + * + * Get a section header from the ELF file + * + * Input parameters: + * ops - file I/O dispatch + * ref - reference data for open file + * ep - extended header info + * + * Return value: + * copy of section header (malloc'd) or NULL if no memory + ********************************************************************* */ + +static Elf32_Shdr *elfgetshdr(fileio_ctx_t *fsctx,void *ref,Elf32_Ehdr *ep) +{ + Elf32_Shdr *shtab; + unsigned size = ep->e_shnum * sizeof(Elf32_Shdr); + + shtab = (Elf32_Shdr *) KMALLOC(size,0); + if (!shtab) { + return NULL; + } + + if (fs_seek(fsctx,ref,ep->e_shoff,FILE_SEEK_BEGINNING) != ep->e_shoff || + fs_read(fsctx,ref,(uint8_t *)shtab,size) != size) { + KFREE(shtab); + return NULL; + } + + return (shtab); +} + +/* ********************************************************************* + * elfload_internal(ops,ref,entrypt,flags) + * + * Read an ELF file (main routine) + * + * Input parameters: + * ops - file I/O dispatch + * ref - open file handle + * entrypt - filled in with entry vector + * flags - generic boot flags + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int elfload_internal(fileio_ctx_t *fsctx,void *ref, + long *entrypt,int flags) +{ + Elf32_Ehdr *ep; + Elf32_Phdr *phtab = 0; + Elf32_Shdr *shtab = 0; + unsigned int nbytes; + int i; + int res; + Elf32_Ehdr ehdr; + + ep = &ehdr; + if (fs_read(fsctx,ref,(uint8_t *) ep,sizeof(*ep)) != sizeof(*ep)) { + return CFE_ERR_IOERR; + } + + /* check header validity */ + if (ep->e_ident[EI_MAG0] != ELFMAG0 || + ep->e_ident[EI_MAG1] != ELFMAG1 || + ep->e_ident[EI_MAG2] != ELFMAG2 || + ep->e_ident[EI_MAG3] != ELFMAG3) { + return CFE_ERR_NOTELF; + } + + if (ep->e_ident[EI_CLASS] != ELFCLASS32) return CFE_ERR_NOT32BIT; + +#ifdef __MIPSEB + if (ep->e_ident[EI_DATA] != ELFDATA2MSB) return CFE_ERR_WRONGENDIAN; /* big endian */ +#endif +#ifdef __MIPSEL + if (ep->e_ident[EI_DATA] != ELFDATA2LSB) return CFE_ERR_WRONGENDIAN; /* little endian */ +#endif + + if (ep->e_ident[EI_VERSION] != EV_CURRENT) return CFE_ERR_BADELFVERS; + if (ep->e_machine != EM_MIPS) return CFE_ERR_NOTMIPS; + + /* Is there a program header? */ + if (ep->e_phoff == 0 || ep->e_phnum == 0 || + ep->e_phentsize != sizeof(Elf32_Phdr)) { + return CFE_ERR_BADELFFMT; + } + + /* Load program header */ + nbytes = ep->e_phnum * sizeof(Elf32_Phdr); + phtab = (Elf32_Phdr *) KMALLOC(nbytes,0); + if (!phtab) { + return CFE_ERR_NOMEM; + } + + if (fs_seek(fsctx,ref,ep->e_phoff,FILE_SEEK_BEGINNING) != ep->e_phoff || + fs_read(fsctx,ref,(uint8_t *)phtab,nbytes) != nbytes) { + KFREE(phtab); + return CFE_ERR_IOERR; + } + + /* + * From now on we've got no guarantee about the file order, + * even where the section header is. Hopefully most linkers + * will put the section header after the program header, when + * they know that the executable is not demand paged. We assume + * that the symbol and string tables always follow the program + * segments. + */ + + /* read section table (if before first program segment) */ + if (ep->e_shoff < phtab[0].p_offset) { + shtab = elfgetshdr(fsctx,ref,ep); + } + + /* load program segments */ + /* We cope with a badly sorted program header, as produced by + * older versions of the GNU linker, by loading the segments + * in file offset order, not in program header order. */ + + while (1) { + Elf32_Off lowest_offset = ~0; + Elf32_Phdr *ph = 0; + + /* find nearest loadable segment */ + for (i = 0; i < ep->e_phnum; i++) + if ((phtab[i].p_type == PT_LOAD) && (phtab[i].p_offset < lowest_offset)) { + ph = &phtab[i]; + lowest_offset = ph->p_offset; + } + if (!ph) { + break; /* none found, finished */ + } + /* load the segment */ + if (ph->p_filesz) { + if (fs_seek(fsctx,ref,ph->p_offset,FILE_SEEK_BEGINNING) != ph->p_offset) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return CFE_ERR_BADELFFMT; + } + res = readprogsegment(fsctx,ref, + (void *)(intptr_t)(signed)ph->p_vaddr, + ph->p_filesz,flags); + if (res != ph->p_filesz) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return res; + } + } + if (ph->p_filesz < ph->p_memsz) { + res = readclearbss((void *)(intptr_t)(signed)ph->p_vaddr + ph->p_filesz, + ph->p_memsz - ph->p_filesz,flags); + if (res < 0) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return res; + } + } + + ph->p_type = PT_NULL; /* remove from consideration */ + } + + KFREE(phtab); + + *entrypt = (intptr_t)ep->e_entry; /* return entry point */ + return 0; +} + + + +/* ********************************************************************* + * cfe_elfload(ops,file,flags) + * + * Read an ELF file (main entry point) + * + * Input parameters: + * ops - fileio dispatch + * file - name of file to read + * ept - where to put entry point + * flags - load flags + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int bcm63xx_cfe_elfload(cfe_loadargs_t *la) +{ + fileio_ctx_t *fsctx; + void *ref; + int res; + + /* + * Look up the file system type and get a context + */ + + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (la->la_flags & LOADFLG_COMPRESSED) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the remote file + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return CFE_ERR_FILENOTFOUND; + } + + /* + * Load the image. + */ + + la->la_entrypt = 0; + res = elfload_internal(fsctx,ref,&(la->la_entrypt),la->la_flags); + + /* + * All done, release resources + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + return res; +} + + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_raw.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_raw.c new file mode 100755 index 0000000..eaabf14 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ldr_raw.c @@ -0,0 +1,368 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * RAW Program Loader File: cfe_ldr_raw.c + * + * This program reads raw binaries into memory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_boot.h" +#include "cfe_bootblock.h" + +#include "cfe_loader.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +int bcm63xx_cfe_rawload(cfe_loadargs_t *la); + +const cfe_loader_t rawloader = { + "raw", + bcm63xx_cfe_rawload, + 0}; + +/* ********************************************************************* + * cfe_findbootblock(la,fsctx,ref) + * + * Find the boot block on the specified device. + * + * Input parameters: + * la - loader args (to be filled in) + * ops - file operations + * ref - reference for open file handle + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +static int cfe_findbootblock(cfe_loadargs_t *la, + fileio_ctx_t *fsctx, + void *ref, + struct boot_block *bootblock) +{ + uint32_t checksum = 0; + uint32_t calcsum = 0; + uint32_t secsize = 0; + uint64_t secoffset = 0; + int res; + int curblk; + + /* + * Search for the boot block. Stop when we find + * something with a matching checksum and magic + * number. + */ + + fs_seek(fsctx,ref,0,FILE_SEEK_BEGINNING); + + for (curblk = 0; curblk < BOOT_BLOCK_MAXLOC; curblk++) { + + + /* Read a block */ + + res = fs_read(fsctx,ref, + (unsigned char *) bootblock, + sizeof(struct boot_block)); + + if (res != sizeof(struct boot_block)) { + return CFE_ERR_IOERR; + } + + /* Verify magic number */ + +#if defined(CONFIG_MIPS_BRCM) + continue; +#else + if (bootblock->bb_magic != BOOT_MAGIC_NUMBER) { + continue; + } +#endif + + /* Extract fields from block */ + + checksum = ((uint32_t) (bootblock->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK)); + bootblock->bb_hdrinfo &= ~BOOT_HDR_CHECKSUM_MASK; + secsize = ((uint32_t) (bootblock->bb_secsize & BOOT_SECSIZE_MASK)); + secoffset = bootblock->bb_secstart; + + /* Verify block's checksum */ + + CHECKSUM_BOOT_DATA(&(bootblock->bb_magic),BOOT_BLOCK_SIZE,&calcsum); + + if (checksum == calcsum) { + break; + } + } + + /* + * Okay, determine if we were successful. + */ + +#if !defined(CONFIG_MIPS_BRCM) + if (bootblock->bb_magic != BOOT_MAGIC_NUMBER) { + return CFE_ERR_INVBOOTBLOCK; + } +#endif + + if (checksum != calcsum) { + return CFE_ERR_BBCHECKSUM; + } + + /* + * If we get here, we had a valid boot block. + */ + + return 0; +} + + +/* ********************************************************************* + * cfe_rawload(la) + * + * Read a raw (unformatted) boot file + * + * Input parameters: + * la - loader args + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +int bcm63xx_cfe_rawload(cfe_loadargs_t *la) +{ + int res; + fileio_ctx_t *fsctx; + const fileio_dispatch_t *ops; + void *ref; + int ttlcopy = 0; + int findbb; + int devinfo; + struct boot_block bootblock; + uint8_t *ptr; + uint8_t *bootcode; +#if !defined(CONFIG_MIPS_BRCM) + uint32_t checksum,calcsum; +#endif + uint64_t secoffset = 0; + int32_t maxsize; + int amtcopy; + int thisamt; + uint32_t loadflags; + int onedot; + + loadflags = la->la_flags; + + /* + * Set starting address and maximum size. You can either + * explicitly set this (with LOADFLG_SPECADDR) or + * let CFE decide. If CFE decides, the load address + * will be BOOT_START_ADDRESS in all cases. + * The size is dependant on the device type: block and flash + * devices will get this info from the boot block, + * and network devices will get the info by reaching EOF + * on reads, up to the maximum size of the boot area. + */ + + if (loadflags & LOADFLG_SPECADDR) { + bootcode = (uint8_t *) la->la_address; + maxsize = la->la_maxsize; + findbb = FALSE; /* don't find a boot block */ + } + else { + bootcode = (uint8_t *) BOOT_START_ADDRESS; + maxsize = BOOT_AREA_SIZE; + findbb = FALSE; + devinfo = la->la_device ? cfe_getdevinfo(la->la_device) : 0; + + /* + * If the device is either a disk or a flash device, + * we will expect to find a boot block. + * Serial and network devices do not have boot blocks. + */ + if ((devinfo >= 0) && + ( ((devinfo & CFE_DEV_MASK) == CFE_DEV_DISK) || + ((devinfo & CFE_DEV_MASK) == CFE_DEV_FLASH) )) { + findbb = TRUE; + } + } + + + /* + * merge in any filesystem-specific flags + */ + + ops = cfe_findfilesys(la->la_filesys); + if (!ops) return CFE_ERR_FSNOTAVAIL; + loadflags |= ops->loadflags; + + /* + * turn off the boot block if requested. + */ + + if (loadflags & LOADFLG_NOBB) findbb = FALSE; + + /* + * Create a file system context + */ + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (!findbb && (la->la_flags & LOADFLG_COMPRESSED)) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the boot device + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return res; + } + + /* + * If we need to find a boot block, do it now. + */ + + if (findbb) { + res = cfe_findbootblock(la,fsctx,ref,&bootblock); + + /* + * If we found the boot block, seek to the part of the + * disk where the boot code is. + * Otherwise, get out now, since the disk has no boot block. + */ + + if (res == 0) { + maxsize = (int) ((uint32_t) (bootblock.bb_secsize & BOOT_SECSIZE_MASK)); + secoffset = bootblock.bb_secstart; + fs_seek(fsctx,ref,secoffset,FILE_SEEK_BEGINNING); + } + else { + fs_close(fsctx,ref); + fs_uninit(fsctx); + return res; + } + + } + + /* + * Okay, go load the boot file. + */ + + ptr = bootcode; + amtcopy = maxsize; + ttlcopy = 0; + + onedot = amtcopy / 10; /* ten dots for entire load */ + if (onedot < 4096) onedot = 4096; /* but minimum 4096 bytes per dot */ + onedot = (onedot + 1) & ~4095; /* round to multiple of 4096 */ + + while (amtcopy > 0) { + thisamt = onedot; + if (thisamt > amtcopy) thisamt = amtcopy; + + res = fs_read(fsctx,ref,ptr,thisamt); + if (la->la_flags & LOADFLG_NOISY) { + xprintf("."); + } + if (res <= 0) break; + ptr += res; + amtcopy -= res; + ttlcopy += res; + } + + /* + * We're done with the file. + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + /* + * Verify the boot loader checksum if we were reading + * the disk. + */ + +#if !defined(CONFIG_MIPS_BRCM) + if (findbb) { + CHECKSUM_BOOT_DATA(bootcode,maxsize,&calcsum); + checksum = (uint32_t) ((bootblock.bb_secsize & BOOT_DATA_CHECKSUM_MASK) + >> BOOT_DATA_CHECKSUM_SHIFT); + + if (checksum != calcsum) { + return CFE_ERR_BOOTPROGCHKSUM; + } + } +#endif + + la->la_entrypt = (uintptr_t) bootcode; + + if (la->la_flags & LOADFLG_NOISY) xprintf(" %d bytes read\n",ttlcopy); + + return (res < 0) ? res : ttlcopy; + +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_main.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_main.c new file mode 100755 index 0000000..2cf2546 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_main.c @@ -0,0 +1,611 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Main Module File: cfe_main.c + * + * This module contains the main "C" routine for CFE and + * the main processing loop. There should not be any board-specific + * stuff in here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_timer.h" + +#include "env_subr.h" +#include "cfe_mem.h" +#include "cfe.h" + +#include "exception.h" + +#include "bsp_config.h" +#include "bcm_hwdefs.h" +#include "boardparms.h" +#include "bcm_map.h" +#include "bcm_cpu.h" +#include "bcm63xx_util.h" + +#include "segtable.h" +#include "initdata.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#ifndef CFG_STACK_SIZE +#define STACK_SIZE 8192 +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +void cfe_main(int,int); +void cfe_command_restart(uint64_t status); + +extern void cfe_device_poll(void *x); + +extern int cfe_web_check(void); +extern void cfe_web_fg_process(void); +extern void cfe_web_poll(void *x); + +extern const char *builddate; +extern const char *builduser; + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +extern int ui_init_netcmds(void); +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +const char *cfe_boardname = CFG_BOARDNAME; +unsigned int cfe_startflags = 0; +#if defined (_BCM96368_) +static int cfe_bus_speed = 0; +static int cfe_ref_speed = 0; +#endif +#if defined (_BCM96328_) || defined (_BCM96362_) || defined (_BCM96816_) +static int cfe_bus_speed = 0; +static int cfe_ddr_speed = 0; +#endif +unsigned long cfe_sdramsize = 8 * 1024 * 1024; + +static void calculateCpuSpeed(void); + +#if defined (_BCM96328_) +const uint32 cpu_speed_table[0x20] = { + 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, + 0, 320, 160, 200, 160, 200, 400, 320, 320, 160, 384, 320, 192, 320, 320, 320 +}; +const uint32 ddr_speed_table[0x20] = { + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 0, 80, 100, 100, 160, 200, 400, 400, 80, 160, 160, 160, 192, 192, 240, 320 +}; +const uint32 bus_speed_table[0x20] = { + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 0, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160 +}; +#endif + +#if defined (_BCM96362_) +const uint32 cpu_speed_table[0x20] = { + 320, 320, 320, 240, 160, 400, 440, 384, 320, 320, 320, 240, 160, 320, 400, 320, + 320, 320, 320, 240, 160, 200, 400, 384, 320, 320, 320, 240, 160, 200, 400, 400 +}; +const uint32 ddr_speed_table[0x20] = { + 320, 400, 192, 320, 200, 400, 367, 320, 320, 400, 192, 320, 200, 400, 400, 320, + 320, 400, 192, 320, 200, 267, 400, 320, 320, 320, 192, 320, 200, 200, 400, 333 +}; +const uint32 bus_speed_table[0x20] = { + 160, 200, 96, 160, 100, 160, 183, 160, 160, 200, 96, 160, 100, 160, 200, 160, + 160, 200, 96, 160, 100, 100, 200, 160, 160, 160, 96, 160, 100, 100, 200, 166 +}; +#endif + +#if defined (_BCM96816_) +const uint32 cpu_speed_table[0x20] = { + 200, 400, 400, 320, 200, 400, 333, 333, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 400, 400, 200, 360, 400, 400, 300, 300, 320, 320, 400, 400 +}; +const uint32 ddr_speed_table[0x20] = { + 200, 333, 200, 200, 200, 333, 333, 333, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 400, 200, 200, 300, 300, 300, 300, 300, 400, 400, 400, 400 +}; +const uint32 bus_speed_table[0x20] = { + 200, 200, 200, 160, 100, 167, 200, 167, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 200, 200, 160, 180, 171, 200, 171, 200, 160, 200, 160, 200 +}; +#endif + +static unsigned long cfe_get_sdram_size(void); + +/* ********************************************************************* + * cfe_setup_default_env() + * + * Initialize the default environment for CFE. These are all + * the temporary variables that do not get stored in the NVRAM + * but are available to other programs and command-line macros. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_setup_default_env(void) +{ + char buffer[80]; + + xsprintf(buffer,"%d.%d.%d",CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD); + env_setenv("CFE_VERSION",buffer,ENV_FLG_BUILTIN | ENV_FLG_READONLY); + + if (cfe_boardname) { + env_setenv("CFE_BOARDNAME",(char *) cfe_boardname, + ENV_FLG_BUILTIN | ENV_FLG_READONLY); + } +} + + +/* ********************************************************************* + * cfe_ledstr(leds) + * + * Display a string on the board's LED display, if it has one. + * This routine depends on the board-support package to + * include a "driver" to write to the actual LED, if the board + * does not have one this routine will do nothing. + * + * The LEDs are written at various places in the initialization + * sequence, to debug board problems. + * + * Input parameters: + * leds - pointer to four-character ASCII string + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_ledstr(const char *leds) +{ +#if 0 + unsigned int val; + + val = ((((unsigned int) leds[0]) << 24) | + (((unsigned int) leds[1]) << 16) | + (((unsigned int) leds[2]) << 8) | + ((unsigned int) leds[3])); + + cfe_leds(val); +#endif +} + + +/* ********************************************************************* + * cfe_say_hello() + * + * Print out the CFE startup message and copyright notice + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_command_restart(uint64_t status) +{ +} + +static void cfe_say_hello(void) +{ + xprintf("\n\n"); + xprintf("CFE version 2.0.3" +#ifdef CFE_VER_RELEASE + ".%d" +#endif + " for DGN2200v2 (%s)\n", + //CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD, BCM63XX_MAJOR, BCM63XX_MINOR, +#ifdef CFE_VER_RELEASE + CFE_VER_RELEASE, +#endif + //cfe_boardname, +#ifdef __long64 + "64bit," +#else + "32bit," +#endif +#if CFG_MULTI_CPUS + "MP," +#else + "SP," +#endif +#ifdef __MIPSEL + "LE" +#endif +#ifdef __MIPSEB + "BE" +#endif +#if CFG_VAPI + ",VAPI" +#endif + ); + + xprintf("Build Date: %s (%s)\n",builddate,builduser); + xprintf("Copyright (C) 2000-2009 Broadcom Corporation.\n"); + xprintf("\n"); +} + + +/* ********************************************************************* + * cfe_restart() + * + * Restart CFE from scratch, jumping back to the boot vector. + * + * Input parameters: + * nothing + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_restart(void) +{ + _exc_restart(); +} + + +/* ********************************************************************* + * cfe_start(ept) + * + * Start a user program + * + * Input parameters: + * ept - entry point + * + * Return value: + * nothing + ********************************************************************* */ +void cfe_start(unsigned long ept) +{ + cfe_launch(ept); +} + +/* ********************************************************************* + * cfe_startup_info() + * + * Display startup memory configuration messages + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_startup_info(void) +{ + xprintf("Chip ID: BCM%X%X, ", (PERF->RevID & 0xFFFF0000) >> 16, PERF->RevID & 0xFF); + xprintf("MIPS: %dMHz",cfe_cpu_speed/1000000); +#if defined (_BCM96328_) || defined (_BCM96362_) || defined (_BCM96816_) + xprintf(", DDR: %dMHz, Bus: %dMHz\n", cfe_ddr_speed/1000000, cfe_bus_speed/1000000); +#else + xprintf("\n"); +#endif + { + unsigned long tp; + __asm __volatile( + "mfc0 $9, $22, 3;" + "move %0, $9" + :"=r" (tp)); + tp = ((tp & CP0_CMT_TPID) == CP0_CMT_TPID) ? 1 : 0; + xprintf("Main Thread: TP%d\n", tp); + } +#if defined (_BCM96328_) || defined (_BCM96362_) || defined (_BCM96816_) + if (DDR->TEST_CFG1 & 0x2) { /* Memory Test is finished */ + xprintf("Memory Test "); + if (DDR->TEST_CFG1 & 0x4) { + xprintf("Failed\n"); + } + else { + xprintf("Passed\n"); + } + } +#endif + cfe_sdramsize = cfe_get_sdram_size(); + xprintf("Total Memory: %lu bytes (%luMB)\n", cfe_sdramsize, cfe_sdramsize >> 20); + xprintf("Boot Address: 0x%x\n\n", FLASH_BASE); +} + +#if defined (_BCM96816_) +/* ********************************************************************* + * apm_hvg_init() + * + * Work around 6816-specific reset logic + * + * Input parameters: + * nothing + * + * Return value: + * does not return + ********************************************************************* */ + +static void apm_hvg_init(void) +{ + HVG->reg_hvg_cha_misc ^= HVG_SOFT_INIT_0; + HVG->reg_hvg_chb_misc ^= HVG_SOFT_INIT_0; +} +#endif + +/* ********************************************************************* + * cfe_main(a,b) + * + * It's gotta start somewhere. + * + * Input parameters: + * a,b - not used + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_main(int a,int b) +{ + /* + * By the time this routine is called, the following things have + * already been done: + * + * 1. The processor(s) is(are) initialized. + * 2. The caches are initialized. + * 3. The memory controller is initialized. + * 4. BSS has been zeroed. + * 5. The data has been moved to R/W space. + * 6. The "C" Stack has been initialized. + */ + + cfe_bg_init(); /* init background processing */ + cfe_attach_init(); + calculateCpuSpeed(); + cfe_timer_init(); /* Timer process */ + cfe_bg_add(cfe_device_poll,NULL); + + /* + * Initialize the memory allocator + */ + KMEMINIT((unsigned char *) (uintptr_t) mem_heapstart, + ((CFG_HEAP_SIZE)*1024)); + + /* + * Initialize the console. It is done before the other devices + * get turned on. + */ + + board_console_init(); + cfe_setup_exceptions(); + cfe_say_hello(); + +#if defined(CONFIG_BRCM_IKOS) + { + /*0x694b6f32 (iKo2) is replaced with actual addr during the build process*/ + static unsigned long linuxStartAddr=0x694b6f32; + printf("IKOS Build: Jump to Linux start address 0x%8.8lx.\n\n", + linuxStartAddr); + cfe_launch(linuxStartAddr); + } +#endif + + cfe_arena_init(); + board_device_init(); + cfe_startup_info(); + cfe_setup_default_env(); + ui_init_cmddisp(); + getBootLine(); + getBoardParam(); +#if defined (_BCM96816_) + apm_hvg_init(); +#endif + + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + ui_init_netcmds(); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + board_final_init(); + cfe_command_loop(); + + +} + + +/* ********************************************************************* + * cfe_command_loop() + * + * This routine reads and processes user commands + * + * Input parameters: + * nothing + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_command_loop() +{ + char buffer[300]; + int status; + char *prompt; + + /* Start Web interface. */ + cfe_bg_add(cfe_web_poll,NULL); + + for (;;) { + prompt = env_getenv("PROMPT"); + if (!prompt) prompt = "CFE> "; + console_readline(prompt,buffer,sizeof(buffer)); + + if (cfe_web_check()) + cfe_web_fg_process(); + else { + status = ui_docommands(buffer); + if (status != CMD_ERR_BLANK) { + xprintf("*** command status = %d\n", status); + } + } + } +} + +/* ********************************************************************* + * cfe_errortext(err) + * + * Returns an error message with a number in it. The number can be + * looked up in cfe_error.h. + * + * Input parameters: + * err - error code + * + * Return value: + * string description of error + ********************************************************************* */ + +const char *cfe_errortext(int err) +{ + static char err_buf[20]; + + sprintf(err_buf, "CFE error %d", err); + return (const char *) err_buf; +} + +#if defined (_BCM96368_) +/* ********************************************************************* + * calculateCpuSpeed() + * Calculate BCM6368 CPU speed by reading the PLL Config register + * and applying the following formula: + * Fref_clk = (64 * (P2/P1) * (MIPSDDR_NDIV / REF_MDIV) + * Fbus_clk = (64 * (P2/P1) * (MIPSDDR_NDIV / DDR_MDIV) + * Fcpu_clk = (64 * (P2/P1) * (MIPSDDR_NDIV / CPU_MDIV) + * Input parameters: + * none + * Return value: + * none + ********************************************************************* */ +void static calculateCpuSpeed(void) +{ + UINT32 numerator; + UINT32 pllConfig = DDR->MIPSDDRPLLConfig; + UINT32 pllMDiv = DDR->MIPSDDRPLLMDiv; + + numerator = 64000000 / ((pllConfig & MIPSDDR_P1_MASK) >> MIPSDDR_P1_SHFT) * + ((pllConfig & MIPSDDR_P2_MASK) >> MIPSDDR_P2_SHFT) * + ((pllConfig & MIPSDDR_NDIV_MASK) >> MIPSDDR_NDIV_SHFT); + + cfe_cpu_speed = numerator / ((pllMDiv & MIPS_MDIV_MASK) >> MIPS_MDIV_SHFT); + cfe_bus_speed = numerator / ((pllMDiv & DDR_MDIV_MASK) >> DDR_MDIV_SHFT); + cfe_ref_speed = numerator / ((pllConfig & REF_MDIV_MASK) >> REF_MDIV_SHFT); +} +#endif + +#if defined (_BCM96328_) || defined (_BCM96362_) || (_BCM96816_) +/* ********************************************************************* + * calculateCpuSpeed() + * Calculate CPU speed by reading strap register + * Input parameters: + * none + * Return value: + * none + ********************************************************************* */ +void static calculateCpuSpeed(void) +{ + uint32 mips_pll_fvco; + + mips_pll_fvco = MISC->miscStrapBus & MISC_STRAP_BUS_MIPS_PLL_FVCO_MASK; + mips_pll_fvco >>= MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT; + cfe_cpu_speed = cpu_speed_table[mips_pll_fvco] * 1000000; + cfe_ddr_speed = ddr_speed_table[mips_pll_fvco] * 1000000; + cfe_bus_speed = bus_speed_table[mips_pll_fvco] * 1000000; +} +#endif + +/* ********************************************************************* + * cfe_get_sdram_size(void) + * + * Return amount of SDRAM on the board. + * + * Input parameters: + * None. + * + * Return value: + * Amount of SDRAM on the board. + ********************************************************************* */ +static unsigned long cfe_get_sdram_size(void) +{ +#if defined (_BCM96368_) + uint32 size; + uint32 memCfg; + + size = 1; + memCfg = MEMC->Config; + /* Number of column bits */ + size <<= (((memCfg & MEMC_COL_MASK) >> MEMC_COL_SHFT) + 8); + /* Plus number of row bits */ + size <<= (((memCfg & MEMC_ROW_MASK) >> MEMC_ROW_SHFT) + 11); + /* Plus bus width */ + if (((memCfg & MEMC_WIDTH_MASK) >> MEMC_WIDTH_SHFT) == MEMC_32BIT_BUS) + size <<= 2; + else + size <<= 1; + + /* Plus number of banks */ + size <<= 2; + + return( size ); +#else + return (DDR->CSEND << 24); +#endif +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_net_icmp.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_net_icmp.c new file mode 100755 index 0000000..89802f8 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_net_icmp.c @@ -0,0 +1,199 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * ICMP Protocol File: net_icmp.c + * + * This module implements portions of the ICMP protocol. Note + * that it is not a complete implementation, just enough to + * generate and respond to ICMP echo requests. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_ip.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define ICMP_CODE_ECHO 0 +#define ICMP_TYPE_ECHOREPLY 0 +#define ICMP_TYPE_ECHOREQ 8 + +#define ICMPMSG(type,code) (((type)<<8)|(code)) + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +struct icmp_info_s { + ip_info_t *icmp_ipinfo; + queue_t icmp_echoreplies; + int icmp_maxreplies; +}; + +/* ********************************************************************* + * ICMP_RX_CALLBACK(ref,buf,dst,src) + * + * This routine is called by the IP layer when we receive + * ICMP protocol messages. + * + * Input parameters: + * ref - reference data (an icmp_info_t) + * buf - the ebuf containing the buffer + * dst - destination IP address (us, usually) + * src - source IP address + * + * Return value: + * ETH_KEEP to keep packet, ETH_DROP to cause packet to be freed + ********************************************************************* */ + +static int icmp_rx_callback(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src) +{ + icmp_info_t *icmp = (icmp_info_t *)ref; + ip_info_t *ipi = icmp->icmp_ipinfo; + uint16_t imsg; + uint16_t cksum; + ebuf_t *txbuf; + uint8_t *icmphdr; + int res; + + imsg = ICMPMSG(buf->eb_ptr[0],buf->eb_ptr[1]); + + res = ETH_DROP; /* assume we're dropping the pkt */ + + switch (imsg) { + case ICMPMSG(ICMP_TYPE_ECHOREQ,ICMP_CODE_ECHO): + txbuf = _ip_alloc(ipi); + if (txbuf) { + /* Construct reply from the original packet. */ + icmphdr = txbuf->eb_ptr; + ebuf_append_bytes(txbuf,buf->eb_ptr,buf->eb_length); + icmphdr[0] = ICMP_TYPE_ECHOREPLY; + icmphdr[1] = ICMP_CODE_ECHO; + icmphdr[2] = 0; icmphdr[3] = 0; + cksum = ~ip_chksum(0,icmphdr,ebuf_length(txbuf)); + icmphdr[2] = (cksum >> 8) & 0xFF; + icmphdr[3] = (cksum & 0xFF); + if (_ip_send(ipi,txbuf,src,IPPROTO_ICMP) < 0) { + _ip_free(ipi,txbuf); + } + } + break; + + case ICMPMSG(ICMP_TYPE_ECHOREPLY,ICMP_CODE_ECHO): + if (q_count(&(icmp->icmp_echoreplies)) < icmp->icmp_maxreplies) { + /* We're keeping this packet, put it on the queue and don't + free it in the driver. */ + q_enqueue(&(icmp->icmp_echoreplies),(queue_t *) buf); + res = ETH_KEEP; + } + break; + + default: + res = ETH_DROP; + } + + return res; +} + + +/* ********************************************************************* + * _ICMP_INIT(ipi) + * + * Initialize the ICMP layer. + * + * Input parameters: + * ipi - ipinfo structure of IP layer to attach to + * + * Return value: + * icmp_info_t structure or NULL if error occurs + ********************************************************************* */ + +icmp_info_t *_icmp_init(ip_info_t *ipi) +{ + icmp_info_t *icmp; + + icmp = (icmp_info_t *) KMALLOC(sizeof(icmp_info_t),0); + if (!icmp) return NULL; + + icmp->icmp_ipinfo = ipi; + q_init(&(icmp->icmp_echoreplies)); + icmp->icmp_maxreplies = 0; + + _ip_register(ipi,IPPROTO_ICMP,icmp_rx_callback,icmp); + + return icmp; +} + +/* ********************************************************************* + * _ICMP_UNINIT(icmp) + * + * Un-initialize the ICMP layer. + * + * Input parameters: + * icmp - icmp_info_t structure + * + * Return value: + * nothing + ********************************************************************* */ + +void _icmp_uninit(icmp_info_t *icmp) +{ + _ip_deregister(icmp->icmp_ipinfo,IPPROTO_ICMP); + + KFREE(icmp); +} + +int _icmp_ping(icmp_info_t *icmp,uint8_t *dest,int seq,int len) +{ + return 0; +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ram_boot.S b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ram_boot.S new file mode 100755 index 0000000..cf48de0 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_ram_boot.S @@ -0,0 +1,88 @@ +#include "sbmips.h" + +/* ********************************************************************* + * BOARD_EARLYINIT() + * + * Initialize board registers. This is the earliest + * time the BSP gets control. This routine cannot assume that + * memory is operational, and therefore all code in this routine + * must run from registers only. The $ra register must not + * be modified, as it contains the return address. + * + * This routine will be called from uncached space, before + * the caches are initialized. If you want to make + * subroutine calls from here, you must use the CALLKSEG1 macro. + * + * Among other things, this is where the GPIO registers get + * programmed to make on-board LEDs function, or other startup + * that has to be done before anything will work. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +LEAF(board_earlyinit) + j ra +END(board_earlyinit) + +/* ********************************************************************* + * BOARD_DRAMINFO + * + * Return the address of the DRAM information table + * + * Input parameters: + * nothing + * + * Return value: + * v0 - DRAM info table, return 0 to use default table + ********************************************************************* */ +LEAF(board_draminfo) + j ra +END(board_draminfo) + +/* ********************************************************************* + * BOARD_DRAMINIT + * + * This routine should activate memory. + * + * Input parameters: + * a0 - points to configuration table returned by board_draminfo + * or 0 to use an automatic table + * + * Return value: + * v0 - total memory installed + * + * Registers used: + * can use all registers. + ********************************************************************* */ +LEAF(board_draminit) + j ra +END(board_draminit) + +/* ********************************************************************* + * BOARD_SETLEDS(x) + * + * Set LEDs for boot-time progress indication. Not used if + * the board does not have progress LEDs. This routine + * must not call any other routines, since it may be invoked + * either from KSEG0 or KSEG1 and it may be invoked + * whether or not the icache is operational. + * + * Input parameters: + * a0 - LED value (8 bits per character, 4 characters) + * + * Return value: + * nothing + * + * Registers used: + * t0,t1,t2,t3 + ********************************************************************* */ +LEAF(board_setleds) + j ra +END(board_setleds) + +LEAF(bcmcore_tp1_switch) + j ra +END(bcmcore_tp1_switch) diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c new file mode 100755 index 0000000..91e1ad0 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c @@ -0,0 +1,1375 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * bcm63xx utility functions + * + * Created on : 04/18/2002 seanl + * + ********************************************************************* + +<:copyright-broadcom + + Copyright (c) 2002 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ + +#define BCMTAG_EXE_USE +#include "bcm63xx_util.h" +#include "flash_api.h" +#include "jffs2.h" + +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) + +static void convertBootInfo(void); +static int checkChipId(int tagChipId, char *sig2); +static void UpdateImageSequenceNumber( char *imageSequence ); + +BOOT_INFO bootInfo; + +static int parseFilename(char *fn) +{ + if (strlen(fn) < BOOT_FILENAME_LEN) + return 0; + else + return 1; +} + +static int parseChoiceFh(char *choice) +{ + + if (*choice == 'f' || *choice == 'h') + return 0; + else + return 1; +} + + +static int parseBootPartition(char *choice) +{ + return( (*choice == BOOT_LATEST_IMAGE || *choice == BOOT_PREVIOUS_IMAGE) + ? 0 : 1 ); +} + +static int parseChoice09(char *choice) +{ + int bChoice = *choice - '0'; + + if (bChoice >= 0 && bChoice <= 9) + return 0; + else + return 1; +} + +static int parseIpAddr(char *ipStr); +static int parseGwIpAddr(char *ipStr); +static int parseAfeId(char *afeIdStr); + +#define PARAM_IDX_BOARD_IPADDR 0 +#define PARAM_IDX_HOST_IPADDR 1 +#define PARAM_IDX_GW_IPADDR 2 +#define PARAM_IDX_RUN_FROM 3 +#define PARAM_IDX_RUN_FILENAME 4 +#define PARAM_IDX_FLASH_FILENAME 5 +#define PARAM_IDX_BOOT_DELAY 6 +#define PARAM_IDX_BOOT_IMAGE 7 + +static PARAMETER_SETTING gBootParam[] = +{ + // prompt name Error Prompt Boot Define Boot Param Validation function + {"Board IP address :", IP_PROMPT , "e=", + "", 24, parseIpAddr, TRUE}, // index 0 + {"Host IP address :", IP_PROMPT , "h=", + "", 15, parseIpAddr, TRUE}, // index 1 + {"Gateway IP address :", IP_PROMPT , "g=", + "", 15, parseGwIpAddr, TRUE}, // index 2 + {"Run from flash/host (f/h) :", RUN_FROM_PROMPT , "r=", + "", 1, parseChoiceFh, TRUE}, // index 3 + {"Default host run file name :", HOST_FN_PROMPT , "f=", + "", MAX_PROMPT_LEN - 1, parseFilename, TRUE}, // index 4 + {"Default host flash file name :", FLASH_FN_PROMPT , "i=", + "", MAX_PROMPT_LEN - 1, parseFilename, TRUE}, // index 5 + {"Boot delay (0-9 seconds) :", BOOT_DELAY_PROMPT, "d=", + "", 1, parseChoice09, TRUE}, // index 6 + {"Boot image (0=latest, 1=previous) :", BOOT_PARTITION_PROMPT, "p=", + "", 1, parseBootPartition, TRUE}, // index 7 + {NULL}, +}; + +static int gNumBootParams = (sizeof(gBootParam) / sizeof(PARAMETER_SETTING))-1; + +static PARAMETER_SETTING gAfeId[] = +{ + // prompt name Error Prompt Boot Define Boot Param Validation function + {"Primary AFE ID :", AFE_PROMPT, "", "", 12, parseAfeId, TRUE}, // index 0 + {"Bonding AFE ID :", AFE_PROMPT, "", "", 12, parseAfeId, TRUE}, // index 1 + {NULL}, +}; +static int gAfeIdParams = (sizeof(gAfeId) / sizeof(PARAMETER_SETTING))-1; + +// move from lib_misc.c +int parseipaddr(const char *ipaddr,uint8_t *dest) +{ + int a,b,c,d; + char *x; + + /* make sure it's all digits and dots. */ + x = (char *) ipaddr; + while (*x) { + if ((*x == '.') || ((*x >= '0') && (*x <= '9'))) { + x++; + continue; + } + return -1; + } + + x = (char *) ipaddr; + a = lib_atoi(ipaddr); + x = lib_strchr(x,'.'); + if (!x) return -1; + b = lib_atoi(x+1); + x = lib_strchr(x+1,'.'); + if (!x) return -1; + c = lib_atoi(x+1); + x = lib_strchr(x+1,'.'); + if (!x) return -1; + d = lib_atoi(x+1); + + if ((a < 0) || (a > 255)) return -1; + if ((b < 0) || (b > 255)) return -1; + if ((c < 0) || (c > 255)) return -1; + if ((d < 0) || (d > 255)) return -1; + + dest[0] = (uint8_t) a; + dest[1] = (uint8_t) b; + dest[2] = (uint8_t) c; + dest[3] = (uint8_t) d; + + return 0; +} + +#if 0 +static const char hextable[16] = "0123456789ABCDEF"; +void dumpHex(unsigned char *start, int len) +{ + unsigned char *ptr = start, + *end = start + len; + + while (ptr < end) + { + long offset = ptr - start; + unsigned char text[120], + *p = text; + while (ptr < end && p < &text[16 * 3]) + { + *p++ = hextable[*ptr >> 4]; + *p++ = hextable[*ptr++ & 0xF]; + *p++ = ' '; + } + p[-1] = 0; + printf("%4lX %s\n", offset, text); + } +} + +#endif + +int parsexdigit(char str) +{ + int digit; + + if ((str >= '0') && (str <= '9')) + digit = str - '0'; + else if ((str >= 'a') && (str <= 'f')) + digit = str - 'a' + 10; + else if ((str >= 'A') && (str <= 'F')) + digit = str - 'A' + 10; + else + return -1; + + return digit; +} + + +// convert in = fffffff00 to out=255.255.255.0 +// return 0 = OK, 1 failed. +static int convertMaskStr(char *in, char *out) +{ + int i; + char twoHex[4]; + uint8_t dest[4]; + char mask[BOOT_IP_LEN]; + + if (strlen(in) != MASK_LEN) // mask len has to 8 + return 1; + + memset(twoHex, 0, sizeof(twoHex)); + for (i = 0; i < 4; i++) + { + twoHex[0] = (uint8_t)*in++; + twoHex[1] = (uint8_t)*in++; + if (parsexdigit(*twoHex) == -1) + return 1; + dest[i] = (uint8_t) xtoi(twoHex); + } + sprintf(mask, "%d.%d.%d.%d", dest[0], dest[1], dest[2], dest[3]); + strcpy(out, mask); + return 0; +} + +// return 0 - OK, !0 - Bad ip +static int parseIpAddr(char *ipStr) +{ + char *x; + uint8_t dest[4]; + char mask[BOOT_IP_LEN]; + char ipMaskStr[2*BOOT_IP_LEN]; + + strcpy(ipMaskStr, ipStr); + + x = strchr(ipMaskStr,':'); + if (!x) // no mask + return parseipaddr(ipMaskStr, dest); + + *x = '\0'; + + if (parseipaddr(ipMaskStr, dest)) // ipStr is not ok + return 1; + + x++; + return convertMaskStr(x, mask); // mask is not used here + +} + +// return 0 - OK, !0 - Bad ip +static int parseGwIpAddr(char *ipStr) +{ + int ret = 0; + if( *ipStr ) + ret = parseIpAddr(ipStr); + return(ret); +} + +// return 0 - OK, !0 - Bad ip +static int parseAfeId(char *afeIdStr) +{ + return 0; +} + +// port from ifconfig command in ui_netcmds.c +void enet_init(void) +{ + char devname[] = "eth0"; + uint8_t addr[IP_ADDR_LEN]; + int res; + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + + if (net_getparam(NET_DEVNAME) == NULL) { + res = net_init(devname); /* turn interface on */ + if (res < 0) { + ui_showerror(res, "Could not activate network interface '%s'", devname); + return; + } + } + + net_setparam(NET_HWADDR, nvramData.ucaBaseMacAddr); + + parseipaddr(bootInfo.boardIp, addr); + net_setparam(NET_IPADDR, addr); + + if (strlen(bootInfo.boardMask) > 0) { + parseipaddr(bootInfo.boardMask, addr); + net_setparam(NET_NETMASK, addr); + } + + if (strlen(bootInfo.gatewayIp) > 0) { + parseipaddr(bootInfo.gatewayIp, addr); + net_setparam(NET_GATEWAY, addr); + } + + net_setnetvars(); +} + +/*************************************************************************** +// Function Name: getCrc32 +// Description : caculate the CRC 32 of the given data. +// Parameters : pdata - array of data. +// size - number of input data bytes. +// crc - either CRC32_INIT_VALUE or previous return value. +// Returns : crc. +****************************************************************************/ +UINT32 getCrc32(byte *pdata, UINT32 size, UINT32 crc) +{ + while (size-- > 0) + crc = (crc >> 8) ^ Crc32_table[(crc ^ *pdata++) & 0xff]; + + return crc; +} + + +// return 0, ok. return -1 = wrong chip +static int checkChipId(int tagChipId, char *sig2) +{ + unsigned int chipId = (PERF->RevID & 0xFFFE0000) >> 16; + int result = 0; + + /* Force BCM681x variants to be be BCM6816) */ + if( (chipId & 0xfff0) == 0x6810 ) + chipId = 0x6816; + + if (tagChipId == chipId) + result = 0; + else { + printf("Chip Id error. Image Chip Id = %04x, Board Chip Id = %04x.\n", tagChipId, chipId); + result = -1; + } + + return result; +} + +// return -1: fail. +// 0: OK. +int verifyTag( PFILE_TAG pTag, int verbose ) +{ + UINT32 crc; + FLASH_ADDR_INFO info; + int tagVer, curVer; + + kerSysFlashAddrInfoGet( &info ); + + tagVer = atoi(pTag->tagVersion); + curVer = atoi(BCM_TAG_VER); + + if (tagVer != curVer) + { + if( verbose ) + { + printf("Firmware tag version [%d] is not compatible with the current Tag version [%d].\n", \ + tagVer, curVer); + } + return -1; + } + + if (checkChipId(xtoi(pTag->chipId), pTag->signiture_2) != 0) + return -1; + + // check tag validate token first + crc = CRC32_INIT_VALUE; + crc = getCrc32((byte *) pTag, (UINT32)TAG_LEN-TOKEN_LEN, crc); + + if (crc != (UINT32)(*(UINT32*)(pTag->tagValidationToken))) + { + if( verbose ) + printf("Illegal image ! Tag crc failed.\n"); + return -1; + } + return 0; +} + +#if (INC_NAND_FLASH_DRIVER==0) +PFILE_TAG getTagFromPartition(int imageNumber) +{ + static unsigned char sectAddr1[sizeof(FILE_TAG)]; + static unsigned char sectAddr2[sizeof(FILE_TAG)]; + int blk = 0; + UINT32 crc; + PFILE_TAG pTag = NULL; + unsigned char *pBase = flash_get_memptr(0); + unsigned char *pSectAddr = NULL; + + /* The image tag for the first image is always after the boot loader. + * The image tag for the second image, if it exists, is at one half + * of the flash size. + */ + if( imageNumber == 1 ) + { + + FLASH_ADDR_INFO flash_info; + + kerSysFlashAddrInfoGet(&flash_info); + blk = flash_get_blk((int)(pBase+flash_info.flash_rootfs_start_offset)); + pSectAddr = sectAddr1; + } + else + if( imageNumber == 2 ) + { + blk = flash_get_blk((int) (pBase + (flash_get_total_size() / 2))); + pSectAddr = sectAddr2; + } + + if( blk ) + { + memset(pSectAddr, 0x00, sizeof(FILE_TAG)); + flash_read_buf((unsigned short) blk, 0, pSectAddr, sizeof(FILE_TAG)); + crc = CRC32_INIT_VALUE; + crc = getCrc32(pSectAddr, (UINT32)TAG_LEN-TOKEN_LEN, crc); + pTag = (PFILE_TAG) pSectAddr; + if (crc != (UINT32)(*(UINT32*)(pTag->tagValidationToken))) + pTag = NULL; + } + + return( pTag ); +} +#else +#define tag_not_searched 0 +#define tag_not_found 1 +#define tag_found 2 +PFILE_TAG getTagFromPartition(int imageNumber) +{ + extern unsigned char *mem_topofmem; + static FILE_TAG Tag1 = {{tag_not_searched}}; + static FILE_TAG Tag2 = {{tag_not_searched}}; + PFILE_TAG pTag = (imageNumber == 2) ? &Tag2 : &Tag1; + PFILE_TAG ret = NULL; + + switch( pTag->tagVersion[0] ) + { + case tag_not_searched: + { + int rootfs = (imageNumber == 2) ? NP_ROOTFS_2 : NP_ROOTFS_1; + char fname[] = NAND_CFE_RAM_NAME; + int fname_actual_len = strlen(fname); + int fname_cmp_len = strlen(fname) - 3; /* last three are digits */ + unsigned char *buf = (unsigned char *) mem_topofmem + 1024; + unsigned char *p; + int len = flash_get_sector_size(0); + int num_blks = flash_get_numsectors(); + int i, done, start_blk, end_blk; + struct jffs2_raw_dirent *pdir; + unsigned long version = 0; + NVRAM_DATA nvramData; + + pTag->tagVersion[0] = tag_not_found; + readNvramData(&nvramData); + validateNandPartTbl(&nvramData); + + if( nvramData.ulNandPartOfsKb[rootfs] > 0 && + nvramData.ulNandPartOfsKb[rootfs] < ((num_blks * len) / 1024) && + nvramData.ulNandPartSizeKb[rootfs] > 0 && + nvramData.ulNandPartSizeKb[rootfs] < ((num_blks * len) / 1024) ) + { + const int max_not_jffs2 = 10; + int not_jffs2 = 0; + + start_blk = nvramData.ulNandPartOfsKb[rootfs] / (len / 1024); + end_blk = + start_blk + (nvramData.ulNandPartSizeKb[rootfs] / (len / 1024)); + + /* Find the directory entry. */ + for( i = start_blk, done = 0; i < end_blk && done == 0; i++ ) + { + if( flash_read_buf(i, 0, buf, len) > 0 ) + { + p = buf; + while( p < buf + len ) + { + pdir = (struct jffs2_raw_dirent *) p; + if( je16_to_cpu(pdir->magic) == JFFS2_MAGIC_BITMASK ) + { + if( je16_to_cpu(pdir->nodetype) == + JFFS2_NODETYPE_DIRENT && + fname_actual_len == pdir->nsize && + !memcmp(fname, pdir->name, fname_cmp_len) ) + { + if( je32_to_cpu(pdir->version) > version ) + { + if( je32_to_cpu(pdir->ino) != 0 ) + { + unsigned char *seq = + pdir->name + fname_cmp_len; + pTag->imageSequence[0] = seq[0]; + pTag->imageSequence[1] = seq[1]; + pTag->imageSequence[2] = seq[2]; + pTag->imageSequence[3] = '\0'; + pTag->tagVersion[0] = tag_found; + + version = je32_to_cpu(pdir->version); + + /* Setting 'done = 1' assumes there is + * only one version of the directory + * entry. + */ + done = 1; + ret = pTag; + break; + } + } + } + + p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; + not_jffs2 = 0; + } + else + { + if( not_jffs2++ > max_not_jffs2 ) + done = 1; + break; + } + } + } + } + } + } + break; + + case tag_found: + ret = pTag; + break; + + case tag_not_found: + ret = NULL; + break; + } + + return(ret); +} +#endif + + +int getPartitionFromTag( PFILE_TAG pTag ) +{ + int ret = 0; + + if( pTag ) + { + PFILE_TAG pTag1 = getTagFromPartition(1); + PFILE_TAG pTag2 = getTagFromPartition(2); + int sequence = atoi(pTag->imageSequence); + int sequence1 = (pTag1) ? atoi(pTag1->imageSequence) : -1; + int sequence2 = (pTag2) ? atoi(pTag2->imageSequence) : -1; + + if( pTag1 && sequence == sequence1 ) + ret = 1; + else + if( pTag2 && sequence == sequence2 ) + ret = 2; + } + + return( ret ); +} + +PFILE_TAG getBootImageTag(void) +{ + PFILE_TAG pTag = NULL; + + if( flash_get_flash_type() != FLASH_IFC_NAND ) + { + PFILE_TAG pTag1 = getTagFromPartition(1); + + /* Foxconn modified end pling 10/13/2008 */ + PFILE_TAG pTag2 = NULL; + // PFILE_TAG pTag2 = getTagFromPartition(2); + //* Foxconn modified end pling 10/13/2008 */ + + if( pTag1 && pTag2 ) + { + /* Two images are flashed. */ + int sequence1 = atoi(pTag1->imageSequence); + int sequence2 = atoi(pTag2->imageSequence); + + if( bootInfo.bootPartition == BOOT_LATEST_IMAGE ) + pTag = (sequence2 > sequence1) ? pTag2 : pTag1; + else /* Boot from the previous image. */ + pTag = (sequence2 < sequence1) ? pTag2 : pTag1; + } + else + /* One image is flashed. */ + pTag = (pTag2) ? pTag2 : pTag1; + } + else + { + /* TBD. Verify that linux is on the file system. */ + /* pTag pointer is only compared to NULL for NAND flash boot. */ + pTag = (PFILE_TAG) 1; + } + + return( pTag ); +} + +static void UpdateImageSequenceNumber( char *imageSequence ) +{ + int newImageSequence = 0; + PFILE_TAG pTag = getTagFromPartition(1); + + if( pTag ) + newImageSequence = atoi(pTag->imageSequence); + + pTag = getTagFromPartition(2); + if( pTag && atoi(pTag->imageSequence) > newImageSequence ) + newImageSequence = atoi(pTag->imageSequence); + + newImageSequence++; + sprintf(imageSequence, "%d", newImageSequence); +} + +// return -1: fail. +// 0: OK. +int flashImage(uint8_t *imagePtr) +{ + UINT32 crc; + FLASH_ADDR_INFO info; + int totalImageSize = 0; + int cfeSize; + int cfeAddr, rootfsAddr, kernelAddr; + int status = 0; + PFILE_TAG pTag = (PFILE_TAG) imagePtr; + NVRAM_DATA nvramData, tmpNvramData; + + if( flash_get_flash_type() == FLASH_IFC_NAND ) + { + printf("ERROR: Image is not a valid NAND flash image.\n"); + return -1; + } + + // save existing NVRAM data into a local structure + readNvramData(&nvramData); + + if( verifyTag( pTag, 1 ) == -1 ) + return -1; + + kerSysFlashAddrInfoGet( &info ); + + // check imageCrc + totalImageSize = atoi(pTag->totalImageLen); + crc = CRC32_INIT_VALUE; + crc = getCrc32((imagePtr+TAG_LEN), (UINT32) totalImageSize, crc); + + if (crc != (UINT32) (*(UINT32*)(pTag->imageValidationToken))) + { + printf(" Illegal image ! Image crc failed.\n"); + return -1; + } + + cfeSize = cfeAddr = rootfsAddr = kernelAddr = 0; + + // check cfe's existence + cfeAddr = atoi(pTag->cfeAddress); + if (cfeAddr) + { + cfeSize = atoi(pTag->cfeLen); + if( (cfeSize <= 0) ) + { + printf("Illegal cfe size [%d].\n", cfeSize ); + return -1; + } + + printf("\nFlashing CFE: "); + if ((status = kerSysBcmImageSet(cfeAddr+BOOT_OFFSET, imagePtr+TAG_LEN, + cfeSize, 0)) != 0) + { + printf("Failed to flash CFE. Error: %d\n", status); + return status; + } + + // Check if the new image has valid NVRAM + if ((readNvramData(&tmpNvramData) != 0) || (BpSetBoardId(tmpNvramData.szBoardId) != BP_SUCCESS) || (BpSetVoiceBoardId(tmpNvramData.szBoardId) != BP_SUCCESS)) + writeNvramData(&nvramData); + } + + // check root filesystem and kernel existence + rootfsAddr = atoi(pTag->rootfsAddress); + kernelAddr = atoi(pTag->kernelAddress); + + if( rootfsAddr && kernelAddr ) + { + char *p; + unsigned char *tagFs = imagePtr; + unsigned int baseAddr = (unsigned int) flash_get_memptr(0); + unsigned int totalSize = (unsigned int) flash_get_total_size(); + unsigned int reservedBytesAtEnd; + unsigned int availableSizeOneImg; + unsigned int reserveForTwoImages; + unsigned int availableSizeTwoImgs; + unsigned int newImgSize = atoi(pTag->rootfsLen)+atoi(pTag->kernelLen); + PFILE_TAG pCurTag = getBootImageTag(); + UINT32 crc; + unsigned int curImgSize = 0; + unsigned int rootfsOffset = (unsigned int)rootfsAddr-IMAGE_BASE-TAG_LEN; + FLASH_ADDR_INFO flash_info; + + kerSysFlashAddrInfoGet(&flash_info); + if( rootfsOffset < flash_info.flash_rootfs_start_offset ) + { + // Increase rootfs and kernel addresses by the difference between + // rootfs offset and what it needs to be. + rootfsAddr += flash_info.flash_rootfs_start_offset - rootfsOffset; + kernelAddr += flash_info.flash_rootfs_start_offset - rootfsOffset; + sprintf(pTag->rootfsAddress,"%lu", (unsigned long) rootfsAddr); + sprintf(pTag->kernelAddress,"%lu", (unsigned long) kernelAddr); + crc = CRC32_INIT_VALUE; + crc = getCrc32((unsigned char *)pTag,(UINT32)TAG_LEN-TOKEN_LEN,crc); + *(unsigned long *) &pTag->tagValidationToken[0] = crc; + } + + rootfsAddr += BOOT_OFFSET; + kernelAddr += BOOT_OFFSET; + + reservedBytesAtEnd = flash_get_reserved_bytes_at_end(&flash_info); + availableSizeOneImg = totalSize - ((unsigned int)rootfsAddr-baseAddr) - + reservedBytesAtEnd; + reserveForTwoImages = + (flash_info.flash_rootfs_start_offset > reservedBytesAtEnd) + ? flash_info.flash_rootfs_start_offset : reservedBytesAtEnd; + availableSizeTwoImgs = (totalSize / 2) - reserveForTwoImages; + +// printf("availableSizeOneImage=%dKB availableSizeTwoImgs=%dKB reserve=%dKB\n", +// availableSizeOneImg/1024, availableSizeTwoImgs/1024, reserveForTwoImages/1024); + + if( pCurTag ) + curImgSize = atoi(pCurTag->rootfsLen) + atoi(pCurTag->kernelLen); + + if( newImgSize > availableSizeOneImg) + { + printf("Illegal image size %d. Image size must not be greater " + "than %d.\n", newImgSize, availableSizeOneImg); + return -1; + } + + // tag is alway at the sector start of fs + if (cfeAddr) + { + // will trash cfe memory, but cfe is already flashed + tagFs = imagePtr + cfeSize; + memcpy(tagFs, imagePtr, TAG_LEN); + } + + // If the current image fits in half the flash space and the new + // image to flash also fits in half the flash space, then flash it + // in the partition that is not currently being used to boot from. + if( curImgSize <= availableSizeTwoImgs && + newImgSize <= availableSizeTwoImgs && + getPartitionFromTag( pCurTag ) == 1 ) + { + // Update rootfsAddr to point to the second boot partition. + int offset = (totalSize / 2) + TAG_LEN; + + sprintf(((PFILE_TAG) tagFs)->kernelAddress, "%lu", + (unsigned long) IMAGE_BASE + offset + (kernelAddr-rootfsAddr)); + kernelAddr = baseAddr + offset + (kernelAddr - rootfsAddr); + + sprintf(((PFILE_TAG) tagFs)->rootfsAddress, "%lu", + (unsigned long) IMAGE_BASE + offset); + rootfsAddr = baseAddr + offset; + } + + UpdateImageSequenceNumber( ((PFILE_TAG) tagFs)->imageSequence ); + crc = CRC32_INIT_VALUE; + crc = getCrc32((unsigned char *)tagFs, (UINT32)TAG_LEN-TOKEN_LEN, crc); + *(unsigned long *) &((PFILE_TAG) tagFs)->tagValidationToken[0] = crc; + + printf("\nFlashing root file system and kernel at 0x%8.8lx: ", + rootfsAddr - TAG_LEN); + if( (status = kerSysBcmImageSet((rootfsAddr-TAG_LEN), tagFs, + TAG_LEN + newImgSize, 0)) != 0 ) + { + printf("Failed to flash root file system. Error: %d\n", status); + return status; + } + + for( p = nvramData.szBootline; p[2] != '\0'; p++ ) + { + if( p[0] == 'p' && p[1] == '=' && p[2] != BOOT_LATEST_IMAGE ) + { + // Change boot partition to boot from new image. + p[2] = BOOT_LATEST_IMAGE; + writeNvramData(&nvramData); + break; + } + } + } + + printf(".\n*** Image flash done *** !\n"); + + return status; +} + +static int nandUpdateImageSequenceNumber( uint8_t *imagePtr, int imageSize ) +{ + unsigned char *buf, *p; + char fname[] = NAND_CFE_RAM_NAME; + int fname_actual_len = strlen(fname); + int fname_cmp_len = strlen(fname) - 3; /* last three are digits */ + int len = flash_get_sector_size(0); + struct jffs2_raw_dirent *pdir; + unsigned long version = 0; + PFILE_TAG pTag1 = getTagFromPartition(1); + PFILE_TAG pTag2 = getTagFromPartition(2); + int seq = (pTag1) ? atoi(pTag1->imageSequence) : -1; + int seq2 = (pTag2) ? atoi(pTag2->imageSequence) : -1; + int ret = 0; + + if( seq2 > seq ) + seq = seq2; + + if( seq != -1 ) + { + int done = 0; + + /* Increment the new highest sequence number. Add it to the CFE RAM + * file name. + */ + seq++; + + for(buf = imagePtr; buf < imagePtr+imageSize && done == 0; buf += len) + { + p = buf; + while( p < buf + len ) + { + pdir = (struct jffs2_raw_dirent *) p; + if( je16_to_cpu(pdir->magic) == JFFS2_MAGIC_BITMASK ) + { + if( je16_to_cpu(pdir->nodetype) == JFFS2_NODETYPE_DIRENT && + fname_actual_len == pdir->nsize && + !memcmp(fname, pdir->name, fname_cmp_len) && + je32_to_cpu(pdir->version) > version && + je32_to_cpu(pdir->ino) != 0 ) + { + p = pdir->name + fname_cmp_len; + p[0] = (seq / 100) + '0'; + p[1] = ((seq % 100) / 10) + '0'; + p[2] = ((seq % 100) % 10) + '0'; + p[3] = '\0'; + + je32_to_cpu(pdir->name_crc) = getCrc32(pdir->name, + (unsigned long) fname_actual_len, 0); + + version = je32_to_cpu(pdir->version); + + /* Setting 'done = 1' assumes there is only one version + * of the directory entry. + */ + done = 1; + ret = (buf - imagePtr) / len; /* block number */ + break; + } + + p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; + } + else + break; + } + } + } + + return(ret); +} + +// return -1: fail. +// 0: OK. +int writeWholeImage(uint8_t *imagePtr, int wholeImageSize) +{ + UINT32 crc; + int status = 0; + int offset = 0; + int imageSize = wholeImageSize - TOKEN_LEN; + unsigned char crcBuf[CRC_LEN]; + NVRAM_DATA nvramData, tmpNvramData; + WFI_TAG wfiTag; +#if (INC_SPI_PROG_NAND==1) + if( flash_get_flash_type() != FLASH_IFC_NAND && wholeImageSize > FLASH_LENGTH_BOOT_ROM) + flash_change_flash_type(FLASH_IFC_NAND); +#endif + + // if whole image size (plus TOKEN_LEN of crc) is greater than total flash size, return error + if (wholeImageSize > (flash_get_total_size() + TOKEN_LEN)) + { + printf("Image size too big\n"); + return -1; + } + + memcpy(&wfiTag, imagePtr + imageSize, sizeof(wfiTag)); + if( (wfiTag.wfiVersion & WFI_ANY_VERS_MASK) == WFI_ANY_VERS && + checkChipId(wfiTag.wfiChipId, NULL) != 0 ) + return -1; + + // check tag validate token first + crc = CRC32_INIT_VALUE; + crc = getCrc32(imagePtr, (UINT32)imageSize, crc); + memcpy(crcBuf, imagePtr+imageSize, CRC_LEN); + if (memcmp(&crc, crcBuf, CRC_LEN) != 0) + { + printf("Illegal whole flash image\n"); + return -1; + } + + // save existing NVRAM data into a local structure + readNvramData(&nvramData); + + if( flash_get_flash_type() == FLASH_IFC_NAND ) + { + /* The CFE ROM boot loader saved the rootfs partition index at the + * memory location before CFE RAM load address. + */ + extern unsigned char _ftext; + + /* Allow addition blocks to flash cfram block that has sequence number + * and is flashed last. + */ + const int overhead_blocks = 8; + + int rootfs = (int) *(&_ftext - 1); + int blksize = flash_get_sector_size(0) / 1024; + int sectsize = flash_get_sector_size(0); + int i, cferam_blk, after_cferam, cferam_overhead; + + if( (wfiTag.wfiVersion & WFI_ANY_VERS_MASK) == WFI_ANY_VERS && + ((blksize == 16 && wfiTag.wfiFlashType != WFI_NAND16_FLASH) || + (blksize == 128 && wfiTag.wfiFlashType != WFI_NAND128_FLASH)) ) + { + printf("\nERROR: NAND flash block size does not match image " + "block size\n\n"); + return -1; + } + + if( *(unsigned short *) imagePtr != JFFS2_MAGIC_BITMASK ) + { + /* Flash block 0 (cferom). */ + PNVRAM_DATA pnd = (PNVRAM_DATA) (imagePtr + NVRAM_DATA_OFFSET); + char *p; + + /* Copy NVRAM data to block to be flashed so it is preserved. */ + memcpy((unsigned char *) pnd, (unsigned char *) &nvramData, + sizeof(NVRAM_DATA)); + for( p = pnd->szBootline; p[2] != '\0'; p++ ) + { + if( p[0] == 'p' && p[1] == '=' && p[2] != BOOT_LATEST_IMAGE ) + { + // Change boot partition to boot from new image. + p[2] = BOOT_LATEST_IMAGE; + break; + } + } + + /* Recalculate the nvramData CRC. */ + pnd->ulCheckSum = 0; + pnd->ulCheckSum = getCrc32((unsigned char *) pnd, + sizeof(NVRAM_DATA), CRC32_INIT_VALUE); + + if((status = kerSysBcmImageSet(FLASH_BASE,imagePtr,sectsize,0)) != 0) + printf("Failed to flash block 0. Error: %d\n", status); + imagePtr += sectsize; + imageSize -= sectsize; + } + + validateNandPartTbl(&nvramData); + cferam_blk = nandUpdateImageSequenceNumber(imagePtr, imageSize); + + /* rootfs is the partition that the CFE RAM booted from. Write the + * image to the other rootfs partition. + */ + if(rootfs == NP_ROOTFS_1 && nvramData.ulNandPartSizeKb[NP_ROOTFS_2]>0) + offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_2] * 1024; + else + offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_1] * 1024; + + after_cferam = (cferam_blk + 1) * sectsize; + cferam_overhead = overhead_blocks * sectsize; + + /* Erase block with cferam JFFS2 directory entry so if flashing this + * image does not finish, the partition will not be valid. + */ + for( i = 0; i < (cferam_blk + 1 + overhead_blocks); i++ ) + flash_sector_erase_int((offset / sectsize) + i); + + /* Flash image after cferam directory entry. */ + printf("\nFlashing root file system at 0x%8.8lx: ", FLASH_BASE+offset); + if((status = kerSysBcmImageSet(FLASH_BASE + offset + after_cferam + + cferam_overhead, imagePtr + after_cferam, imageSize - after_cferam, + 1)) != 0) + { + printf("Failed to flash whole image. Error: %d\n", status); + return status; + } + + /* Flash block(s) up to and including the block with cferam JFFS2 + * directory entry. + */ + if((status = kerSysBcmImageSet(FLASH_BASE + offset, imagePtr, + after_cferam, 0)) != 0) + { + printf("Failed to flash whole image. Error: %d\n", status); + return status; + } + } + else /* NOR FLASH */ + { + printf("\nFlashing root file system and kernel at 0x%8.8lx\n", + FLASH_BASE+offset); + + if( (wfiTag.wfiVersion & WFI_ANY_VERS_MASK) == WFI_ANY_VERS && + wfiTag.wfiFlashType != WFI_NOR_FLASH ) + { + printf("\nERROR: Image does not support a NOR flash device.\n\n"); + return -1; + } + + if((status = kerSysBcmImageSet(FLASH_BASE+offset, imagePtr, imageSize, + 1)) != 0) + { + printf("Failed to flash whole image. Error: %d\n", status); + return status; + } + } + + // Check if the new image has valid NVRAM + // Also check if the new image still supports currently configured board ID + if( (readNvramData(&tmpNvramData) != 0) || + (BpSetBoardId(tmpNvramData.szBoardId) != BP_SUCCESS) || + (BpSetVoiceBoardId(tmpNvramData.szVoiceBoardId) != BP_SUCCESS) ) + { + // Don't write NVRAM area if we are flashing tiny bridge image. + // unlike cfe.w, the tiny bridge .w image will not have NVRAM_DATA_ID set + if (*(unsigned long *) &tmpNvramData == NVRAM_DATA_ID) + writeNvramData(&nvramData); + } + + return status; +} + +int processPrompt(PPARAMETER_SETTING promptPtr, int promptCt) +{ + char tmpBuf[MAX_PROMPT_LEN]; + int i = 0; + int bChange = FALSE; + + printf("Press: to use current value\r\n"); + printf(" '-' to go previous parameter\r\n"); + printf(" '.' to clear the current value\r\n"); + printf(" 'x' to exit this command\r\n"); + + memset(tmpBuf, 0, MAX_PROMPT_LEN); + while (i < promptCt) + { + if( (promptPtr+i)->enabled == FALSE ) + { + if( tmpBuf[0] == '-' ) + { + if( i > 0 ) + { + i--; + continue; + } + } + else + { + i++; + continue; + } + } + + if (strlen((promptPtr+i)->parameter) > 0) + printf("%s %s ", (promptPtr+i)->promptName, (promptPtr+i)->parameter); + else + printf("%s %s", (promptPtr+i)->promptName, (promptPtr+i)->parameter); + + memset(tmpBuf, 0, MAX_PROMPT_LEN); + console_readline ("", tmpBuf, (promptPtr+i)->maxValueLength + 1); + + switch (tmpBuf[0]) + { + case '-': // go back one parameter + if (i > 0) + i--; + break; + case 'x': // get out the b command + if ((promptPtr+i)->func != 0) // validate function is supplied, do a check + { + if ((promptPtr+i)->func((promptPtr+i)->parameter)) + { + printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); + break; + } + } + i = promptCt; + break; + case '.': // clear the current parameter and advance + if ((promptPtr+i)->func != 0) // validate function is supplied, do a check + { + if ((promptPtr+i)->func("")) + { + printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); + break; + } + } + memset((promptPtr+i)->parameter, 0, MAX_PROMPT_LEN); + i++; + bChange = TRUE; + break; + case 0: // no input; use default if it is OK + if ((promptPtr+i)->func != 0) // validate function is supplied, do a check + { + if ((promptPtr+i)->func((promptPtr+i)->parameter)) + { + printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); + break; + } + } + i++; + break; + default: // new parameter + if ((promptPtr+i)->func != 0) // validate function is supplied, do a check + { + if ((promptPtr+i)->func(tmpBuf)) + { + printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); + break; + } + } + memset((promptPtr+i)->parameter, 0, MAX_PROMPT_LEN); + memcpy((promptPtr+i)->parameter, tmpBuf, strlen(tmpBuf)); + i++; + bChange = TRUE; + } + } + + return bChange; + +} // processPrompt + +// write the nvramData struct to nvram after CRC is calculated +void writeNvramData(PNVRAM_DATA pNvramData) +{ + UINT32 crc = CRC32_INIT_VALUE; + + pNvramData->ulCheckSum = 0; + crc = getCrc32((unsigned char *)pNvramData, sizeof(NVRAM_DATA), crc); + pNvramData->ulCheckSum = crc; + kerSysNvRamSet((unsigned char *)pNvramData, sizeof(NVRAM_DATA), 0); +} + +// read the nvramData struct from nvram +// return -1: crc fail, 0 ok +int readNvramData(PNVRAM_DATA pNvramData) +{ + UINT32 crc = CRC32_INIT_VALUE, savedCrc; + + kerSysNvRamGet((unsigned char *)pNvramData, sizeof(NVRAM_DATA), 0); + savedCrc = pNvramData->ulCheckSum; + pNvramData->ulCheckSum = 0; + crc = getCrc32((unsigned char *)pNvramData, sizeof(NVRAM_DATA), crc); + if (savedCrc != crc) + return -1; + + return 0; +} + +static void convertBootInfo(void) +{ + char *x; + + memset(&bootInfo, 0, sizeof(BOOT_INFO)); + strcpy(bootInfo.boardIp, gBootParam[PARAM_IDX_BOARD_IPADDR].parameter); + + if ((x = strchr(bootInfo.boardIp, ':'))) // has mask + { + *x = '\0'; + convertMaskStr((x+1), bootInfo.boardMask); + } + strcpy(bootInfo.hostIp, gBootParam[PARAM_IDX_HOST_IPADDR].parameter); + if ((x = strchr(bootInfo.hostIp, ':'))) // ignore host mask + *x = '\0'; + strcpy(bootInfo.gatewayIp, gBootParam[PARAM_IDX_GW_IPADDR].parameter); + if ((x = strchr(bootInfo.gatewayIp, ':'))) // ignore gw mask + *x = '\0'; + bootInfo.runFrom = gBootParam[PARAM_IDX_RUN_FROM].parameter[0]; + strcpy(bootInfo.hostFileName, gBootParam[PARAM_IDX_RUN_FILENAME].parameter); + strcpy(bootInfo.flashFileName, gBootParam[PARAM_IDX_FLASH_FILENAME].parameter); + bootInfo.bootDelay = (int)(gBootParam[PARAM_IDX_BOOT_DELAY].parameter[0] - '0'); + bootInfo.bootPartition = gBootParam[PARAM_IDX_BOOT_IMAGE].parameter[0]; +} + +void getBootLine(void) +{ + int i; + char *curPtr; + char *dPtr; + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + + if ((nvramData.szBootline[0] == (char)0xff) || + (nvramData.szBootline[0] == (char)0)) + { + setDefaultBootline(); + return; + } + + curPtr = nvramData.szBootline; + for (i = 0; (i < gNumBootParams) && (curPtr != 0); i++) + { + curPtr = strchr(curPtr, '='); + if (curPtr) // found '=' and get the param. + { + dPtr = strchr(curPtr, ' '); // find param. deliminator ' ' + memset(gBootParam[i].parameter, 0, MAX_PROMPT_LEN); + memcpy(gBootParam[i].parameter, curPtr+1, dPtr-curPtr-1); + // move to next param. + curPtr = dPtr; + } + } // for loop + + if (i < gNumBootParams) { + setDefaultBootline(); + return; + } + + convertBootInfo(); +} + +// print the bootline and board parameter info and fill in the struct for later use +// +int printSysInfo(void) +{ + int i; + ETHERNET_MAC_INFO EnetInfos[BP_MAX_ENET_MACS]; + + // display the bootline info + + if( getTagFromPartition(1) == NULL || getTagFromPartition(2) == NULL ) + gBootParam[PARAM_IDX_BOOT_IMAGE].enabled = FALSE; + + for (i = 0; i < gNumBootParams; i++) + if( gBootParam[i].enabled ) + printf("%s %s \n", gBootParam[i].promptName, gBootParam[i].parameter); + + // display the board param + displayBoardParam(); + + if( BpGetEthernetMacInfo( EnetInfos, BP_MAX_ENET_MACS ) == BP_SUCCESS ) + { + // Here we should print whether EMAC1 or EMAC2 is selected + } + + printf("\n"); + + return 0; +} + + +//************************************************************************** +// Function Name: changeBootLine +// Description : Use vxWorks bootrom style parameter input method: +// Press to use default, '-' to go to previous parameter +// Note: Parameter is set to current value in the menu. +// Returns : None. +//************************************************************************** +int changeBootLine(void) +{ + int i; + char boardIpSaved[BOOT_IP_LEN]; + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + + strcpy(boardIpSaved, bootInfo.boardIp); + + if (processPrompt(gBootParam, gNumBootParams)) + { + char *blPtr = nvramData.szBootline; + int paramLen; + + memset(blPtr, 0, NVRAM_BOOTLINE_LEN); + for (i = 0; i < gNumBootParams; i++) + { + memcpy(blPtr, gBootParam[i].promptDefine, PROMPT_DEFINE_LEN); + blPtr += PROMPT_DEFINE_LEN; + paramLen = strlen(gBootParam[i].parameter); + memcpy(blPtr, gBootParam[i].parameter, paramLen); + blPtr += paramLen; + if (!(gBootParam[i].parameter[0] == ' ')) + { + memcpy(blPtr, " ", 1); + blPtr += 1; + } + } + writeNvramData(&nvramData); + } + + getBootLine(); + + // if board ip differs, do enet init + if (strcmp(boardIpSaved, bootInfo.boardIp) != 0) + enet_init(); + + return 0; + +} + +void setDefaultBootline(void) +{ + char boardIpSaved[BOOT_IP_LEN]; + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + strcpy(boardIpSaved, bootInfo.boardIp); + + memset(nvramData.szBootline, 0, NVRAM_BOOTLINE_LEN); + strncpy(nvramData.szBootline, DEFAULT_BOOTLINE, strlen(DEFAULT_BOOTLINE)); + printf("Use default boot line parameters: %s\n", DEFAULT_BOOTLINE); + writeNvramData(&nvramData); + + getBootLine(); + + // if board ip differs, do enet init + if (strcmp(boardIpSaved, bootInfo.boardIp) != 0) + enet_init(); +} + +//************************************************************************** +// Function Name: changeAfeId +// Description : Use vxWorks bootrom style parameter input method: +// Press to use default, '-' to go to previous parameter +// Note: Parameter is set to current value in the menu. +// Returns : None. +//************************************************************************** +static void hex2Str(unsigned long num, char *str) +{ + static const char hextable[16] = "0123456789ABCDEF"; + unsigned long i, n; + str[0] = '0'; + str[1] = 'x'; + if (0 == num) { + str[2] = '0'; + str[3] = 0; + return; + } + str +=2; + n = num >> 28; + i = 0; + while (0 == n) { + num <<= 4; + n = num >> 28; + i++; + } + for (; i < 8; i++) { + *str++ = hextable[num >> 28]; + num <<= 4; + } + *str = 0; +} + +int changeAfeId(void) +{ + NVRAM_DATA nvramData; + + readNvramData(&nvramData); + hex2Str(nvramData.afeId[0], gAfeId[0].parameter); + hex2Str(nvramData.afeId[1], gAfeId[1].parameter); + if (processPrompt(gAfeId, gAfeIdParams)) + { + nvramData.afeId[0] = lib_atoi(gAfeId[0].parameter); + nvramData.afeId[1] = lib_atoi(gAfeId[1].parameter); + writeNvramData(&nvramData); + } + return 0; +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_eth.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_eth.c new file mode 100755 index 0000000..c4ea465 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_eth.c @@ -0,0 +1,547 @@ +/* +<:copyright-broadcom + + Copyright (c) 2002 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ + +/** Includes. **/ +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_ioctl.h" +#include "cfe_device.h" +#include "cfe_devfuncs.h" +#include "sbmips.h" +#include "cfe_timer.h" +#include "dev_bcm63xx_eth.h" +#include "dev_bcm63xx_flash.h" +#include "mii.h" +#include "robosw_reg.h" + +#define DMA_RX_CHAN (softc->dmaPort * 2) +#define DMA_TX_CHAN (softc->dmaPort * 2 + 1) + +#define CACHE_ALIGN 16 +extern void _cfe_flushcache(int, uint8_t *, uint8_t *); +#define INVAL_RANGE(s,l) _cfe_flushcache(CFE_CACHE_INVAL_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l)) +#define FLUSH_RANGE(s,l) _cfe_flushcache(CFE_CACHE_FLUSH_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l)) + +/** Externs. **/ +extern unsigned long sysGetEnetModeFlag(void); + +/** Prototypes. **/ +static void bcm63xx_ether_probe( cfe_driver_t * drv, unsigned long probe_a, + unsigned long probe_b, void * probe_ptr ); +static int bcm63xx_ether_open(cfe_devctx_t *ctx); +static int bcm63xx_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm63xx_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int bcm63xx_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm63xx_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm63xx_ether_close(cfe_devctx_t *ctx); +static int internal_open(bcmenet_softc * softc); + +/** Variables. **/ +const static cfe_devdisp_t bcm63xx_ether_dispatch = { + bcm63xx_ether_open, + bcm63xx_ether_read, + bcm63xx_ether_inpstat, + bcm63xx_ether_write, + bcm63xx_ether_ioctl, + bcm63xx_ether_close, + NULL, + NULL +}; + +const cfe_driver_t bcm63xx_enet = { + "BCM63xx Ethernet", + "eth", + CFE_DEV_NETWORK, + &bcm63xx_ether_dispatch, + bcm63xx_ether_probe +}; + +/** Functions. **/ +static void bcm63xx_ether_probe( cfe_driver_t * drv, unsigned long probe_a, + unsigned long probe_b, void * probe_ptr ) +{ + bcmenet_softc * softc; + char descr[100]; + + softc = (bcmenet_softc *) KMALLOC( sizeof(bcmenet_softc), CACHE_ALIGN ); + if( softc == NULL ) { + xprintf( "BCM63xx : Failed to allocate softc memory.\n" ); + } else { + memset( softc, 0, sizeof(bcmenet_softc) ); + + if (internal_open( softc ) == -1) + xprintf("Failed initializing enet hardware\n"); + else + { + cfe_attach( drv, softc, NULL, descr ); + } + } +} + +static int bcm63xx_ether_open(cfe_devctx_t *ctx) +{ + /* FIXME -- See if this can be returned to its normal place. */ + return 0; +} + +/* + * init_dma: Initialize DMA control register + */ +static void init_dma(bcmenet_softc *softc) +{ + uint32 *StateRam; + int i; + + /* + * clear State RAM + */ + StateRam = (UINT32 *)&softc->dmaCtrl->stram.s[0]; + for (i = 0; i < sizeof(DmaStateRam) / sizeof(UINT32) * NUM_PORTS * 2; i++) + StateRam[i] = 0; + + /* + * initialize IUDMA controller register + */ + softc->dmaCtrl->controller_cfg = DMA_FLOWC_CH1_EN; + softc->dmaCtrl->flowctl_ch1_thresh_lo = DMA_FC_THRESH_LO; + softc->dmaCtrl->flowctl_ch1_thresh_hi = DMA_FC_THRESH_HI; + softc->dmaCtrl->flowctl_ch1_alloc = 0; + + // transmit + softc->txDma->cfg = 0; /* initialize first (will enable later) */ + softc->txDma->maxBurst = DMA_MAX_BURST_LENGTH; + softc->txDma->intMask = 0; /* mask all ints */ + /* clr any pending interrupts on channel */ + softc->txDma->intStat = DMA_DONE|DMA_NO_DESC|DMA_BUFF_DONE; + softc->txDma->intMask = DMA_DONE; + softc->dmaCtrl->stram.s[DMA_TX_CHAN].baseDescPtr = (uint32)K1_TO_PHYS((uint32_t)(softc->txFirstBdPtr)); + + // receive + softc->rxDma->cfg = 0; // initialize first (will enable later) + softc->rxDma->maxBurst = DMA_MAX_BURST_LENGTH; + softc->rxDma->intMask = 0; /* mask all ints */ + /* clr any pending interrupts on channel */ + softc->rxDma->intStat = DMA_DONE|DMA_NO_DESC|DMA_BUFF_DONE; + softc->rxDma->intMask = DMA_DONE; + softc->dmaCtrl->stram.s[DMA_RX_CHAN].baseDescPtr = (uint32)K1_TO_PHYS((uint32_t)(softc->rxFirstBdPtr)); +} + + +static int internal_open(bcmenet_softc * softc) +{ + int i; + void *p; + + robosw_init(); + softc->dmaCtrl = (DmaRegs *)(SWITCH_DMA_BASE); + + softc->rxDma = &softc->dmaCtrl->chcfg[DMA_RX_CHAN]; + softc->txDma = &softc->dmaCtrl->chcfg[DMA_TX_CHAN]; + + // If doing SW reboot in EPI the controller can still be active + softc->rxDma->cfg = 0; + softc->txDma->cfg = 0; + softc->dmaCtrl->controller_cfg &= ~DMA_MASTER_EN; + + p = KMALLOC( NR_TX_BDS * sizeof(DmaDesc), CACHE_ALIGN ); + if( p == NULL ) { + xprintf( "BCM63xx : Failed to allocate txBds memory.\n" ); + return -1; + } + INVAL_RANGE(p, NR_TX_BDS * sizeof(DmaDesc)); + softc->txBds = (DmaDesc *)K0_TO_K1((uint32) p); + + p = KMALLOC( NR_RX_BDS * sizeof(DmaDesc), CACHE_ALIGN ); + if( p== NULL ) { + xprintf( "BCM63xx : Failed to allocate rxBds memory.\n" ); + KFREE( (void *)(softc->txBds) ); + softc->txBds = NULL; + return -1; + } + INVAL_RANGE(p, NR_RX_BDS * sizeof(DmaDesc)); + softc->rxBds = (DmaDesc *)K0_TO_K1((uint32) p); + + softc->rxBuffers = (uint32_t)KMALLOC( NR_RX_BDS * ENET_BUF_SIZE, CACHE_ALIGN ); + if( softc->rxBuffers == NULL ) { + xprintf( "BCM63xx : Failed to allocate RxBuffer memory.\n" ); + KFREE( (void *)(softc->txBds) ); + softc->txBds = NULL; + KFREE( (void *)(softc->rxBds) ); + softc->rxBds = NULL; + return -1; + } + INVAL_RANGE(softc->rxBuffers, NR_RX_BDS * ENET_BUF_SIZE); + + softc->txBuffers = (uint32_t)KMALLOC( NR_TX_BDS * ENET_BUF_SIZE, CACHE_ALIGN ); + if( softc->txBuffers == NULL ) { + xprintf( "BCM63xx : Failed to allocate txBuffer memory.\n" ); + KFREE( (void *)(softc->rxBuffers) ); + softc->rxBuffers = NULL; + KFREE( (void *)(softc->txBds) ); + softc->txBds = NULL; + KFREE( (void *)(softc->rxBds) ); + softc->rxBds = NULL; + return -1; + } + INVAL_RANGE(softc->txBuffers, NR_TX_BDS * ENET_BUF_SIZE); + + /* Init the Receive Buffer Descriptor Ring. */ + softc->rxFirstBdPtr = softc->rxBdReadPtr = softc->rxBds; + softc->rxLastBdPtr = softc->rxBds + NR_RX_BDS - 1; + + for(i = 0; i < NR_RX_BDS; i++) { + (softc->rxBds + i)->status = DMA_OWN; + (softc->rxBds + i)->length = ENET_BUF_SIZE; + (softc->rxBds + i)->address = softc->rxBuffers + i * ENET_BUF_SIZE; + (softc->rxBds + i)->address = K1_TO_PHYS( (softc->rxBds + i)->address ); + softc->dmaCtrl->flowctl_ch1_alloc = 1; + } + softc->rxLastBdPtr->status |= DMA_WRAP; + + /* Init Transmit Buffer Descriptor Ring. */ + softc->txFirstBdPtr = softc->txNextBdPtr = softc->txBds; + softc->txLastBdPtr = softc->txBds + NR_TX_BDS - 1; + + for(i = 0; i < NR_TX_BDS; i++) { + (softc->txBds + i)->status = 0; + (softc->txBds + i)->length = 0; + (softc->txBds + i)->address = softc->txBuffers + i * ENET_BUF_SIZE; + (softc->txBds + i)->address = K1_TO_PHYS( (softc->txBds + i)->address ); + } + softc->txLastBdPtr->status = DMA_WRAP; + + /* init dma registers */ + init_dma(softc); + + robosw_configure_ports(); + + softc->dmaCtrl->controller_cfg |= DMA_MASTER_EN; + + softc->rxDma->cfg |= DMA_ENABLE; + + softc->linkCheck = 0; + + return 0; +} + +static int bcm63xx_ether_read( cfe_devctx_t * ctx, iocb_buffer_t * buffer ) +{ + unsigned char * dstptr; + unsigned char * srcptr; + volatile DmaDesc * CurrentBdPtr; + bcmenet_softc * softc = (bcmenet_softc *) ctx->dev_softc; + uint16 dmaFlag; + + if( ctx == NULL ) { + xprintf( "No context\n" ); + return -1; + } + + if( buffer == NULL ) { + xprintf( "No dst buffer\n" ); + return -1; + } + + if( softc == NULL ) { + xprintf( "softc has not been initialized.\n" ); + return -1; + } + + dmaFlag = (uint16) softc->rxBdReadPtr->status; + if (!(dmaFlag & DMA_EOP)) + { + xprintf("dmaFlag (return -1)[%04x]\n", dmaFlag); + return -1; + } + + dstptr = buffer->buf_ptr; + CurrentBdPtr = softc->rxBdReadPtr; + + srcptr = (unsigned char *)( PHYS_TO_K1(CurrentBdPtr->address) ); + + buffer->buf_retlen = ((CurrentBdPtr->length < buffer->buf_length) ? CurrentBdPtr->length : buffer->buf_length); + + memcpy( dstptr, srcptr, buffer->buf_retlen ); + + CurrentBdPtr->length = ENET_BUF_SIZE; + CurrentBdPtr->status &= DMA_WRAP; + CurrentBdPtr->status |= DMA_OWN; + + IncRxBdPtr( CurrentBdPtr, softc ); + softc->rxBdReadPtr = CurrentBdPtr; + softc->dmaCtrl->flowctl_ch1_alloc = 1; + + // enable rx dma + softc->rxDma->cfg = DMA_ENABLE; + return 0; +} + + +static int bcm63xx_ether_inpstat( cfe_devctx_t * ctx, iocb_inpstat_t * inpstat ) +{ + bcmenet_softc * softc; + volatile DmaDesc * CurrentBdPtr; + + /* ============================= ASSERTIONS ============================= */ + + if( ctx == NULL ) { + xprintf( "No context\n" ); + return -1; + } + + if( inpstat == NULL ) { + xprintf( "No inpstat buffer\n" ); + return -1; + } + + softc = (bcmenet_softc *)ctx->dev_softc; + if( softc == NULL ) { + xprintf( "softc has not been initialized.\n" ); + return -1; + } + + /* ====================================================================== */ + + + CurrentBdPtr = softc->rxBdReadPtr; + + // inp_status == 1 -> data available + inpstat->inp_status = (CurrentBdPtr->status & DMA_OWN) ? 0 : 1; + + if (!inpstat->inp_status || (++softc->linkCheck > 100)) { + // Don't check link state too often when receiving data + softc->linkCheck = 0; + robosw_check_ports(); + } + + return 0; +} + + +static int bcm63xx_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + uint32_t status; + unsigned char * dstptr; + bcmenet_softc * softc; + volatile DmaDesc * CurrentBdPtr; + volatile uint32 txEvents = 0; + + /* ============================= ASSERTIONS ============================= */ + + if( ctx == NULL ) { + xprintf( "No context\n" ); + return -1; + } + + if( buffer == NULL ) { + xprintf( "No dst buffer\n" ); + return -1; + } + + if( buffer->buf_length > ENET_MAX_MTU_SIZE ) { + xprintf( "src buffer too large.\n" ); + xprintf( "size is %d\n", buffer->buf_length ); + return -1; + } + + softc = (bcmenet_softc *) ctx->dev_softc; + if( softc == NULL ) { + xprintf( "softc has not been initialized.\n" ); + return -1; + } + + /* ====================================================================== */ + + CurrentBdPtr = softc->txNextBdPtr; + + /* Find out if the next BD is available. */ + if( CurrentBdPtr->status & DMA_OWN ) { + xprintf( "No tx BD available ?!\n" ); + return -1; + } + + dstptr = (unsigned char *)PHYS_TO_K1( CurrentBdPtr->address ); + memcpy( dstptr, buffer->buf_ptr, buffer->buf_length ); + + /* Set status of DMA BD to be transmitted. */ + status = DMA_SOP | DMA_EOP | DMA_APPEND_CRC | DMA_OWN; + if( CurrentBdPtr == softc->txLastBdPtr ) { + status |= DMA_WRAP; + } + + CurrentBdPtr->length = ((buffer->buf_length < ETH_ZLEN) ? ETH_ZLEN : buffer->buf_length); + CurrentBdPtr->status = status; + + // Enable DMA for this channel + softc->txDma->cfg |= DMA_ENABLE; + + // poll the dma status until done + do + { + txEvents = CurrentBdPtr->status; + } while (txEvents & DMA_OWN); + + + //Advance BD pointer to next in the chain. + InctxBdPtr( CurrentBdPtr, softc ); + softc->txNextBdPtr = CurrentBdPtr; + + return 0; +} + +static int bcm63xx_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + bcmenet_softc *softc = (bcmenet_softc *) ctx->dev_softc; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_ETHER_GETHWADDR: + memcpy(buffer->buf_ptr, softc->hwaddr, sizeof(softc->hwaddr)); + return 0; + + case IOCTL_ETHER_SETHWADDR: + memcpy(softc->hwaddr, buffer->buf_ptr, sizeof(softc->hwaddr)); + return 0; + + default: + return -1; + } + + return 0; +} + +/* + * bcm63xx_ether_flush: Flushes packets from the DMA receive ring + */ +static int bcm63xx_ether_flush(bcmenet_softc * softc) +{ + volatile DmaDesc * CurrentBdPtr; + uint16 dmaFlag; + unsigned char * srcptr; + uint16 len; + uint32 rxBdsCount = 0; + int i; + + if( softc == NULL ) { + xprintf( "softc has not been initialized.\n" ); + return -1; + } + + xprintf("Disabling Switch ports.\n"); + + /* disable forwarding */ + SWITCH->SwitchMode &= ~SwitchMode_FwdgEn; + + /* Bring the link down on all switch ports */ + for(i=0; i<8; ++i) { + SWITCH->PortOverride[i] &= ~PortOverride_Linkup; + /* disable Rx and Tx */ + SWITCH->PortCtrl[i] = PortCtrl_DisableTx | PortCtrl_DisableRx; + } + + for(i=0; i<1000; ++i) { + cfe_usleep(1000); + } + + xprintf("Flushing Receive Buffers...\n"); + + while(!((dmaFlag = (uint16) softc->rxBdReadPtr->status) & DMA_OWN)) { + + if (!(dmaFlag & DMA_EOP)) + { + xprintf("dmaFlag (return -1)[%04x]\n", dmaFlag); + return -1; + } + + CurrentBdPtr = softc->rxBdReadPtr; + + srcptr = (unsigned char *)( PHYS_TO_K1(CurrentBdPtr->address) ); + + len = CurrentBdPtr->length; + + ++rxBdsCount; + + CurrentBdPtr->length = ENET_BUF_SIZE; + CurrentBdPtr->status &= DMA_WRAP; + CurrentBdPtr->status |= DMA_OWN; + + IncRxBdPtr( CurrentBdPtr, softc ); + softc->rxBdReadPtr = CurrentBdPtr; + softc->dmaCtrl->flowctl_ch1_alloc = 1; + + // enable rx dma + softc->rxDma->cfg = DMA_ENABLE; + } + + xprintf("%d buffers found.\n", rxBdsCount); + + return 0; +} + +static int bcm63xx_ether_close(cfe_devctx_t *ctx) +{ + int i; + bcmenet_softc * softc = (bcmenet_softc *) ctx->dev_softc; + unsigned long sts; + + /* flush Rx DMA Channel */ + bcm63xx_ether_flush(softc); + + xprintf("Closing DMA Channels.\n"); + + sts = softc->rxDma->intStat; + softc->rxDma->intStat = sts; + softc->rxDma->intMask = 0; + softc->rxDma->cfg = 0; + // wait the current packet to complete before turning off EMAC, otherwise memory corruption can occur. + for(i=0; softc->rxDma->cfg & DMA_ENABLE; i++) { + // put the line below inside - it seems the signal can be lost and DMA never stops + softc->rxDma->cfg = 0; + if (i >= 20) { + xprintf("Rx Timeout !!!\n"); + break; + } + cfe_usleep(100); + } + + sts = softc->txDma->intStat; + softc->txDma->intStat = sts; + softc->txDma->intMask = 0; + softc->txDma->cfg = 0; + for(i=0; softc->txDma->cfg & DMA_ENABLE; i++) { + // put the line below inside - it seems the signal can be lost and DMA never stops + softc->txDma->cfg = 0; + if (i >= 20) { + xprintf("Tx Timeout !!!\n"); + break; + } + cfe_usleep(100); + } + + /* return buffer allocation register internal count to 0 */ + softc->dmaCtrl->flowctl_ch1_alloc = (DMA_BUF_ALLOC_FORCE | 0); + + softc->dmaCtrl->controller_cfg &= ~DMA_MASTER_EN; + + KFREE( (void *)(softc->txBuffers) ); + KFREE( (void *)(softc->rxBuffers) ); + KFREE( (void *)(softc->txBds) ); + KFREE( (void *)(softc->rxBds) ); + return 0; +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c new file mode 100755 index 0000000..cf38104 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c @@ -0,0 +1,629 @@ +/*************************************************************************** + * Broadcom Corp. Confidential + * Copyright 2001 Broadcom Corp. All Rights Reserved. + * + * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED + * SOFTWARE LICENSE AGREEMENT BETWEEN THE USER AND BROADCOM. + * YOU HAVE NO RIGHT TO USE OR EXPLOIT THIS MATERIAL EXCEPT + * SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. + * + *************************************************************************** + * File Name : bcm63xx_flash.c + * + * Description: This file contains the flash device driver for bcm63xx board. Very similar to + * board.c in linux development. + * + * Created on : 4/18/2002 seanl + * + ***************************************************************************/ + + +/* Includes. */ +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "bcm_map.h" +#include "bcm_hwdefs.h" +#include "dev_bcm63xx_flash.h" +#include "flash_api.h" +#include "boardparms.h" +#include "boardparms_voice.h" +#include "bcm63xx_util.h" + +//#define DEBUG_FLASH + +/* This driver determines the NVRAM and persistent storage flash address and + * length. + */ +/* Foxconn start jenny add for timeout */ +extern int NMRPKeepAlive(void); +extern int NMRPTFTPWaiting(void); +extern int g_nmrp_keepalive; +extern int nmrp_server_detected; +/* Foxconn end jenny add for timeout*/ + +static FLASH_ADDR_INFO fInfo; + +//************************************************************************************** +// Flash read/write and image downloading.. +//************************************************************************************** + +void kerSysFlashInit( void ) +{ + NVRAM_DATA nvramData; + + flash_init(); + + while ((readNvramData(&nvramData) != 0) || (BpSetBoardId(nvramData.szBoardId) != BP_SUCCESS)) + { + printf("\n*** Board is not initialized properly ***\n\n"); + //setBoardParam(); /* Bob removed to set default board parameters, 11/01/2010 */ + setDefaultBoardParam(); /* Bob added to set default board parameters, 11/01/2010 */ + } + + fInfo.flash_rootfs_start_offset = flash_get_sector_size(0); + if( fInfo.flash_rootfs_start_offset < FLASH_LENGTH_BOOT_ROM ) + fInfo.flash_rootfs_start_offset = FLASH_LENGTH_BOOT_ROM; + + flash_init_info(&nvramData, &fInfo); + +#if (INC_NAND_FLASH_DRIVER==1) + validateNandPartTbl(&nvramData); + + /* Check if spare area data contains non 0xff values after JFFS2 clean + * marker. Early version of this CFE driver filled bytes 8 - 11 with + * 0 which Linux does not like. + */ + { + extern int read_spare_data(int blk, unsigned char *buf, int bufsize); + + int blk_size = flash_get_sector_size(0) / 1024; + int blk_start = nvramData.ulNandPartOfsKb[NP_DATA] / blk_size; + unsigned char spare[64]; + + memset(spare, 0xff, sizeof(spare)); + if( read_spare_data(blk_start, spare, sizeof(spare)) == FLASH_API_OK ) + { + const int spare_len = 8; /* Linux JFFS2 spare area is 8 bytes */ + int i; + + for( i = spare_len; i < sizeof(spare); i++ ) + { + if( spare[i] != 0xff ) + { + printf("Data spare area is not correct, erasing psi\n"); + printf("%8.8lx %8.8lx %8.8lx %8.8lx\n", + *(unsigned long *) &spare[0],*(unsigned long *)&spare[4], + *(unsigned long *) &spare[8],*(unsigned long *)&spare[12]); + kerSysErasePsi(); + break; + } + } + } + } +#endif +} + +#if (INC_NAND_FLASH_DRIVER==1) || (INC_SPI_PROG_NAND==1) +/*********************************************************************** + * Function Name: validateNandPartTbl + * Description : Checks the NAND partition table fields in NVRAM data. + * If nay of the fields are not valid, new values are set. + * Returns : None. + ***********************************************************************/ +void validateNandPartTbl(PNVRAM_DATA pNvramData) +{ + unsigned long ulBlockSizeKb = (unsigned long)flash_get_sector_size(0)/1024; + unsigned long ulTotalSizeKb = (unsigned long)flash_get_total_size() / 1024; + +#if (INC_SPI_PROG_NAND==1) + if( flash_get_flash_type() != FLASH_IFC_NAND ) + return; +#endif + if( pNvramData->ulNandPartSizeKb[NP_BOOT] != ulBlockSizeKb || + pNvramData->ulNandPartSizeKb[NP_DATA] != NAND_DATA_SIZE_KB || + (pNvramData->ulNandPartSizeKb[NP_BBT] != NAND_BBT_SMALL_SIZE_KB && + pNvramData->ulNandPartSizeKb[NP_BBT] != NAND_BBT_BIG_SIZE_KB) ) + { + /* Initialize NAND flash partition table. */ + unsigned long ulRootfsSizeKb; + unsigned long ulBbtSizeKb = (ulTotalSizeKb > NAND_BBT_THRESHOLD_KB) + ? NAND_BBT_BIG_SIZE_KB : NAND_BBT_SMALL_SIZE_KB; + + /* The Boot partition is first and is one block in size. */ + pNvramData->ulNandPartOfsKb[NP_BOOT] = 0; + pNvramData->ulNandPartSizeKb[NP_BOOT] = ulBlockSizeKb; + + /* The Bad Block Table partition is last and is a constant size. */ + pNvramData->ulNandPartOfsKb[NP_BBT] = ulTotalSizeKb - ulBbtSizeKb; + pNvramData->ulNandPartSizeKb[NP_BBT] = ulBbtSizeKb; + + /* The Data partition is before the BBT and is a constant size. */ + pNvramData->ulNandPartOfsKb[NP_DATA] = + pNvramData->ulNandPartOfsKb[NP_BBT] - NAND_DATA_SIZE_KB; + pNvramData->ulNandPartSizeKb[NP_DATA] = NAND_DATA_SIZE_KB; + + /* The first rootfs partition starts at the second sector. */ + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1] = ulBlockSizeKb; + + /* The size of the two root file system partitions is whatever is left + * after the Boot, Data and BBT paritions divided by 2 and evenly + * divisible by the NAND flash block size. + */ + ulRootfsSizeKb = ((pNvramData->ulNandPartOfsKb[NP_DATA] - + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1]) / 2); + ulRootfsSizeKb = (ulRootfsSizeKb / ulBlockSizeKb) * ulBlockSizeKb; + +#if 1 /* support two file system partitions */ + pNvramData->ulNandPartSizeKb[NP_ROOTFS_1] = ulRootfsSizeKb; + + pNvramData->ulNandPartOfsKb[NP_ROOTFS_2] = + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1] + ulRootfsSizeKb; + pNvramData->ulNandPartSizeKb[NP_ROOTFS_2] = ulRootfsSizeKb; +#else /* support one file system partition */ + pNvramData->ulNandPartSizeKb[NP_ROOTFS_1] = ulRootfsSizeKb * 2; + + pNvramData->ulNandPartOfsKb[NP_ROOTFS_2] = ulTotalSizeKb; + pNvramData->ulNandPartSizeKb[NP_ROOTFS_2] = 0; +#endif + + writeNvramData(pNvramData); + +#if defined(DEBUG_FLASH) + printf("boot offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_BOOT], + pNvramData->ulNandPartSizeKb[NP_BOOT]); + printf("rootfs1 offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1], + pNvramData->ulNandPartSizeKb[NP_ROOTFS_1]); + printf("rootfs2 offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_ROOTFS_2], + pNvramData->ulNandPartSizeKb[NP_ROOTFS_2]); + printf("data offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_DATA], + pNvramData->ulNandPartSizeKb[NP_DATA]); + printf("bbt offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_BBT], + pNvramData->ulNandPartSizeKb[NP_BBT]); +#endif + } +} +#else +void validateNandPartTbl(PNVRAM_DATA pNvramData) +{ +} +#endif + + +/*********************************************************************** + * Function Name: kerSysFlashAddrInfoGet + * Description : Fills in a structure with information about the NVRAM + * and persistent storage sections of flash memory. + * Returns : None. + ***********************************************************************/ +void kerSysFlashAddrInfoGet(PFLASH_ADDR_INFO pflash_addr_info) +{ + memcpy(pflash_addr_info, &fInfo, sizeof(FLASH_ADDR_INFO)); +} + +// get shared blks into *** pTempBuf *** which has to be released bye the caller! +// return: if pTempBuf != NULL, poits to the data with the dataSize of the buffer +// !NULL -- ok +// NULL -- fail +static unsigned char *getSharedBlks(int start_blk, int num_blks) +{ + int i = 0; + int usedBlkSize = 0; + int sect_size = 0; + unsigned char *pTempBuf = NULL; + unsigned char *pBuf = NULL; + + for (i = start_blk; i < (start_blk + num_blks); i++) + usedBlkSize += flash_get_sector_size((unsigned short) i); + + if ((pTempBuf = (unsigned char *) KMALLOC(usedBlkSize, sizeof(long))) == NULL) + { + printf("failed to allocate memory with size: %d\n", usedBlkSize); + return pTempBuf; + } + + pBuf = pTempBuf; + for (i = start_blk; i < (start_blk + num_blks); i++) + { + sect_size = flash_get_sector_size((unsigned short) i); +#if defined(DEBUG_FLASH) + printf("getShareBlks: blk=%d, sect_size=%d\n", i, sect_size); +#endif + flash_read_buf((unsigned short)i, 0, pBuf, sect_size); + pBuf += sect_size; + } + + return pTempBuf; +} + + + +// Set the pTempBuf to flash from start_blk for num_blks +// return: +// 0 -- ok +// -1 -- fail +static int setSharedBlks(int start_blk, int num_blks, unsigned char *pTempBuf) +{ + int i = 0; + int sect_size = 0; + int sts = 0; + unsigned char *pBuf = pTempBuf; + + for (i = start_blk; i < (start_blk + num_blks); i++) + { + sect_size = flash_get_sector_size((unsigned short) i); + flash_sector_erase_int(i); + if (flash_write_buf(i, 0, pBuf, sect_size) != sect_size) + { + printf("Error writing flash sector %d.", i); + sts = -1; + break; + } + +#if defined(DEBUG_FLASH) + printf("setShareBlks: blk=%d, sect_size=%d\n", i, sect_size); +#endif + + pBuf += sect_size; + } + + return sts; +} + + + +/******************************************************************************* + * NVRAM functions + *******************************************************************************/ + +// get nvram data +// return: +// 0 - ok +// -1 - fail +int kerSysNvRamGet(unsigned char *string, int strLen, int offset) +{ + unsigned char *pBuf = NULL; + + if ((pBuf = getSharedBlks(NVRAM_SECTOR, 1)) == NULL) + return -1; + + // get string off the memory buffer + memcpy(string, (pBuf + NVRAM_DATA_OFFSET + offset), strLen); + + KFREE(pBuf); + + return 0; +} + + +// set nvram +// return: +// 0 - ok +// -1 - fail +int kerSysNvRamSet(unsigned char *string, int strLen, int offset) +{ + int sts = 0; + unsigned char *pBuf = NULL; + + if ((pBuf = getSharedBlks(NVRAM_SECTOR, 1)) == NULL) + return -1; + + // set string to the memory buffer + memcpy((pBuf + NVRAM_DATA_OFFSET + offset), string, strLen); + + if (setSharedBlks(NVRAM_SECTOR, 1, pBuf) != 0) + sts = -1; + + KFREE(pBuf); + + return sts; +} + +/*********************************************************************** + * Function Name: kerSysEraseNvRam + * Description : Erase the NVRAM storage section of flash memory. + * Returns : 1 -- ok, 0 -- fail + ***********************************************************************/ +int kerSysEraseNvRam(void) +{ + int sts = 1; + unsigned char *tempStorage = KMALLOC(NVRAM_LENGTH, sizeof(long)); + + // just write the whole buf with '0xff' to the flash + if (!tempStorage) + sts = 0; + else + { + memset(tempStorage, 0xff, NVRAM_LENGTH); + if (kerSysNvRamSet(tempStorage, NVRAM_LENGTH, 0) != 0) + sts = 0; + KFREE(tempStorage); + } + + return sts; +} + + +/******************************************************************************* + * PSI functions + *******************************************************************************/ + +#if (INC_NAND_FLASH_DRIVER!=1) +/** set psi while preserving any other data that might be sharing sectors with + * the psi, e.g. scratch pad. + * + * @param string (IN) buffer that holds the data to be written. + * @param strLen (IN) length of buffer. + * + * @return 0 if OK, -1 on failure. + */ +static int kerSysPsiSet(const unsigned char *string, int strLen) +{ + int sts = 0; + unsigned char *pBuf = NULL; + + if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk, + fInfo.flash_persistent_number_blk)) == NULL) + return -1; + + // set string to the memory buffer + memcpy((pBuf + fInfo.flash_persistent_blk_offset), string, strLen); + + if (setSharedBlks(fInfo.flash_persistent_start_blk, + fInfo.flash_persistent_number_blk, pBuf) != 0) + sts = -1; + + KFREE(pBuf); + + return sts; +} + +/** set backup psi + * + * Backup PSI does not share its sectors with anything else, so this + * function does not need to read first and write. Just write. + * This function expects the length of the buffer to be exactly the + * length of the entire PSI. + * + * @param string (IN) buffer that holds the data to be written. + * + * @return 0 if OK, -1 on failure. + */ +static int kerSysBackupPsiSet(const unsigned char *string) +{ + int sts = 0; + + if (setSharedBlks(fInfo.flash_backup_psi_start_blk, + fInfo.flash_backup_psi_number_blk, + (unsigned char *) string) != 0) + sts = -1; + + return sts; +} + +/*********************************************************************** + * Function Name: kerSysErasePsi + * Description : Erase the Psi storage section of flash memory. + * Returns : 1 -- ok, 0 -- fail + ***********************************************************************/ +int kerSysErasePsi(void) +{ + int sts = 1; + unsigned char *tempStorage; + + if (fInfo.flash_persistent_start_blk == 0) { + sts = 0; + } + else { + tempStorage = KMALLOC(fInfo.flash_persistent_length, sizeof(long)); + // just write the whole buf with '0xff' to the flash + if (!tempStorage) + sts = 0; + else + { + memset(tempStorage, 0xff, fInfo.flash_persistent_length); + if (kerSysPsiSet(tempStorage, fInfo.flash_persistent_length) != 0) + sts = 0; + + // Also erase backup psi if it is there + if (fInfo.flash_backup_psi_number_blk > 0) + { + if (kerSysBackupPsiSet(tempStorage) != 0) + sts = 0; + } + + KFREE(tempStorage); + } + } + return sts; +} +#else +int kerSysErasePsi(void) +{ + int sts = 1; + NVRAM_DATA nvramData; + + if( readNvramData(&nvramData) == 0 ) + { + int blk_size = flash_get_sector_size(0) / 1024; + int blk_start = nvramData.ulNandPartOfsKb[NP_DATA] / blk_size; + int total_blks = + blk_start + (nvramData.ulNandPartSizeKb[NP_DATA]) / blk_size; + + while( blk_start < total_blks ) + { + flash_sector_erase_int(blk_start); + blk_start++; + } + sts = 0; + } + + return(sts); +} +#endif + +// flash bcm image +// return: +// 0 - ok +// !0 - the sector number fail to be flashed (should not be 0) +int kerSysBcmImageSet( int flash_start_addr, unsigned char *string, int size, int fWholeImage) +{ + int sts; + int sect_size; + int blk_start; + // int savedSize = size; + int total_blks = flash_get_numsectors(); + + /* Foxconn add by Cliff Wang, 03/23/2010 */ + unsigned char *pTempBuf = NULL; + int savedBlkStart; + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + if( flash_get_flash_type() == FLASH_IFC_NAND ) + { + if( flash_start_addr == FLASH_BASE ) + total_blks = 1; + else + { + NVRAM_DATA nvramData; + + if( readNvramData(&nvramData) == 0 ) + { + sect_size = flash_get_sector_size(0); + int rootfs = + ((flash_start_addr - FLASH_BASE) / 1024 == + nvramData.ulNandPartOfsKb[NP_ROOTFS_2]) + ? NP_ROOTFS_2 : NP_ROOTFS_1; + + total_blks = (nvramData.ulNandPartOfsKb[rootfs] + + nvramData.ulNandPartSizeKb[rootfs]) / (sect_size/ 1024); + } + } + } + +#if defined(DEBUG_FLASH) + printf("kerSysBcmImageSet: flash_start_addr=0x%x string=%p len=%d wholeImage=%d\n", + flash_start_addr, string, size, fWholeImage); +#endif + + blk_start = flash_get_blk(flash_start_addr); + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + savedBlkStart = blk_start; + if( blk_start < 0 ) + return( -1 ); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + /* write image to flash memory */ + do + { + g_nmrp_keepalive = 1; /* Foxconn add by Cliff Wang, 03/23/2010 */ + + sect_size = flash_get_sector_size(blk_start); + +#if defined(DEBUG_FLASH) + printf("Image flashing on block: %d\n", blk_start); +#endif + + // share the blk with psi only when fWholeImage == 0 + // Foxconn modified by Silver Shih for burn board Id + if ((!fWholeImage && blk_start == fInfo.flash_persistent_start_blk) || (fWholeImage == 5)) + { + +#if 0 + if (size > (sect_size - fInfo.flash_persistent_length)) + { + printf("Image is too big\n"); + break; // image is too big. Can not overwrite to psi + } +#endif + + if ((pTempBuf = (unsigned char *) KMALLOC(sect_size, sizeof(long))) == NULL) + { + printf("Failed to allocate memory with size: %d\n", sect_size); + break; + } + flash_read_buf((unsigned short)blk_start, 0, pTempBuf, sect_size); + memcpy(pTempBuf, string, size); + flash_sector_erase_int(blk_start); // erase blk before flash + + + if (flash_write_buf(blk_start, 0, pTempBuf, sect_size) == sect_size) + size = 0; // break out and say all is ok + break; + } + + flash_sector_erase_int(blk_start); // erase blk before flash + + if (sect_size > size) + { + if (size & 1) + size++; + sect_size = size; + } + if (flash_write_buf(blk_start, 0, string, sect_size) != sect_size) { + if( flash_get_flash_type() != FLASH_IFC_NAND ) + break; + blk_start++; + } + else { + printf("."); + blk_start++; + string += sect_size; + size -= sect_size; + + /* Foxconn added start by jenny @NMRP */ + if(nmrp_server_detected==1) // in NMRP mode + { + if(blk_start - savedBlkStart == 30) + { + savedBlkStart = blk_start; + printf("\n"); + NMRPKeepAlive(); + } + } + /* Foxconn added end by jenny @NMRP */ + } + } while (size > 0); + g_nmrp_keepalive = 0; /* Foxconn added by jenny add for timeout */ + +#if 0 /* Foxconn removed by EricHuang */ + if (size == 0 && fWholeImage && savedSize > FLASH_LENGTH_BOOT_ROM) + { + // If flashing a whole image, erase to end of flash. + while( blk_start < total_blks ) + { + flash_sector_erase_int(blk_start); + printf("."); + blk_start++; + } + } +#endif + + printf("\n\n"); + + if( size == 0 ) + sts = 0; // ok + else + sts = blk_start; // failed to flash this sector + + g_nmrp_keepalive = 0; /* Foxconn jenny add for timeout */ + return sts; +} + +unsigned long kerSysReadFromFlash( void *toaddr, unsigned long fromaddr, + unsigned long len ) +{ + int sect = flash_get_blk((int) fromaddr); + unsigned char *start = flash_get_memptr(sect); + flash_read_buf( sect, (int) fromaddr - (int) start, toaddr, len ); + + return(len); +} + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c new file mode 100755 index 0000000..3b2ce63 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_uart.c @@ -0,0 +1,211 @@ +#include "cfe.h" +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" + +#include "sbmips.h" +#include "bsp_config.h" + +#include "bcm_hwdefs.h" +#include "bcm_map.h" + +static void bcm63xx_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +static int bcm63xx_uart_open(cfe_devctx_t *ctx); +static int bcm63xx_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm63xx_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int bcm63xx_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm63xx_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm63xx_uart_close(cfe_devctx_t *ctx); + +const static cfe_devdisp_t bcm63xx_uart_dispatch = { + bcm63xx_uart_open, + bcm63xx_uart_read, + bcm63xx_uart_inpstat, + bcm63xx_uart_write, + bcm63xx_uart_ioctl, + bcm63xx_uart_close, + NULL, + NULL +}; + + +const cfe_driver_t bcm63xx_uart = { + "BCM63xx DUART", + "uart", + CFE_DEV_SERIAL, + &bcm63xx_uart_dispatch, + bcm63xx_uart_probe +}; + + +typedef struct bcm63xx_uart_s { + int baudrate; +} bcm63xx_uart_t; + + +static void bcm63xx_set_baudrate( bcm63xx_uart_t * softc ) +{ + uint32_t baudwd; + + baudwd = (FPERIPH / softc->baudrate) / 16; + if( baudwd & 0x1 ) { + baudwd = baudwd / 2; + } else { + baudwd = baudwd / 2 - 1; + } + UART->baudword = baudwd; +} + + +static void bcm63xx_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + bcm63xx_uart_t * softc; + char descr[80]; + + /* enable the transmitter interrupt? */ + + /* + * probe_a is the DUART base address. + * probe_b is the channel-number-within-duart (0 or 1) + * probe_ptr is unused. + */ + softc = (bcm63xx_uart_t *) KMALLOC(sizeof(bcm63xx_uart_t),0); + if (softc) { + xsprintf( descr, "%s channel %d", drv->drv_description, probe_b ); + cfe_attach( drv, softc, NULL, descr ); + } +} + +static int bcm63xx_uart_open(cfe_devctx_t *ctx) +{ + bcm63xx_uart_t * softc = ctx->dev_softc; + + /* Enable the UART clock */ + softc->baudrate = CFG_SERIAL_BAUD_RATE; + bcm63xx_set_baudrate( softc ); + + UART->control = BRGEN | TXEN | RXEN; + UART->config = BITS8SYM | ONESTOP; + UART->fifoctl = RSTTXFIFOS | RSTRXFIFOS; + UART->intMask = 0; + + return 0; +} + + +static int bcm63xx_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + unsigned char * bptr; + int blen; + uint32_t status; + char inval; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + while (blen > 0) { + status = UART->intStatus; + if(status & (RXOVFERR | RXPARERR | RXFRAMERR | RXBRK)) { + /* RX over flow */ + if(status & RXOVFERR) { + /* reset RX FIFO to clr interrupt */ + UART->fifoctl |= RSTRXFIFOS; + } + + /* other errors just read the bad character to clear the bit */ + inval = UART->Data; + } + else if(status & RXFIFONE) { + *bptr++ = UART->Data; + blen--; + } + else + break; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + + +static int bcm63xx_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + inpstat->inp_status = UART->intStatus & RXFIFONE; + return 0; +} + + +static int bcm63xx_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + unsigned char * bptr; + int blen; + uint32_t status; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + status = 0; + while( (blen > 0) && !status ) { + /* Wait for the buffer to empty before we write the next character */ + /* FIXME - The serial port should be able to accept more than one */ + /* character at a time. Why doesn't it work though? */ + do { + status = UART->intStatus & TXFIFOEMT; + } while( !status ); + UART->Data = *bptr; + bptr++; + blen--; + + status = UART->intStatus & (TXOVFERR|TXUNDERR); + } + + if( status ) { + /* Reset TX FIFO */ + UART->fifoctl |= RSTTXFIFOS; + blen++; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + + +static int bcm63xx_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + bcm63xx_uart_t * softc = ctx->dev_softc; + unsigned int * info = (unsigned int *) buffer->buf_ptr; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_SERIAL_GETSPEED: + *info = softc->baudrate; + break; + case IOCTL_SERIAL_SETSPEED: + softc->baudrate = *info; + bcm63xx_set_baudrate( softc ); + break; + case IOCTL_SERIAL_GETFLOW: + *info = SERIAL_FLOW_NONE; + break; + case IOCTL_SERIAL_SETFLOW: + break; + default: + return -1; + } + + return 0; +} + + +static int bcm63xx_uart_close(cfe_devctx_t *ctx) +{ + /* Turn off the UART clock. */ + return 0; +} diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ul.html b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ul.html new file mode 100755 index 0000000..a663a35 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ul.html @@ -0,0 +1,48 @@ + + + + + + +
+
+ Update Software
+
+ Step 1: Obtain an updated software image file from your ISP.
+
+ Step 2: Enter the path to the image file location in the box below or + click the "Browse" button to locate the image file.
+
+ Step 3: Click the "Update Software" button once to upload the new image + file.
+
+ NOTE: The update process takes about 2 minutes to complete, and your DSL Router + will reboot.
+
+ + + + + +
Software File Name:  +
+

+
+
+ + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ulinfo.html b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ulinfo.html new file mode 100755 index 0000000..1edb2ae --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/html/ulinfo.html @@ -0,0 +1,60 @@ + + + + + + +
DSL Router Software Upgrade
+
+ +
+
+
+ +
+
+ + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/ram_cfe.mk b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/ram_cfe.mk new file mode 100755 index 0000000..a540170 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/ram_cfe.mk @@ -0,0 +1,378 @@ + +# +# CFE's version number +# + +include ${TOP}/main/cfe_version.mk + +# +# Default values for certain parameters +# + +CFG_MLONG64 ?= 0 +CFG_LITTLE ?= 0 +CFG_RELOC ?= 0 +CFG_UNCACHED ?= 0 +CFG_NEWRELOC ?= 0 +CFG_BOOTRAM ?= 0 +CFG_VGACONSOLE ?= 0 +CFG_PCI ?= 1 +CFG_LDT_REV_017 ?= 0 +CFG_ZLIB ?= 0 +CFG_BIENDIAN ?= 0 +CFG_DOWNLOAD ?= 0 +CFG_RAMAPP ?= 0 +CFG_USB ?= 0 + +# +# Paths to other parts of the firmware. Everything's relative to ${TOP} +# so that you can actually do a build anywhere you want. +# + +ARCH_TOP = ${TOP}/arch/${ARCH} +ARCH_SRC = ${ARCH_TOP}/common/src +ARCH_INC = ${ARCH_TOP}/common/include +CPU_SRC = ${ARCH_TOP}/cpu/${CPU}/src +CPU_INC = ${ARCH_TOP}/cpu/${CPU}/include + +# +# It's actually optional to have a 'board' +# directory. If you don't specify BOARD, +# don't include the files. +# + +ifneq ("$(strip ${BOARD})","") +BOARD_SRC = ${ARCH_TOP}/board/${BOARD}/src +BOARD_INC = ${ARCH_TOP}/board/${BOARD}/include +endif + +# +# Preprocessor defines for CFE's version number +# + +VDEF = -DCFE_VER_MAJ=${CFE_VER_MAJ} -DCFE_VER_MIN=${CFE_VER_MIN} -DCFE_VER_ECO=${CFE_VER_ECO} + +# +# Construct the list of paths that will eventually become the include +# paths and VPATH +# + +SRCDIRS = ${ARCH_SRC} ${CPU_SRC} ${LZMZ_SRC} ${BOARD_SRC} ${TOP}/main ${TOP}/vendor ${TOP}/include ${TOP}/net ${TOP}/dev ${TOP}/pci ${TOP}/ui ${TOP}/lib ${TOP}/common ${TOP}/verif ${TOP}/lzma + +CFE_INC = ${TOP}/include ${TOP}/pci ${TOP}/net + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +SRCDIRS += ${TOP}/x86emu ${TOP}/pccons +CFE_INC += ${TOP}/x86emu ${TOP}/pccons +endif + +ifeq ($(strip ${CFG_VAPI}),1) +SRCDIRS += ${TOP}/verif +CFE_INC += ${TOP}/verif +endif + +ifeq ($(strip ${CFG_ZLIB}),1) +SRCDIRS += ${TOP}/zlib +CFE_INC += ${TOP}/zlib +endif + + +INCDIRS = $(patsubst %,-I%,$(subst :, ,$(ARCH_INC) $(CPU_INC) $(BOARD_INC) $(CFE_INC))) + +VPATH = $(SRCDIRS) + +# +# Bi-endian support: If we're building the little-endian +# version, use a different linker script so we can locate the +# ROM at a higher address. You'd think we could do this with +# normal linker command line switches, but there appears to be no +# command-line way to override the 'AT' qualifier in the linker script. +# + +CFG_TEXTAT1MB=0 +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),1) + CFG_TEXTAT1MB=1 + endif +endif + + +# +# Configure tools and basic tools flags. This include sets up +# macros for calling the C compiler, basic flags, +# and linker scripts. +# + +include ${ARCH_SRC}/tools.mk + +# +# Add some common flags that are used on any architecture. +# + +CFLAGS += -I. $(INCDIRS) +CFLAGS += -D_CFE_ ${VDEF} -DCFG_BOARDNAME=\"${CFG_BOARDNAME}\" -DCONFIG_MIPS_BRCM + +# +# Add flash driver support. +# +# INC_xxx_FLASH_DRIVER is exported from rom_cfe.mk + +CFLAGS += -DINC_CFI_FLASH_DRIVER=$(INC_CFI_FLASH_DRIVER) +CFLAGS += -DINC_SPI_FLASH_DRIVER=$(INC_SPI_FLASH_DRIVER) +CFLAGS += -DINC_NAND_FLASH_DRIVER=$(INC_NAND_FLASH_DRIVER) +CFLAGS += -DINC_SPI_PROG_NAND=$(INC_SPI_PROG_NAND) + +# +# Set CFG_TCP=0 to not include the TCP protocol. +# + +CFG_TCP=1 +ifeq ($(strip ${CFG_TCP}),1) +CFLAGS += -DCFG_TCP +endif + +# +# Set CFG_WEB_SERVER=0 to not include the web server. +# + +CFG_WEB_SERVER=1 +CFLAGS += -DCFG_WEB_SERVER=${CFG_WEB_SERVER} + +# +# Gross - allow more options to be supplied from command line +# + +ifdef CFG_OPTIONS +OPTFLAGS = $(patsubst %,-D%,$(subst :, ,$(CFG_OPTIONS))) +CFLAGS += ${OPTFLAGS} +endif + + +# +# IKOS Build +# + +ifeq ($(strip $(BRCM_IKOS)),y) +CFLAGS += -DCONFIG_BRCM_IKOS +endif + +# +# This is the makefile's main target. Note that we actually +# do most of the work in 'ALL' not 'all', since we include +# other makefiles after this point. +# + +all : build_date.c ALL + +# +# Macros that expand to the list of arch-independent files +# + +LZMAOBJS = LzmaDecode.o dcapi.o +DEVOBJS = +## dev_newflash.o dev_null.o dev_promice.o dev_ide_common.o dev_ns16550.o dev_ds17887clock.o dev_flash.o +LIBOBJS = lib_malloc.o lib_printf.o lib_queue.o lib_string.o lib_string2.o \ + lib_setjmp.o lib_arena.o +##lib_hssubr.o lib_physio.o lib_misc.o lib_qsort.o + +## Foxconn add start by Cliff Wang, 03/23/2010 ## +#NETOBJS = net_ether.o net_tftp.o net_ip.o net_udp.o net_dns.o net_arp.o \ + net_api.o net_tcp.o net_tcpbuf.o +NETOBJS = net_ether.o net_tftp.o net_ip.o net_udp.o net_dns.o net_arp.o \ + net_api.o net_tcp.o net_tcpbuf.o net_nmrp.o +## Foxconn add end by Cliff Wang, 03/23/2010 + +## dev_tcpconsole.o net_dhcp.o net_icmp.o +CFEOBJS = cfe_attach.o cfe_iocb_dispatch.o cfe_devfuncs.o \ + cfe_console.o cfe_mem.o cfe_timer.o \ + cfe_background.o build_date.o \ + cfe_xreq.o cfe_filesys.o +## cfe_error.o cfe_rawfs.o cfe_fatfs.o cfe_httpfs.o cfe_ldr_srec.o cfe_autoboot.o cfe_boot.o cfe_ldr_elf.o cfe_ldr_raw.o cfe_loader.o +## cfe_main.o nvram_subr.o url.o cfe_savedata.o env_subr.o cfe_zlibfs.o + +#UIOBJS = ui_command.o ui_cmddisp.o +# Foxconn add start by Cliff Wang, 03/23/2010 +UIOBJS = ui_command.o ui_cmddisp.o ui_tftpd.o ui_netcmds.o + +## ui_pcicmds.o \ui_tcpcmds.o ui_memcmds.o ui_loadcmds.o ui_flash.o ui_envcmds.o ui_devcmds.o ui_netcmds.o +## ui_examcmds.o ui_misccmds.o \ +## ui_test_disk.o ui_test_ether.o ui_test_flash.o ui_test_uart.o + +# +# Add more object files if we're supporting PCI +# + +ifeq ($(strip ${CFG_PCI}),1) +PCIOBJS = pciconf.o ldtinit.o pci_subr.o +PCIOBJS += pci_devs.o +DEVOBJS += dev_sp1011.o dev_ht7520.o +DEVOBJS += dev_ide_pci.o dev_ns16550_pci.o +DEVOBJS += dev_tulip.o dev_dp83815.o +CFLAGS += -DCFG_PCI=1 +ifeq ($(strip ${CFG_LDT_REV_017}),1) +CFLAGS += -DCFG_LDT_REV_017=1 +endif +ifeq ($(strip ${CFG_DOWNLOAD}),1) +DEVOBJS += dev_bcm1250.o download.data +CFLAGS += -DCFG_DOWNLOAD=1 +endif +endif + +# +# If doing bi-endian, add the compiler switch to change +# the way the vectors are generated. These switches are +# only added to the big-endian portion of the ROM, +# which is located at the real boot vector. +# + +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),0) + CFLAGS += -DCFG_BIENDIAN=1 + endif +endif + +# +# Include the makefiles for the architecture-common, cpu-specific, +# and board-specific directories. Each of these will supply +# some files to "ALLOBJS". The BOARD directory is optional +# as some ports are so simple they don't need boad-specific stuff. +# + +include ${ARCH_SRC}/Makefile +include ${CPU_SRC}/Makefile + +ifneq ("$(strip ${BOARD})","") +include ${BOARD_SRC}/Makefile +endif + +# +# Add the common object files here. +# + +ALLOBJS += $(LIBOBJS) $(DEVOBJS) $(CFEOBJS) $(VENOBJS) $(UIOBJS) $(NETOBJS) $(LZMAOBJS) +#$(PCIOBJS) + +# +# VAPI continues to be a special case. +# + +ifeq ($(strip ${CFG_VAPI}),1) +include ${TOP}/verif/Makefile +endif + +# +# USB support +# + +ifeq ($(strip ${CFG_USB}),1) +SRCDIRS += ${TOP}/usb +CFE_INC += ${TOP}/usb +include ${TOP}/usb/Makefile +endif + +# +# If we're doing the VGA console thing, pull in the x86 emulator +# and the pcconsole subsystem +# + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +include ${TOP}/x86emu/Makefile +include ${TOP}/pccons/Makefile +endif + +# +# If we're including ZLIB, then add its makefile. +# + +ifeq ($(strip ${CFG_ZLIB}),1) +include ${TOP}/zlib/Makefile +CFLAGS += -DCFG_ZLIB=1 -DMY_ZCALLOC -DNO_MEMCPY +endif + +# +# Vendor extensions come next - they live in their own directory. +# + +include ${TOP}/vendor/Makefile + +.PHONY : all +.PHONY : ALL +.PHONY : build_date.c + +# +# Build the local tools that we use to construct other source files +# + +mkpcidb : ${TOP}/hosttools/mkpcidb.c + gcc -o mkpcidb ${TOP}/hosttools/mkpcidb.c + +memconfig : ${TOP}/hosttools/memconfig.c + gcc -o memconfig -D_MCSTANDALONE_ -D_MCSTANDALONE_NOISY_ -I${TOP}/arch/mips/cpu/sb1250/include ${TOP}/hosttools/memconfig.c ${TOP}/arch/${ARCH}/cpu/${CPU}/src/sb1250_draminit.c + +pcidevs_data2.h : mkpcidb ${TOP}/pci/pcidevs_data.h + ./mkpcidb > pcidevs_data2.h + +mkflashimage : ${TOP}/hosttools/mkflashimage.c + gcc -o mkflashimage -I${TOP}/include ${TOP}/hosttools/mkflashimage.c + +pci_subr.o : ${TOP}/pci/pci_subr.c pcidevs_data2.h + +build_date.c : + echo "const char *builddate = \"`date`\";" > build_date.c + echo "const char *builduser = \"`whoami`@`hostname`\";" >> build_date.c + +# +# Make a define for the board name +# + +CFLAGS += -D_$(patsubst "%",%,${CFG_BOARDNAME})_ + +LIBCFE = libcfe.a + +%.o : %.c + $(GCC) $(CFLAGS) -o $@ $< + +%.o : %.S + $(GCC) $(CFLAGS) -o $@ $< + +%.o : %.html + echo unsigned char $*_html[] = { > $*.c + hexdump -v -e '" " 12/1 "0x%2.2x, " "\n"' $< | sed -e "s/ 0x .*$\//" -e "\$$s/, *$$//" >> $*.c + echo ' };' >> $*.c + echo 'int $*_html_size = sizeof($*_html);' >> $*.c + echo >> $*.c + $(GCC) $(CFLAGS) -o $@ $*.c + rm -f $*.c + +%.o : %.css + echo unsigned char $*_css[] = { > $*.c + hexdump -v -e '" " 12/1 "0x%2.2x, " "\n"' $< | sed -e "s/ 0x .*$\//" -e "\$$s/, *$$//" >> $*.c + echo ' };' >> $*.c + echo 'int $*_css_size = sizeof($*_css);' >> $*.c + echo >> $*.c + $(GCC) $(CFLAGS) -o $@ $*.c + rm -f $*.c + +%.o : %.gif + echo unsigned char $*_gif[] = { > $*.c + hexdump -v -e '" " 12/1 "0x%2.2x, " "\n"' $< | sed -e "s/ 0x .*$\//" -e "\$$s/, *$$//" >> $*.c + echo ' };' >> $*.c + echo 'int $*_gif_size = sizeof($*_gif);' >> $*.c + echo >> $*.c + $(GCC) $(CFLAGS) -o $@ $*.c + rm -f $*.c + +# +# This rule constructs "libcfe.a" which contains most of the object +# files. +# + +$(LIBCFE) : $(ALLOBJS) + rm -f $(LIBCFE) + $(AR) cr $(LIBCFE) $(ALLOBJS) + $(RANLIB) $(LIBCFE) + + + + + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/robosw_reg.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/robosw_reg.c new file mode 100755 index 0000000..15dad53 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/robosw_reg.c @@ -0,0 +1,615 @@ +/* +<:copyright-broadcom + + Copyright (c) 2007 Broadcom Corporation + All Rights Reserved + No portions of this material may be reproduced in any form without the + written permission of: + Broadcom Corporation + 16215 Alton Parkway + Irvine, California 92619 + All information contained in this document is Broadcom Corporation + company private, proprietary, and trade secret. + +:> +*/ + +#include "bcm_map.h" +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "mii.h" +#include "bcmmii.h" +#include "sbmips.h" +#include "cfe_iocb.h" +#include "cfe_timer.h" +#include "robosw_reg.h" +#include "dev_bcm63xx_eth.h" +#include "bcmSpiRes.h" + +static uint32 mii_read(uint32 uPhyAddr, uint32 uRegAddr); +static void mii_write(uint32 uPhyAddr, uint32 uRegAddr, uint32 data); + +static int ext_switch_init(void); +static int ethsw_spi_ss_id(void); +static void ethsw_spi_select(int page); +static void ethsw_spi_rreg(int page, int reg, uint8 *data, int len); +static void ethsw_spi_wreg(int page, int reg, uint8 *data, int len); + +void ethsw_rreg_ext(int access_type, int page, int reg, uint8 *data, int len); +void ethsw_wreg_ext(int access_type, int page, int reg, uint8 *data, int len); + + +static ETHERNET_MAC_INFO EnetInfo[BP_MAX_ENET_MACS]; +static uint16 PortLinkState[BP_MAX_SWITCH_PORTS]; + +#define MDIO_BUS 0 +#define SPI_BUS 1 +#define TX_BDS 3 +#define RX_BDS 16 +#define CACHE_ALIGN 16 +#define BUF_LENGTH 160 +extern void _cfe_flushcache(int, uint8_t *, uint8_t *); +#define INVAL_RANGE(s,l) _cfe_flushcache(CFE_CACHE_INVAL_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l)) + +/* read a value from the MII */ +static uint32 mii_read(uint32 uPhyAddr, uint32 uRegAddr) +{ + SWITCH->MdioCtrl = 0x0; + SWITCH->MdioCtrl = MdioCtrl_Read | (IsExtPhyId(uPhyAddr) ? MdioCtrl_Ext : 0) | + ((uPhyAddr << MdioCtrl_ID_Shift) & MdioCtrl_ID_Mask) | + (uRegAddr << MdioCtrl_Addr_Shift); + cfe_usleep(100); + return SWITCH->MdioData; +} + +/* write a value to the MII */ +static void mii_write(uint32 uPhyAddr, uint32 uRegAddr, uint32 data) +{ + SWITCH->MdioCtrl = 0x0; + SWITCH->MdioCtrl = MdioCtrl_Write | (IsExtPhyId(uPhyAddr) ? MdioCtrl_Ext : 0) | + ((uPhyAddr << MdioCtrl_ID_Shift) & MdioCtrl_ID_Mask) | + (uRegAddr << MdioCtrl_Addr_Shift) | data; + cfe_usleep(100); +} + +static int clkHz = 781000; +#if !defined(_BCM96328_) +static int clk781k = 2; +#endif +static int ethsw_spi_ss_id() +{ + int slave_select; + + switch(EnetInfo[1].usConfigType) { + case BP_ENET_CONFIG_SPI_SSB_0: + slave_select = 0; + break; + case BP_ENET_CONFIG_SPI_SSB_1: + slave_select = 1; + break; + case BP_ENET_CONFIG_SPI_SSB_2: + slave_select = 2; + break; + case BP_ENET_CONFIG_SPI_SSB_3: + slave_select = 3; + break; + default: + slave_select = 1; + xprintf("Invalid SPI_SS in usConfigType, Assuming 1\n"); + break; + } + return slave_select; +} + +static void ethsw_spi_select(int page) +{ + unsigned char buf[3]; + int spi_ss, cid = 0; + + spi_ss = ethsw_spi_ss_id(); + /* Select new chip */ + buf[0] = BCM5325_SPI_CMD_NORMAL | BCM5325_SPI_CMD_WRITE | + ((cid & BCM5325_SPI_CHIPID_MASK) << BCM5325_SPI_CHIPID_SHIFT); + + /* Select new page */ + buf[1] = PAGE_SELECT; + buf[2] = (char)page; +#if defined(_BCM96328_) + BcmSpi_Write(buf, sizeof(buf), HS_SPI_BUS_NUM, spi_ss, clkHz); +#else + BcmSpi_Write(buf, sizeof(buf), LEG_SPI_BUS_NUM, spi_ss, clkHz); +#endif + +} + +static void ethsw_spi_rreg(int page, int reg, uint8 *data, int len) +{ + unsigned char buf[64]; + int rc; + int i; + int max_check_spi_sts; + int prependCnt = BCM5325_SPI_PREPENDCNT, spi_ss, cid = 0; + + spi_ss = ethsw_spi_ss_id(); + + ethsw_spi_select(page); + + /* write command byte and register address */ + buf[0] = BCM5325_SPI_CMD_NORMAL | BCM5325_SPI_CMD_READ | + ((cid & BCM5325_SPI_CHIPID_MASK) << BCM5325_SPI_CHIPID_SHIFT); + buf[1] = (unsigned char)reg; +#if defined(_BCM96328_) + rc = BcmSpi_Read(buf, prependCnt, 1, HS_SPI_BUS_NUM, spi_ss, clkHz); +#else + rc = BcmSpi_Read(buf, prependCnt, 1, LEG_SPI_BUS_NUM, spi_ss, clkHz); +#endif + + if (rc == SPI_STATUS_OK) { + max_check_spi_sts = 0; + do { + /* write command byte and read spi_sts address */ + buf[0] = BCM5325_SPI_CMD_NORMAL | BCM5325_SPI_CMD_READ | + ((cid & BCM5325_SPI_CHIPID_MASK) << BCM5325_SPI_CHIPID_SHIFT); + buf[1] = (unsigned char)BCM5325_SPI_STS; +#if defined(_BCM96328_) + rc = BcmSpi_Read(buf, prependCnt, 1, HS_SPI_BUS_NUM, spi_ss, clkHz); +#else + rc = BcmSpi_Read(buf, prependCnt, 1, LEG_SPI_BUS_NUM, spi_ss, clkHz); +#endif + if (rc == SPI_STATUS_OK) { + /* check the bit 0 RACK bit is set */ + if (buf[0] & BCM5325_SPI_CMD_RACK) { + break; + } + cfe_usleep(10000); + } else { + break; + } + } while (max_check_spi_sts++ < 10); + + if (rc == SPI_STATUS_OK) { + for (i = 0; i < len; i++) { + buf[0] = BCM5325_SPI_CMD_NORMAL | BCM5325_SPI_CMD_READ | + ((cid & BCM5325_SPI_CHIPID_MASK) << BCM5325_SPI_CHIPID_SHIFT); + buf[1] = (unsigned char)0xf0; +#if defined(_BCM96328_) + rc = BcmSpi_Read(buf, prependCnt, 1, HS_SPI_BUS_NUM, spi_ss, clkHz); +#else + rc = BcmSpi_Read(buf, prependCnt, 1, LEG_SPI_BUS_NUM, spi_ss, clkHz); +#endif + if (rc == SPI_STATUS_OK) { + *(data + (len - i - 1)) = buf[0]; + } + } + } + } +} + +static void ethsw_spi_wreg(int page, int reg, uint8 *data, int len) +{ + unsigned char buf[64]; + int i; + int spi_ss, cid = 0; + + ethsw_spi_select(page); + + spi_ss = ethsw_spi_ss_id(); + buf[0] = BCM5325_SPI_CMD_NORMAL | BCM5325_SPI_CMD_WRITE | + ((cid & BCM5325_SPI_CHIPID_MASK) << BCM5325_SPI_CHIPID_SHIFT); + + buf[1] = (char)reg; + for (i = 0; i < len; i++) { + /* Write the data out in LE format to the switch */ + buf[BCM5325_SPI_PREPENDCNT+i] = *(data + (len - i - 1)); + } + BcmSpi_Write(buf, len+BCM5325_SPI_PREPENDCNT, LEG_SPI_BUS_NUM, spi_ss, clkHz); +} + +/* External switch register access through MDC/MDIO */ +static void ethsw_mdio_rreg(int page, int reg, uint8 *data, int len) +{ + uint32 cmd, res, ret; + int max_retry = 0; + + cmd = (page << REG_PPM_REG16_SWITCH_PAGE_NUMBER_SHIFT) | REG_PPM_REG16_MDIO_ENABLE; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG16, cmd); + + cmd = (reg << REG_PPM_REG17_REG_NUMBER_SHIFT) | REG_PPM_REG17_OP_READ; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG17, cmd); + + do { + res = mii_read(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG17); + cfe_usleep(10); + } while (((res & (REG_PPM_REG17_OP_WRITE|REG_PPM_REG17_OP_READ)) != REG_PPM_REG17_OP_DONE) && + (max_retry++ < 5)); + + ret = 0; + ret |= mii_read(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG24) << 0; + ret |= mii_read(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG25) << 16; + switch (len) { + case 1: + *data = (uint8)ret; + break; + case 2: + *(uint16 *)data = (uint16)ret; + break; + case 4: + *(uint32 *)data = ret; + break; + } +} + +static void ethsw_mdio_wreg(int page, int reg, uint8 *data, int len) +{ + uint32 cmd, res; + uint32 val = 0; + int max_retry = 0; + + switch (len) { + case 1: + val = *data; + break; + case 2: + val = *(uint16 *)data; + break; + case 4: + val = *(uint32 *)data; + break; + } + cmd = (page << REG_PPM_REG16_SWITCH_PAGE_NUMBER_SHIFT) | REG_PPM_REG16_MDIO_ENABLE; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG16, cmd); + + cmd = val>>0 & 0xffff; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG24, cmd); + cmd = val>>16 & 0xffff; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG25, cmd); + cmd = 0; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG26, cmd); + cmd = 0; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG27, cmd); + + cmd = (reg << REG_PPM_REG17_REG_NUMBER_SHIFT) | REG_PPM_REG17_OP_WRITE; + mii_write(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG17, cmd); + + do { + res = mii_read(PSEUDO_PHY_ADDR, REG_PSEUDO_PHY_MII_REG17); + cfe_usleep(10); + } while (((res & (REG_PPM_REG17_OP_WRITE|REG_PPM_REG17_OP_READ)) != REG_PPM_REG17_OP_DONE) && + (max_retry++ < 5)); +} + +void ethsw_rreg_ext(int access_type, int page, int reg, uint8 *data, int len) +{ + if (access_type == MDIO_BUS) { + ethsw_mdio_rreg(page, reg, data, len); + + } else { + ethsw_spi_rreg(page, reg, data, len); + } +} + +void ethsw_wreg_ext(int access_type, int page, int reg, uint8 *data, int len) +{ + if (access_type == MDIO_BUS) { + ethsw_mdio_wreg(page, reg, data, len); + } else { + ethsw_spi_wreg(page, reg, data, len); + } +} + +int ext_switch_init(void) +{ + uint8 data8; + uint32 data32, access_type; +#if !defined(_BCM96328_) + uint32 clkSave; +#endif + + switch (EnetInfo[1].usConfigType) { + case BP_ENET_CONFIG_SPI_SSB_0: + case BP_ENET_CONFIG_SPI_SSB_1: + case BP_ENET_CONFIG_SPI_SSB_2: + case BP_ENET_CONFIG_SPI_SSB_3: + access_type = SPI_BUS; +#if !defined(_BCM96328_) + clkSave = SPI->spiClkCfg & SPI_CLK_MASK; + xprintf("spiClkCfg = %x; clkSave = %d \n", SPI->spiClkCfg, clkSave); + SPI->spiClkCfg = (SPI->spiClkCfg & ~SPI_CLK_MASK) | clk781k; +#endif + break; + + case BP_ENET_CONFIG_MDIO_PSEUDO_PHY: + access_type = MDIO_BUS; + break; + + default: + xprintf("Unknown PHY configuration type\n"); + return -1; + } + + ethsw_rreg_ext(access_type, PAGE_MANAGEMENT, REG_DEVICE_ID, (uint8 *)&data32, sizeof(data32)); + xprintf("External switch id = %x \n", data32); + + if (data32 == 0x53115) + { + /* setup Switch MII1 port state override */ + data8 = (REG_CONTROL_MPSO_MII_SW_OVERRIDE | + REG_CONTROL_MPSO_SPEED1000 | + REG_CONTROL_MPSO_FDX | + REG_CONTROL_MPSO_LINKPASS); + ethsw_wreg_ext(access_type, PAGE_CONTROL, + REG_CONTROL_MII1_PORT_STATE_OVERRIDE, &data8, sizeof(data8)); + /* management mode, enable forwarding */ + data8 = REG_SWITCH_MODE_FRAME_MANAGE_MODE | REG_SWITCH_MODE_SW_FWDG_EN; + ethsw_wreg_ext(access_type, PAGE_CONTROL, + REG_SWITCH_MODE, &data8, sizeof(data8)); + /* Enable IMP Port */ + data8 = ENABLE_MII_PORT; + ethsw_wreg_ext(access_type, PAGE_MANAGEMENT, + REG_GLOBAL_CONFIG, &data8, sizeof(data8)); + /* Disable BRCM Tag for IMP */ + data8 = ~REG_BRCM_HDR_ENABLE; + ethsw_wreg_ext(access_type, PAGE_MANAGEMENT, + REG_BRCM_HDR_CTRL, &data8, sizeof(data8)); + /* enable rx bcast, ucast and mcast of imp port */ + data8 = (REG_MII_PORT_CONTROL_RX_UCST_EN | + REG_MII_PORT_CONTROL_RX_MCST_EN | + REG_MII_PORT_CONTROL_RX_BCST_EN); + ethsw_wreg_ext(access_type, PAGE_CONTROL, REG_MII_PORT_CONTROL, &data8, sizeof(data8)); + } + +#if !defined(_BCM96328_) + if (access_type == SPI_BUS) + SPI->spiClkCfg = (SPI->spiClkCfg & ~SPI_CLK_MASK) | clkSave; +#endif + return 0; +} + + +void robosw_init(void) +{ + int port; + + BpGetEthernetMacInfo(EnetInfo, BP_MAX_ENET_MACS); + + // Power up and reset EPHYs + GPIO->RoboswEphyCtrl = 0; + cfe_usleep(1000); + + // Take EPHYs out of reset + GPIO->RoboswEphyCtrl = + EPHY_RST_4 | + EPHY_RST_3 | + EPHY_RST_2 | + EPHY_RST_1; + cfe_usleep(1000); + +#if defined(_BCM96328_) || defined(_BCM96362_) + GPIO->RoboswSwitchCtrl |= (RSW_MII_DUMB_FWDG_EN | RSW_HW_FWDG_EN); +#endif +#if defined(_BCM96368_) || defined(_BCM96816_) + GPIO->RoboswEphyCtrl |= (RSW_MII_DUMB_FWDG_EN | RSW_HW_FWDG_EN); +#endif + + // Enable Switch clock + PERF->blkEnables |= ROBOSW_CLK_EN; +#if defined(_BCM96368_) + PERF->blkEnables |= SWPKT_SAR_CLK_EN | SWPKT_USB_CLK_EN; +#endif +#if defined(_BCM96816_) + PERF->blkEnables |= SWPKT_GPON_CLK_EN | SWPKT_USB_CLK_EN; +#endif + + cfe_usleep(1000); + + PERF->softResetB &= ~SOFT_RST_SWITCH; + cfe_usleep(1000); + PERF->softResetB |= SOFT_RST_SWITCH; + cfe_usleep(1000); + + /* Disable Rx and Tx on all Ethernet Ports */ + for (port = 0; port < EPHY_PORTS; port++) { + SWITCH->PortCtrl[port] = 0x03; + } + + if (EnetInfo[1].ucPhyType == BP_ENET_EXTERNAL_SWITCH) { + ext_switch_init(); + } + +} + +void robosw_configure_ports() +{ + uint16 data; + int i; + + for (i = 0; i < 6; i++) { + if ((EnetInfo[0].sw.port_map & (1 << i)) != 0) { + if (EnetInfo[0].sw.phy_id[i] == 0xff) { +#if defined(_BCM96368_) + if (i == 4) + GPIO->GPIOBaseMode |= (EN_GMII1); + if (i == 5) + GPIO->GPIOBaseMode |= (EN_GMII2); +#endif + continue; + } + if (IsWanPort(EnetInfo[0].sw.phy_id[i])) { + *(SWITCH_PBVLAN + i) = PBMAP_MIPS; + SWITCH->DisableLearn |= (1 << i); + } + // Reset + mii_write(EnetInfo[0].sw.phy_id[i], MII_BMCR, BMCR_RESET); + PortLinkState[i] = 0; + if (!IsExtPhyId(EnetInfo[0].sw.phy_id[i])) { + // Configure PHY link/act LED +#if defined(_BCM96368_) + // Enable status change notification */ + mii_write(EnetInfo[0].sw.phy_id[i], MII_INTERRUPT, MII_INTR_ENABLE); + // Configure LEDs + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_RESERVED_1B); + mii_write(EnetInfo[0].sw.phy_id[i], MII_RESERVED_1B, data | MII_RESERVED_1B_ACT_LED); +#elif defined(_BCM96816_) + // Configure LEDs + mii_write(EnetInfo[0].sw.phy_id[i], 0x1c, 0xa410); +#elif defined(_BCM96328_) || defined(_BCM96362_) + // Configure LEDs + // Enable Shadow register 2 + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_BRCM_TEST); + mii_write(EnetInfo[0].sw.phy_id[i], MII_BRCM_TEST, (data | MII_BRCM_TEST_SHADOW2_ENABLE)); + // Set LED0 to speed. Set LED1 to blinky link + mii_write(EnetInfo[0].sw.phy_id[i], 0x15, 0x71); + // Disable Shadow register 2 + mii_write(EnetInfo[0].sw.phy_id[i], MII_BRCM_TEST, (data & ~MII_BRCM_TEST_SHADOW2_ENABLE)); +#endif + } else { +#if defined(_BCM96368_) + if (i == 4) + GPIO->GPIOBaseMode |= (EN_GMII1); + if (i == 5) + GPIO->GPIOBaseMode |= (EN_GMII2); +#endif +#if defined(_BCM96816_) + if (i == 2) + GPIO->GPIOBaseMode |= (EN_GMII1); + if (i == 3) + GPIO->GPIOBaseMode |= (EN_GMII2); +#endif +#if defined(_BCM96362_) + if (i == 4) + GPIO->RoboswSwitchCtrl |= (RSW_MII_SEL_2P5V << RSW_MII_SEL_SHIFT); + if (i == 5) + GPIO->RoboswSwitchCtrl |= (RSW_MII_2_IFC_EN | (RSW_MII_SEL_2P5V << RSW_MII_2_SEL_SHIFT)); +#endif +#if defined(_BCM96328_) + if (i == 4) + MISC->miscPadCtrlHigh |= (MISC_MII_SEL_2P5V << MISC_MII_SEL_SHIFT); +#endif + // Reset + mii_write(EnetInfo[0].sw.phy_id[i], MII_BMCR, BMCR_RESET); + // Enable auto-negotiation + mii_write(EnetInfo[0].sw.phy_id[i], MII_ANAR, ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD | PSB_802_3); + + // Configure LED for link/activity + data = MII_1C_SHADOW_LED_CONTROL << MII_1C_SHADOW_REG_SEL_S; + mii_write(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C, data); + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C); + data |= ACT_LINK_LED_ENABLE; + data |= MII_1C_WRITE_ENABLE; + mii_write(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C, data); + + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_PHYIDR2); + if ((data & BCM_PHYID_M) == (BCM54610_PHYID2 & BCM_PHYID_M)) { + // Configure RGMII timing for 54610 GPHY + data = MII_1C_SHADOW_CLK_ALIGN_CTRL << MII_1C_SHADOW_REG_SEL_S; + mii_write(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C, data); + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C); + data &= (~GTXCLK_DELAY_BYPASS_DISABLE); + data |= MII_1C_WRITE_ENABLE; + mii_write(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C, data); + + // Configure LOM LED Mode + data = MII_1C_EXTERNAL_CONTROL_1 << MII_1C_SHADOW_REG_SEL_S; + mii_write(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C, data); + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C); + data |= LOM_LED_MODE; + data |= MII_1C_WRITE_ENABLE; + mii_write(EnetInfo[0].sw.phy_id[i], MII_REGISTER_1C, data); + } + } + // Restart auto-negotiation + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_BMCR); + mii_write(EnetInfo[0].sw.phy_id[i], MII_BMCR, data | BMCR_RESTARTAN); + } + } + +#if defined(_BCM96816_) + // Disable SERDES, MoCA, USB and GPON port + SWITCH->PortOverride[SERDES_PORT_ID] = PortOverride_Enable; + SWITCH->PortOverride[MOCA_PORT_ID] = PortOverride_Enable; + SWITCH->PortOverride[USB_PORT_ID] = PortOverride_Enable; + SWITCH->PortOverride[GPON_PORT_ID] = PortOverride_Enable; +#endif + +#if defined(_BCM96328_) || defined(_BCM96362_) + // Ports 6 and 7 are not used on 6328 and 6362 + SWITCH->PortOverride[PORT_6_PORT_ID] = PortOverride_Enable; + SWITCH->PortOverride[PORT_7_PORT_ID] = PortOverride_Enable; +#endif + +#if defined(_BCM96368_) + // Disable SAR and USB port + SWITCH->PortOverride[USB_PORT_ID] = PortOverride_Enable; + SWITCH->PortOverride[SAR_PORT_ID] = PortOverride_Enable; +#endif + + // Enable the GMII clocks. + SWITCH->ImpRgmiiCtrlP4 |= ImpRgmiiCtrl_GMII_En; + /* RGMII Delay Programming. Enable ID mode */ + SWITCH->ImpRgmiiCtrlP4 |= ImpRgmiiCtrl_Timing_Sel; + +#if !defined(_BCM96328_) + SWITCH->ImpRgmiiCtrlP5 |= ImpRgmiiCtrl_GMII_En; + SWITCH->ImpRgmiiCtrlP5 |= ImpRgmiiCtrl_Timing_Sel; +#endif + + // Reset MIB counters + SWITCH->GlbMgmt = GlbMgmt_ResetMib; + cfe_usleep(100); + SWITCH->GlbMgmt = 0; + + SWITCH->ImpOverride |= ImpOverride_Force | ImpOverride_Linkup; + +} + +void robosw_check_ports() +{ + uint16 data; + uint8 PortOverride; + int i; + + for (i = 0; i < EPHY_PORTS; i++) { + if ((EnetInfo[0].sw.port_map & (1 << i)) != 0) { + if (EnetInfo[0].sw.phy_id[i] == 0xff) { + PortOverride = PortOverride_Enable | PortOverride_1000Mbs | + PortOverride_Fdx | PortOverride_Linkup; + if ((SWITCH->PortOverride[i] & PortOverride) != PortOverride) { + SWITCH->PortOverride[i] = PortOverride; + SWITCH->PortCtrl[i] = 0; + PortLinkState[i] = 1; + } + continue; + } + PortOverride = PortOverride_Enable; + data = mii_read(EnetInfo[0].sw.phy_id[i], MII_ASR); + if (PortLinkState[i] != MII_ASR_LINK(data)) { + + if (MII_ASR_LINK(data)) + PortOverride |= PortOverride_Linkup; + + if (MII_ASR_DONE(data)) { + if (MII_ASR_FDX(data)) + PortOverride |= PortOverride_Fdx; + if (MII_ASR_1000(data)) + PortOverride |= PortOverride_1000Mbs; + else if (MII_ASR_100(data)) + PortOverride |= PortOverride_100Mbs; + else + PortOverride |= PortOverride_10Mbs; + } + + SWITCH->PortOverride[i] = PortOverride; + + if(PortOverride & PortOverride_Linkup) { + /* Enable Rx and Tx */ + SWITCH->PortCtrl[i] = 0; + } + + PortLinkState[i] = MII_ASR_LINK(data); + } + } + } +} + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile new file mode 100755 index 0000000..808ddc2 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/Makefile @@ -0,0 +1,23 @@ +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96328") +BSPOBJS += \ + bcm63xx_impl1_rom_boot.o +endif +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96362") +BSPOBJS += \ + bcm63xx_impl1_rom_boot.o +endif +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96368") +BSPOBJS += \ + bcm6368_rom_boot.o \ + bcm6368_sdramDqs.o +endif +ifeq ($(strip ${CFG_BOARDNAME}),"BCM96816") +BSPOBJS += \ + bcm63xx_impl1_rom_boot.o +endif +ifeq ($(strip ${INC_NAND_FLASH_DRIVER}),1) +BSPOBJS += \ + nandflash.o +endif +BSPOBJS += \ + bcm63xx_main.o diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S new file mode 100755 index 0000000..f1cba19 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_rom_boot.S @@ -0,0 +1,548 @@ +#include "sbmips.h" +#include "bsp_config.h" + +#include "6368_cpu.h" +#include "6368_common.h" +#include "bcm_hwdefs.h" +#include "boardparms.h" +#include "mipsmacros.h" + +#define SETLEDS1(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + bal board_setleds + +/* ********************************************************************* + * BOARD_EARLYINIT() + * + * Initialize board registers. This is the earliest + * time the BSP gets control. This routine cannot assume that + * memory is operational, and therefore all code in this routine + * must run from registers only. The $ra register must not + * be modified, as it contains the return address. + * + * This routine will be called from uncached space, before + * the caches are initialized. If you want to make + * subroutine calls from here, you must use the CALLKSEG1 macro. + * + * Among other things, this is where the GPIO registers get + * programmed to make on-board LEDs function, or other startup + * that has to be done before anything will work. + * + * Input parameters: + * a0 - Flash base address (address of MIPS reset) + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(board_earlyinit) + + .set noreorder + + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, 2f # if we are running on thread 1, skip init + nop + +#if 0 + /* wait for a while to allow catch by jtag debugger */ + li t8, -(200000000*3) /* we will count up to 0 to delay a couple of seconds */ + /* and give the emulator a chance to catch us */ + mtc0 t8, C0_COUNT +catchloop: + bltz t8, catchloop + mfc0 t8, C0_COUNT +#endif + + /**--------------------------------------------------------------**/ + /** platform specific code **/ + /**--------------------------------------------------------------**/ + /**----- Enable I Cache -----------------------------------------**/ + mfc0 t1, C0_BCM_CONFIG + or t1, (CP0_BCM_CFG_ICSHEN | CP0_BCM_CFG_DCSHEN) + mtc0 t1, C0_BCM_CONFIG # Enable I Cache + + // In the begining MIPS core registers are mapped to 0xbfax_xxxx + li t1, 0x1FA0000C # Set up CBR to 1FAx_xxxx + mtc0 t1, C0_BCM_CONFIG, 6 + + li t1, MIPS_BASE_BOOT + lw t2, MIPS_LMB_CR(t1) + or t2, 0xC0000000 # enable ffxx_xxxx space + sw t2, MIPS_LMB_CR(t1) + li t2, 0xFFF80001 # SBR FFF8_xxxx and enable + sw t2, MIPS_SBR(t1) + + // Now map MIPS core registers to 0xFF4x_xxxx space + li t1, 0xFF40000C # CBR FF4x_xxxx (and reserved bits 0xc). + mtc0 t1, C0_BCM_CONFIG, 6 + + /**----- Initialize EBI -----------------------------------------**/ + li t1, MPI_BASE + li t2, EBI_SIZE_32M + or t2, a0 + sw t2, CS0BASE(t1) # CS[0] Base + li t2, THREEWT|EBI_WORD_WIDE|EBI_ENABLE + sw t2, CS0CNTL(t1) # CS[0] Control + + /**----- Initialize Serial --------------------------------------**/ + li t3, ((FPERIPH / 115200) / 16) + /* + # Baudword = (FPeriph)/Baud/32-1. We have to perform rounding + # and subtraction. Above we divided by 16 (instead of 32). If + # bit0 is set, we round up. However, we then subtract 1, so final + # result should be t3/2. If bit0 is 0, then we truncate and subtract + # 1, t3=t3/2-1. + */ + andi t0, t3, 0x1 + bne t0,zero,1f # do shift only (in delay slot) + # and jump to apply + srl t3,1 # do divide by 2 + addiu t3, -1 # subtract 1 +1: + + # t3 contains the UART BAUDWORD + li t0, UART_BASE + sw t3, UART0BAUD(t0) # Store BaudRate + li t1, BITS8SYM|ONESTOP + sb t1, UART0CONFIG(t0) # 8 Bits/1 Stop + li t1, TXEN|RXEN|BRGEN + sb t1, UART0CONTROL(t0) # Enable, No Parity + move t1, zero + sh t1, UART0INTMASK(t0) + + .set reorder +2: + j ra +END(board_earlyinit) + +/* ********************************************************************* + * BOARD_DRAMINFO + * + * Return the address of the DRAM information table + * + * Input parameters: + * nothing + * + * Return value: + * v0 - DRAM info table, return 0 to use default table + ********************************************************************* */ +LEAF(board_draminfo) + j ra +END(board_draminfo) + +/* ********************************************************************* + * BOARD_DRAMINIT + * + * This routine should activate memory. + * + * Input parameters: + * None + * + * Return value: + * None + * + * Registers used: + * can use all registers. + ********************************************************************* */ +LEAF(board_draminit) + .set noreorder + + li t0, MEMC_BASE + li t1, DDR_BASE + + li t4, (7 << 28) | (7 << 24) | (1 << 20) | (7 << 16) # UBUS_CNTR_CYCLES = 7, LLMB_CNTR_CYCLES = 7, PH_CNTR_EN = 1, PH_CNTR_CYCLES = 7 + sw t4, DDR_MIPS_PHASE_CNTL(t1) + + # Calculate a value for a 90 degree phase shift. + + lw t2, DDR_MIPSDDR_PLL_MDIV(t1) + srl t2, 8 # Shift and mask off DDR_MDIV + and t2, 0xff + sll t2, 2 # PI_steps = (90deg * 16 * MBUS(t2) + 2)/360 ~= MBUS * 4 + or t2, (1 << 14) # set the count direction + + lw t3, DDR_DDR3_4_PHASE_CNTL(t1) # Get current DDR3/4 value. + ori t3, 0x7fff # Clear low 15 bits (DDR3 value). + xori t3, 0x7fff + or t3, t2 # Set new DDR3 value, preserving existing DDR4 value. + sw t3, DDR_DDR3_4_PHASE_CNTL(t1) + + li t4, (1 << 28) | (7 << 24) | (1 << 23) | (1 << 20) | (7 << 16) # UBUS_CNTR_CYCLES = 1, LLMB_CNTR_CYCLES = 7, UBUS_CNTR_EN = 1, PH_CNTR_EN = 1, PH_CNTR_CYCLES = 7 + sw t4, DDR_MIPS_PHASE_CNTL(t1) + + li t4, 0x103e + sw t4, DDR_UBUS_PI_DSK1(t1) + li t4, 0x40000000 + sw t4, DDR_UBUS_PI_DSK0(t1) + + ## Set PI mask, and frequnecy of updates + # bit[5:0] 1 to 31, controls how often feedback is send back to PI + # bit[7] update register in sampling logic to take the new value in bit[5:0] + # bit[14:8] masking bits for the sampling result + + li t2, 0x00000010 # 0x8 for 8 DDR cycles, 0x10 for 16 DDR cycles, 0x4 for 4 DDR cycles, can take values from 1 to 31 + sw t2, DDR_UBUS_PI_DSK0(t1) # set PI update to 16 ddr cycles + li t2, 0x00000090 # update value + sw t2, DDR_UBUS_PI_DSK0(t1) + li t2, 0x00000c90 # set mask to 0001100; 0x1890 will set mask to 0011000 + sw t2, DDR_UBUS_PI_DSK0(t1) + + ###### Check to see if we found the edge... + ###### Ideally we want to loop here until we find an edge.... + + li t3, 0 + li t2, 10000 + +1: + # Looking for a rising edge. + lw t4, DDR_UBUS_PI_DSK0(t1) # Read a sample value. + srl t4, 16 # The sample is in the upper 16 bits. + andi t4, 0x41 # Look at the 2 outermost bits; if the LSB is 0 and the MSB is 1, + beq t4, 0x40, 2f # then there is an edge somewhere in the sample. + + addi t3, 1 + bne t2, t3, 1b + nop + +2: + + /**----- Configure DDR controller ------------------------------------**/ + li v0, 16 + li t2, ((MEMC_12BIT_ROW << MEMC_ROW_SHFT) | (MEMC_9BIT_COL << MEMC_COL_SHFT)) + or t2, (MEMC_16BIT_BUS << MEMC_WIDTH_SHFT) + or t2, (MEMC_SEL_PRIORITY) + or t2, (2 << MEMC_EARLY_HDR_CNT_SHFT) + or t2, (MEMC_USE_HDR_CNT) +// or t2, (MEMC_EN_FAST_REPLY) + or t2, (MEMC_RR_ARB) + or t2, (MEMC_DQS_GATE_EN | MEMC_MEMTYPE_DDR) + sw t2, MEMC_CONFIG(t0) # Enable DDR Mem & SEQ EN, 16MB + + li t2, 0x7 # Reduce drive strength for command pins (per John Lorek) + sw t2, DDR_CMD_PAD_CNTL(t1) + + li t2, 0x00A778DD + sw t2, MEMC_DRAM_TIM(t0) # DDR Timing Set Latency 2.5 Latency,tRAS period =7,tRFC period=12, tWR=3 + li t2, 0x00000003 + sw t2, MEMC_CONTROL(t0) # Turn on CKE + li t2, 0x0000000B + sw t2, MEMC_CONTROL(t0) # PreCharge + li t2, 0x00004002 + sw t2, MEMC_M_EM_BUF(t0) # Value for Extended Mode Register, DDR Reduced Drive Strength On + li t2, 0x00000013 + sw t2, MEMC_CONTROL(t0) # MRS command + li t2, 0x00000163 + sw t2, MEMC_M_EM_BUF(t0) # Reset DLL, Burst Length = 8, Burst Type Sequential 2.5 Latency + li t2, 0x00000013 + sw t2, MEMC_CONTROL(t0) # MRS command + nop # Delay 200 DDR clock cycles (~1.5 uS) + nop + nop + li t2, 0x0000000B + sw t2, MEMC_CONTROL(t0) # Precharge + li t2, 0x0000840f + sw t2, MEMC_REF_PD_CONTROL(t0) # Enable auto refresh + li t2, 0x00000007 + sw t2, MEMC_CONTROL(t0) # Set Auto Refresh Mode + li t2, 0x00000007 + sw t2, MEMC_CONTROL(t0) # Set Auto Refresh Mode + li t2, 0x00000063 + sw t2, MEMC_M_EM_BUF(t0) # Reset DLL, Burst Length = 8, Burst Type Sequential 2.5 Latency + li t2, 0x00000013 + sw t2, MEMC_CONTROL(t0) # MRS + + .set reorder + + li sp, 0x80001000 + sub sp, 8 + sw ra, 0(sp) + sw v0, 4(sp) + bal sdramDqsPhaseSet + lw v0, 4(sp) + lw ra, 0(sp) + add sp, 8 + + /**----- switch to sync -----------------------------------------**/ + li t0, 0xff410000 + li t1, DDR_BASE + li t2, 4048 + li t3, 1 + +1: + lw t4, 0x40(t0) # Read a sample value. + srl t4, 16 # The sample is in the upper 16 bits. + + andi t4, t4, 0x41 # Look at the 2 outermost bits; if the LSB is 0 and the MSB is 1, + beq t4, 0x40, 2f # then there is an edge somewhere in the sample. + + lw t5, DDR_MIPS_PHASE_CNTL(t1) + and t5, 0xffff0000 + or t5, t3 + or t5, (1<<14) + sw t5, DDR_MIPS_PHASE_CNTL(t1) + + lw t5, 0x40(t0) # Delay before reading another sample. + add t3, 1 + bne t2, t3, 1b + b 3f + +2: + # Success + lw t2, DDR_MIPS_PHASE_CNTL(t1) # Turn on auto-PI mode. + and t2, 0xf0ffffff + or t2, (1 << 24) | (1 << 21) # LLMB_CNTR_CYCLES_CNTL = 1, LLMB_CNTR_EN = 1 + sw t2, DDR_MIPS_PHASE_CNTL(t1) + + li t2, 0x0010 # Set PI mask to 0000110, and check new value every 16 MIPS cycles. + sw t2, 0x40(t0) # set PI update to 16 ddr cycles + li t2, 0x80000090 # Enable MIPS auto-PI | Enable update period | Set 16 clock update + sw t2, 0x40(t0) + li t2, 0x80000c90 # Enable MIPS auto-PI | Enable comparator | Enable update period | Set 16 clock update + sw t2, 0x40(t0) + + lw t2, 0x40(t0) # Do a few reads to wait till the edge is stable... + lw t2, 0x40(t0) + lw t2, 0x40(t0) + lw t2, 0x40(t0) + lw t2, 0x40(t0) + + mfc0 t1, C0_BCM_CONFIG, 5 + and t1, ~(0x1 << 28) + mtc0 t1, C0_BCM_CONFIG, 5 + + /**----- Enable RAC and LMB -------------------------------------**/ + li t1, MIPS_BASE + lw t2, MIPS_LMB_CR(t1) + or t2, LMB_EN # Enable LMB + sw t2, MIPS_LMB_CR(t1) + + li t2, 0xFFF << RAC_UPB_SHFT # Enable prefetch for RAM address range up to 256MB + sw t2, MIPS_RAC_ARR(t1) + + lw t2, MIPS_RAC_CR0(t1) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR0(t1) + + lw t2, MIPS_RAC_CR1(t1) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR1(t1) + +3: + /**----- Enable branch prediction and non-blocking data cache ---**/ + mfc0 t1, C0_BCM_CONFIG + and t1, ~CP0_BCM_CFG_BTHD + or t1, CP0_BCM_CFG_NBK + or t1, CP0_BCM_CFG_CLF + mtc0 t1, C0_BCM_CONFIG + + /* Test whether memory is 16 or 32 bit wide */ + li t0, MEMC_BASE + lw t2, MEMC_CONFIG(t0) + and t2, ~MEMC_WIDTH_MASK + or t2, (MEMC_32BIT_BUS << MEMC_WIDTH_SHFT) + sw t2, MEMC_CONFIG(t0) + + li t3, DRAM_BASE_NOCACHE + li t4, 0x12345678 + sw t4, 0(t3) + li t4, 0x87654321 + sw t4, 4(t3) + nop + nop + nop + nop + nop + nop + li t4, 0x12345678 + lw t5, 0(t3) + beq t4, t5, 4f + + /* 16 bit wide memory */ + lw t2, MEMC_CONFIG(t0) + and t2, ~MEMC_WIDTH_MASK + or t2, (MEMC_16BIT_BUS << MEMC_WIDTH_SHFT) + sw t2, MEMC_CONFIG(t0) +4: + j ra + +END(board_draminit) + +/* ********************************************************************* + * BOARD_SETLEDS(x) + * + * Set LEDs for boot-time progress indication. Not used if + * the board does not have progress LEDs. This routine + * must not call any other routines, since it may be invoked + * either from KSEG0 or KSEG1 and it may be invoked + * whether or not the icache is operational. + * + * Input parameters: + * a0 - LED value (8 bits per character, 4 characters) + * + * Return value: + * nothing + * + * Registers used: + * t0,t1,t2,t3 + ********************************************************************* */ +LEAF(board_setleds) +#if 0 + li t0, UART_BASE + li t2, TXFIFOEMT + +1: lh t1, UART0INTSTAT(t0) + and t1, t2 + bne t1, t2, 1b + + srl t3, a0, 24 + sb t3, UART0DATA(t0) + srl t3, a0, 16 + sb t3, UART0DATA(t0) + srl t3, a0, 8 + sb t3, UART0DATA(t0) + sb a0, UART0DATA(t0) + li a0, '\r' + sb a0, UART0DATA(t0) + li a0, '\n' + sb a0, UART0DATA(t0) +#endif + j ra +END(board_setleds) + +/* ********************************************************************* + * BCMCORE_TP1_SWITCH() + * + * Check if the thread switch is required. If we are already + * running on thread 1 this function will do nothing and just return + * If we are running on thread 0 this function will take thread 1 + * out of reset and put thread 0 to sleep waiting for singnal from + * thread 1. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +LEAF(bcmcore_tp1_switch) + + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, tp1 # Already running on thread 1 + +# Start TP1 +# Set boot address for TP1 + li t1, MIPS_BASE + li t2, 0x98000000 | ENABLE_ALT_BV + sw t2, MIPS_TP1_ALT_BV(t1) + +# Set a flag so we can wait for TP1 to catch up + li t1, 0x0 + mtc0 t1, $31 # CO_DESAVE + +# Take TP1 out of reset + mfc0 t1, C0_BCM_CONFIG, 2 + or t1, CP0_CMT_RSTSE + mtc0 t1, C0_BCM_CONFIG, 2 + + /* wait until second thread catches up with the first */ +waittp1: + mfc0 t0, $31 # CO_DESAVE + beqz t0, waittp1 + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + bne t0, t1, return # Linux will run on TP0, continue running bootloader + +# Voice will run on TP0. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set all ints except IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_4 | CP0_CMT_XIR_3 | CP0_CMT_XIR_2 | CP0_CMT_XIR_0 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP1) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP1, give priority to TP0, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_DSU_TP1 | CP0_CMT_PRIO_TP0 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP0 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR0(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR0(t1) + +2: + li t8, 0 + b wait_for_wake + +tp1: +# Running on TP1.... +# First signal to TP0 that TP1 is up + li t1, 0x1 + mtc0 t1, $31 # CO_DESAVE + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + beq t0, t1, return # Linux will run on TP1, continue running bootloader + +# Voice will run on TP1. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_1 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP0) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP0, give priority to TP1, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_PRIO_TP1 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP1 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR1(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR1(t1) + b 2b + +return: + j ra + +END(bcmcore_tp1_switch) + +# align this code to cache line. NAND flash is not memory mapped after system boots +# so when we are signaling to the second TP to wake we need +# jal instruction to be in cache + .align 4 +LEAF(wait_for_wake) + sync + wait # wait for interrupt + jal t8 # jump to entry point +END(wait_for_wake) diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c new file mode 100755 index 0000000..96d5000 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm6368_sdramDqs.c @@ -0,0 +1,439 @@ +/*************************************************************************** +* +* Copyright (c) 2004 Broadcom Corporation, All Rights Reserved. +* Contains proprietary and confidential information. +* +* No portions of this material may be reproduced in any form without the +* written permission of: +* +* Broadcom Corporation +* 16215 Alton Parkway +* P.O. Box 57013 +* Irvine, California 92619-7013 +* +* All information contained in this document is Broadcom Corporation +* company private, proprietary, and trade secret. +* +****************************************************************************/ +#include "lib_types.h" +#include "bcm_map.h" + +// Uncomment out the below line to use MemoryTestSuite() +// #define EXTENDED_MEMORY_TESTS + +/* ---- Private Constants and Types -------------------------------------- */ +#define VCDL_PHASE_DEFAULT 16 +#define VCDL_PHASE_MAX 47 /* 154.69 degree */ +#define VCDL_PHASE_MIN 0 /* 22.5 degree */ + +typedef unsigned long u; + +#define N 32*1024 // Size of the copy operation + // Must be at least equal to the L2 cache size +#define S (1*sizeof(u)) + +/* ---- Private Function Prototypes -------------------------------------- */ +inline static int MemoryTest(void) __attribute__((always_inline)); +inline static void PI_upper_set(volatile uint32 *, int bitOffset, int shift) __attribute__((always_inline)); +inline static void PI_shmoo(volatile uint32 *PI_reg, int bitOffset, int minValue, int maxValue, int increment) __attribute__((always_inline)); +inline static void shmooVcdl(int minValue, int maxValue, int increment) __attribute__((always_inline)); + +// #define DEBUG_SHMOO 1 +#if DEBUG_SHMOO +inline static void dumpChar(uint8 c) __attribute__((always_inline)); +inline static void dumpChar(uint8 c) +{ + //wait till tx fifo below threshold + while (UART->txf_levl > 14); + UART->Data = c; +} + +#else +#define dumpChar(c) +#endif + +#if defined(EXTENDED_MEMORY_TESTS) +#include "memtest.c"/* Suite memory tests SCAN, MARCH, SLIDING, SHIFT ADDRESS */ +inline static int MemoryTestSuite(void) __attribute__((always_inline)); +#endif + +/* ==== Public Functions ================================================= */ +void sdramDqsPhaseSet(void); +void vcdlCalibration(void); + +/*******************************************************************************/ +void sdramDqsPhaseSet(void) +{ + int dqOutPhaseMax; + int delay; + int ubusPhase, mipsPhase; + int equalCount = 0; + + // Reset VCDL + DDR->Spare1 |= 0x1; + delay = 1000; + while(delay--); + DDR->Spare1 &= ~0x1; + + // Calculate max phase offset from PLL config register. + dqOutPhaseMax = ((DDR->MIPSDDRPLLMDiv & DDR_MDIV_MASK) >> DDR_MDIV_SHFT) * 8; + + dumpChar('\n'); + dumpChar('\r'); + + // Start by setting VCDL to the default. This almost always works. + // Enable squelch + DDR->WSliceCntl |= (0x1<<20) | (0x1<<4); + DDR->VCDLPhaseCntl0 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + DDR->VCDLPhaseCntl1 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + DDR->WSliceCntl &= ~((0x1<<20) | (0x1<<4)); + + // Now shmoo over DQ phase to find an optimum value. + dumpChar('D');dumpChar('D');dumpChar('R');dumpChar('2'); + dumpChar('\n'); + dumpChar('\r'); + PI_shmoo(&DDR->DDR1_2PhaseCntl0, 16, -dqOutPhaseMax, dqOutPhaseMax, 1); + + dumpChar('V');dumpChar('C');dumpChar('D');dumpChar('L'); + dumpChar('\n'); + dumpChar('\r'); + shmooVcdl(VCDL_PHASE_MIN, VCDL_PHASE_MAX, 1); + + // Now setup the UBUS clock + dumpChar('U');dumpChar('B');dumpChar('U');dumpChar('S'); + dumpChar('\n'); + dumpChar('\r'); + + MEMC->RefreshPdControl &= ~MEMC_REFRESH_ENABLE; // Turn off refresh while messing with UBus clock + + DDR->MIPSPhaseCntl &= ~(0x1<<23); // turn off ubus PI auto mode + + mipsPhase = DDR->MIPSPhaseCntl; + do { + if (DDR->MIPSPhaseCntl == mipsPhase) + equalCount++; + else { + equalCount = 0; + mipsPhase = DDR->MIPSPhaseCntl; + } + } while (equalCount < 3); + + ubusPhase = ((DDR->UBUSPhaseCntl) & 0x3ffe); // make it even and decrease count + DDR->UBUSPhaseCntl = ubusPhase; + + // Wait until we match several times in a row, to be sure we wait long enough + do { + if (DDR->UBUSPhaseCntl == ubusPhase) + equalCount++; + else + equalCount = 0; + } while (equalCount < 3); + + MEMC->RefreshPdControl |= MEMC_REFRESH_ENABLE; +} + + +/* ==== Private Functions ================================================ */ + +inline static void PI_upper_set(volatile uint32 *PI_reg, int bitOffset, int shift) +{ + uint32 oldVal; + uint32 newVal; + int32 oldPhase; + int32 newPhase; + int equalCount = 0; + + oldVal = *PI_reg; // get the phase config (may have other controls in other 16 bits) + + oldPhase = ( oldVal >> bitOffset ) & 0x3fff; + if ( oldPhase & (0x1<<13) ) { + oldPhase |= ~0x3fff; // sign extend + } + + newPhase = shift & 0x3fff; // set up phase shift value[13:0] + if (shift > oldPhase) { // set up up/down [14], shift is signed value + newPhase |= 0x1<<14; + } + + newPhase = newPhase << bitOffset; + oldVal = oldVal & (0xffff << (16-bitOffset)); // Keep the other control bits + newVal = newPhase | oldVal; + *PI_reg = newVal; + + // Wait until we match several times in a row, to be sure we wait long enough + do { + if (*PI_reg == newVal) + equalCount++; + else + equalCount = 0; + } while (equalCount < 3); +} + + +inline static void PI_shmoo(volatile uint32 *PI_reg, int bitOffset, int minValue, int maxValue, int increment) +{ + int piPhase, piPhaseCnt, passStatus; + int pass1Start, pass1Fail, pass2Start, pass2Fail; + int pass1Cnt, pass2Cnt; + + PI_upper_set(PI_reg, bitOffset, minValue); + + passStatus = 0; + pass1Start = maxValue; + pass1Fail = minValue; + pass2Start = minValue; + pass2Fail = minValue; + + for (piPhase = minValue; piPhase <= maxValue; piPhase += increment) { + + // if (MemoryTestSuite()) + if (MemoryTest()) + { + if (passStatus == 0x0) { // first_pass start + passStatus = 0x1; + pass1Start = piPhase; + } + else if (passStatus == 0x2) { // second_pass start + passStatus = 0x3; + pass2Start = piPhase; + } + dumpChar('p'); + } + else { + if (passStatus == 0x1) { // fisrt_pass end + passStatus = 0x2; + pass1Fail = piPhase; + } + else if (passStatus == 0x3) { // second_pass end + passStatus = 0x4; + pass2Fail = piPhase; + } + dumpChar('.'); + } + + piPhaseCnt = ( piPhase + 0x01) & 0x3fff; + if (increment) { + piPhaseCnt |= (0x01<<14); + } + + *PI_reg = (*PI_reg & (0xffff << (16-bitOffset))) | (piPhaseCnt<> 1; // mid-point of the pass window + } else { + piPhaseCnt = (pass1Start + pass1Fail - 0x1) >> 1; // mid-point of the pass window + } + } + else if ((pass1Start == minValue) && (pass2Start != minValue) && (pass2Fail == minValue)) { // valid window 2 + pass1Cnt = pass1Fail - minValue; + pass2Cnt = maxValue - pass2Start + 1; + passStatus= (pass1Cnt + pass2Cnt) >> 1; + if (passStatus < pass1Cnt) { // mid-point of the overall pass window is in sub-window 1 + piPhaseCnt = minValue + ( pass1Cnt - passStatus ); + } + else { + piPhaseCnt = pass2Start - 0x1 + passStatus; + } + } + else { + piPhaseCnt = 0x0; // shmoo failed. + } + + piPhaseCnt &= ~0x01; // make it even number + + PI_upper_set(PI_reg, bitOffset, piPhaseCnt); // set the final phase value + + dumpChar('\n'); + dumpChar('\r'); +} + + +inline static void shmooVcdl(int minValue, int maxValue, int increment) +{ + UINT32 dqsInPhase; + UINT32 dqsInSum = 0; + UINT32 passCnt = 0; + volatile int delay; + + for (dqsInPhase = minValue; dqsInPhase <= maxValue; dqsInPhase += increment) { + delay = 1000; + while(delay--); + // Enable squelch + DDR->WSliceCntl |= (0x1<<20) | (0x1<<4); + DDR->VCDLPhaseCntl0 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + DDR->VCDLPhaseCntl1 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + DDR->WSliceCntl &= ~((0x1<<20) | (0x1<<4)); + + delay = 1000; + while(delay--); + +#if defined(EXTENDED_MEMORY_TESTS) + if (MemoryTestSuite() == MEMTEST_SUCCESS ) +#else + if (MemoryTest()) +#endif + { + dqsInSum += dqsInPhase; + passCnt++; + dumpChar('p'); + } + else { + dumpChar('.'); + } + } + delay = 1000; + while(delay--); + // Enable squelch + DDR->WSliceCntl |= (0x1<<20) | (0x1<<4); + if (passCnt > 0) { + dqsInPhase = dqsInSum / passCnt; + DDR->VCDLPhaseCntl0 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + DDR->VCDLPhaseCntl1 = (dqsInPhase << 22) | (dqsInPhase << 16) | (dqsInPhase << 6) | dqsInPhase; + } + else { + DDR->VCDLPhaseCntl0 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + DDR->VCDLPhaseCntl1 = (VCDL_PHASE_DEFAULT << 22) | (VCDL_PHASE_DEFAULT << 16) | (VCDL_PHASE_DEFAULT << 6) | VCDL_PHASE_DEFAULT; + } + DDR->WSliceCntl &= ~((0x1<<20) | (0x1<<4)); + dumpChar('\n'); + dumpChar('\r'); +} + +#if defined(EXTENDED_MEMORY_TESTS) + +// Define the memory size for use by the memory test suite +#define MEMORY_SIZE (2 * 1024) + +int MemoryTestSuite(void) +{ + int test = 1; + uint32_t * memory = (uint32_t*) (0xa0000000); + Pattern_t pat32, patIx; + + for (patIx = PATTERN_0x00000000; patIx < PATTERN_MAX; patIx++ ) + { + pat32 = pattern[ patIx ]; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanWordValue( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanBulkValue( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanBulkAltInv( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( slidingAltInv( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( slidingDiag( memory, MEMORY_SIZE, pat32 ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + } + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanWordSelf( memory, MEMORY_SIZE ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_memory( memory, MEMORY_SIZE, 0x0 ); + if ( scanBulkSelf( memory, MEMORY_SIZE ) == MEMTEST_FAILURE ) + goto exit_tests; + + test++; + + fill_alt_memory( memory, MEMORY_SIZE, 0XAAAAAAAA, 0x55555555 ); + if ( memoryBulkCopy( memory, (memory + ((MEMORY_SIZE/2)/sizeof(uint32_t))), + MEMORY_SIZE/2 ) == MEMTEST_FAILURE ) + goto exit_tests; + + // return tests; + return MEMTEST_SUCCESS; + +exit_tests: + return MEMTEST_FAILURE; + +} +#endif /* defined(EXTENDED_MEMORY_TESTS) */ + +// +// Returns: 0=FAILURE, 1=SUCCESS +inline static int MemoryTest(void) +{ + // Test 32-bit write/read + volatile uint32 *memAddr; + uint32 memBase; + uint32 testValue; + int i; + int j; + int k; + + memBase = 0xa0000000; + for (i = 2; i < 24; i++) { + memAddr = (void *) (memBase + (1 << i)); + for (k = 0; k < 2; k++) { + /* walking one */ + testValue = 1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + if (*memAddr != testValue) + return 0; + + testValue <<= 1; + } + /* walking zero */ + testValue = ~1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + if (*memAddr != testValue) + return 0; + + testValue = (testValue << 1) | 1; + } + /* shift in zeroes */ + testValue = -1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + *(uint32*)memBase = 0; + if (*memAddr != testValue) + return 0; + + testValue <<= 1; + } + /* shift in ones */ + testValue = 1; + for (j = 0; j < 32; j++) { + *memAddr = testValue; + *(uint32*)memBase = 0; + if (*memAddr != testValue) + return 0; + + testValue = (testValue << 1) | 1; + } + } + } + return 1; +} + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S new file mode 100755 index 0000000..b3986ed --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_impl1_rom_boot.S @@ -0,0 +1,1818 @@ +#include "sbmips.h" +#include "bsp_config.h" + +#include "bcm_cpu.h" +#include "bcm_common.h" + +#include "bcm_hwdefs.h" +#include "boardparms.h" +#include "mipsmacros.h" + +#define DDR_TEST 1 +#define UBUS_SYNC_ENABLE 1 +#define LMB_SYNC_ENABLE 1 +#define MIPS_SYNC_ENABLE 1 +#define LMB_ENABLE 1 + +/* Memory mapping table for different size DRAMs (256Mb, 512Mb, 1Gb, 2Gb) */ + .globl dram_map_table_x8 +dram_map_table_x8: + // 128Mb 64B Interleaving (x8 Mode) 32MB + // This is just a place holder. This memory does not exist + _LONG_ 0x0F0E0D0C, 0x13121110, 0x17161514, 0x00000018 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x0000000B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000002, 0x00000055 // Bank CS_End Dramsize + + // 256Mb 64B Interleaving (x8 Mode) 64MB + _LONG_ 0x100F0E0D, 0x14131211, 0x18171615, 0x00000019 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x00000C0B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000004, 0x00000066 // Bank CS_End Dramsize + + // 512Mb 64B Interleaving (x8 Mode) 128MB + _LONG_ 0x100F0E0D, 0x14131211, 0x18171615, 0x00001A19 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x00000C0B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000008, 0x00000077 // Bank CS_End Dramsize + + // 1Gb 64B Interleaving (x8 Mode) 256MB + _LONG_ 0x11100F0E, 0x15141312, 0x19181716, 0x00001B1A // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0B0A0905, 0x00000D0C, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000010, 0x00000088 // Bank CS_End Dramsize + + .globl dram_map_table_x16 +dram_map_table_x16: + // 256Mb 64B Interleaving (x16 Mode) 32MB + _LONG_ 0x0F0E0D0C, 0x13121110, 0x17161514, 0x00000018 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x0000000B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000002, 0x00000055 // Bank CS_End Dramsize + + // 512Mb 64B Interleaving (x16 Mode) 64MB + _LONG_ 0x100F0E0D, 0x14131211, 0x18171615, 0x00000019 // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0A090805, 0x00000C0B, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00000706, 0x00000004, 0x00000066 // Bank CS_End Dramsize + + // 1Gb 64B Interleaving (x16 Mode) 128MB + _LONG_ 0x11100F0E, 0x15141312, 0x19181716, 0x0000001A // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0B0A0905, 0x00000D0C, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000008, 0x00000077 // Bank CS_End Dramsize + + // 2Gb 64B Interleaving (x16 Mode) 256MB + _LONG_ 0x11100F0E, 0x15141312, 0x19181716, 0x00001B1A // Row00_0 Row00_1 Row01_0 Row01_1 + _LONG_ 0x04000000, 0x0B0A0905, 0x00000D0C, 0x00000000 // Col00_0 Col00_1 Col01_0 Col01_1 + _LONG_ 0x00080706, 0x00000010, 0x00000088 // Bank CS_End Dramsize + + .globl dram_tRefi_table +dram_tRefi_table: /* Refresh Interval table for different Speed DRAMs (100-200, 300-333, 400) */ + _LONG_ 0x16, 0x49, 0x5D // 100-200 300-333 400 (MHz) + + .globl dram_tRFC_table +dram_tRFC_table: /* tRFC table for different size & Speed DRAMs (256Mb, 512Mb, 1Gb)/(200, 333, 400) */ +// 200 333 400 (MHz) + _LONG_ 0xF, 0x19, 0x1E // 256Mb + _LONG_ 0x15, 0x23, 0x2A // 512Mb + _LONG_ 0x1A, 0x2B, 0x33 // 1Gb + _LONG_ 0x28, 0x42, 0x4F // 2Gb + + .globl dram_timing_table +dram_timing_table: /* */ +// tRCD tCL tWR tWL tRP tRRD tRC tFAW tW2R tR2W tR2R tAL tRTP tW2W +// --------------------------------------------------------------------- + .byte 0x03,0x04,0x03,0x03,0x03,0x02,0x11,0x00,0x01,0x01,0x00,0x02,0x02,0x00,0x00,0x00 // 200MHz + .byte 0x05,0x05,0x05,0x04,0x05,0x04,0x13,0x00,0x02,0x01,0x00,0x04,0x03,0x00,0x00,0x00 // 300MHz + .byte 0x05,0x05,0x06,0x04,0x06,0x05,0x18,0x00,0x02,0x01,0x00,0x04,0x03,0x00,0x00,0x00 // 400MHz + + .globl dram_sync_table +dram_sync_table: /* Bit vector table for Ubus sync modes and Lmb sync modes */ +#if defined(_BCM96328_) + _LONG_ 0x8E10FFFF, 0x8A10FFFF, 0xEDC2FFFF // UBUS Sync , LMB Sync, Mips Sync +#elif defined(_BCM96362_) + _LONG_ 0xFFBFBFBF, 0x6341C101, 0xE7E5E5E5 // UBUS Sync , LMB Sync, Mips Sync +#elif defined(_BCM96816_) + _LONG_ 0xC03033B5, 0x80303095, 0xFF90FFFF // UBUS Sync , LMB Sync, Mips Sync +#endif + .globl dram_speed_table +dram_speed_table: /* Memory Speed Table for different clock strap values */ + /* 0=200Mhz 1=333MHz 2=400MHz */ +#if defined(_BCM96328_) + .byte 0 // 0x0 + .byte 0 // 0x1 + .byte 0 // 0x2 + .byte 0 // 0x3 + .byte 0 // 0x4 + .byte 0 // 0x5 + .byte 0 // 0x6 + .byte 0 // 0x7 + .byte 0 // 0x8 + .byte 0 // 0x9 + .byte 0 // 0xa + .byte 0 // 0xb + .byte 0 // 0xc + .byte 0 // 0xd + .byte 0 // 0xe + .byte 0 // 0xf + .byte 0 // 0x10 + .byte 0 // 0x11 + .byte 0 // 0x12 + .byte 0 // 0x13 + .byte 0 // 0x14 + .byte 0 // 0x15 + .byte 2 // 0x16 + .byte 2 // 0x17 + .byte 0 // 0x18 + .byte 0 // 0x19 + .byte 0 // 0x1a + .byte 0 // 0x1b + .byte 0 // 0x1c + .byte 0 // 0x1d + .byte 0 // 0x1e + .byte 1 // 0x1f +#elif defined(_BCM96362_) + .byte 1 // 0x0 + .byte 2 // 0x1 + .byte 0 // 0x2 + .byte 1 // 0x3 + .byte 0 // 0x4 + .byte 2 // 0x5 + .byte 2 // 0x6 + .byte 1 // 0x7 + .byte 1 // 0x8 + .byte 2 // 0x9 + .byte 0 // 0xa + .byte 1 // 0xb + .byte 0 // 0xc + .byte 2 // 0xd + .byte 2 // 0xe + .byte 1 // 0xf + .byte 1 // 0x10 + .byte 2 // 0x11 + .byte 0 // 0x12 + .byte 1 // 0x13 + .byte 0 // 0x14 + .byte 1 // 0x15 // 267MHz. Need to change tREFI if this is used. + .byte 2 // 0x16 + .byte 1 // 0x17 + .byte 1 // 0x18 + .byte 1 // 0x19 + .byte 0 // 0x1a + .byte 1 // 0x1b + .byte 0 // 0x1c + .byte 0 // 0x1d + .byte 2 // 0x1e + .byte 1 // 0x1f +#elif defined(_BCM96816_) + .byte 0 // 0x0 + .byte 1 // 0x1 + .byte 0 // 0x2 + .byte 0 // 0x3 + .byte 0 // 0x4 + .byte 1 // 0x5 + .byte 1 // 0x6 + .byte 1 // 0x7 + .byte 1 // 0x8 + .byte 1 // 0x9 + .byte 1 // 0xa + .byte 2 // 0xb + .byte 2 // 0xc + .byte 2 // 0xd + .byte 2 // 0xe + .byte 2 // 0xf + .byte 2 // 0x10 + .byte 2 // 0x11 + .byte 2 // 0x12 + .byte 2 // 0x13 + .byte 2 // 0x14 + .byte 0 // 0x15 + .byte 0 // 0x16 + .byte 1 // 0x17 + .byte 1 // 0x18 + .byte 1 // 0x19 + .byte 1 // 0x1a + .byte 1 // 0x1b + .byte 2 // 0x1c + .byte 2 // 0x1d + .byte 2 // 0x1e + .byte 2 // 0x1f +#endif + + .globl memc_ubus_ratio_table +memc_ubus_ratio_table: /* Memory Speed Table for different clock strap values */ +#if defined(_BCM96328_) +// 6328 Clock Speed Table + .byte 3 // 0x0 + .byte 3 // 0x1 + .byte 3 // 0x2 + .byte 3 // 0x3 + .byte 3 // 0x4 + .byte 3 // 0x5 + .byte 3 // 0x6 + .byte 3 // 0x7 + .byte 3 // 0x8 + .byte 3 // 0x9 + .byte 3 // 0xa + .byte 3 // 0xb + .byte 3 // 0xc + .byte 3 // 0xd + .byte 3 // 0xe + .byte 3 // 0xf + .byte 3 // 0x10 + .byte 3 // 0x11 + .byte 0xf // 0x12 + .byte 0xf // 0x13 + .byte 3 // 0x14 + .byte 9 // 0x15 + .byte 9 // 0x16 + .byte 9 // 0x17 + .byte 3 // 0x18 + .byte 3 // 0x19 + .byte 3 // 0x1a + .byte 3 // 0x1b + .byte 0xb // 0x1c + .byte 0xb // 0x1d + .byte 0xb // 0x1e + .byte 3 // 0x1f +#elif defined(_BCM96362_) +// 6362 Clock Speed Table + .byte 3 // 0x0 + .byte 3 // 0x1 + .byte 3 // 0x2 + .byte 3 // 0x3 + .byte 3 // 0x4 + .byte 3 // 0x5 + .byte 3 // 0x6 + .byte 3 // 0x7 + .byte 3 // 0x8 + .byte 3 // 0x9 + .byte 3 // 0xa + .byte 3 // 0xb + .byte 3 // 0xc + .byte 3 // 0xd + .byte 3 // 0xe + .byte 3 // 0xf + .byte 3 // 0x10 + .byte 3 // 0x11 + .byte 3 // 0x12 + .byte 3 // 0x13 + .byte 4 // 0x14 + .byte 4 // 0x15 + .byte 15 // 0x16 + .byte 3 // 0x17 + .byte 3 // 0x18 + .byte 3 // 0x19 + .byte 3 // 0x1a + .byte 3 // 0x1b + .byte 3 // 0x1c + .byte 3 // 0x1d + .byte 3 // 0x1e + .byte 3 // 0x1f +#elif defined(_BCM96816_) +// 6816 Clock Speed Table + .byte 3 // 0x0 + .byte 9 // 0x1 + .byte 3 // 0x2 + .byte 4 // 0x3 + .byte 3 // 0x4 + .byte 3 // 0x5 + .byte 9 // 0x6 + .byte 3 // 0x7 + .byte 3 // 0x8 + .byte 3 // 0x9 + .byte 2 // 0xa + .byte 4 // 0xb + .byte 2 // 0xc + .byte 3 // 0xd + .byte 4 // 0xe + .byte 9 // 0xf + .byte 1 // 0x10 + .byte 1 // 0x11 + .byte 1 // 0x12 + .byte 1 // 0x13 + .byte 3 // 0x14 + .byte 3 // 0x15 + .byte 4 // 0x16 + .byte 9 // 0x17 + .byte 6 // 0x18 + .byte 2 // 0x19 + .byte 6 // 0x1a + .byte 2 // 0x1b + .byte 4 // 0x1c + .byte 3 // 0x1d + .byte 4 // 0x1e + .byte 3 // 0x1f +#endif + +#if defined(_BCM96816_) + .globl periph_fix_table +periph_fix_table: // Periph Clock fix vector for different clock strap values + _LONG_ 0xAA30A047 +#endif + +#define SETLEDS1(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + bal board_setleds; \ + nop + +/* ********************************************************************* + * BOARD_EARLYINIT() + * + * Initialize board registers. This is the earliest + * time the BSP gets control. This routine cannot assume that + * memory is operational, and therefore all code in this routine + * must run from registers only. The $ra register must not + * be modified, as it contains the return address. + * + * This routine will be called from uncached space, before + * the caches are initialized. If you want to make + * subroutine calls from here, you must use the CALLKSEG1 macro. + * + * Among other things, this is where the GPIO registers get + * programmed to make on-board LEDs function, or other startup + * that has to be done before anything will work. + * + * Input parameters: + * a0 - Flash base address (address of MIPS reset) + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(board_earlyinit) + + .set noreorder + + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, 3f # if we are running on thread 1, skip init + nop + + /**-------------------------------------------------------------**/ + /** platform specific code **/ + /**-------------------------------------------------------------**/ + +#if defined(_BCM96816_) + /**----- Offset UBUS Clock 180 degrees -------------------------**/ + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + move s0,ra + LOADREL(t2, periph_fix_table) + lw t2, 0(t2) + srl t2, t1 + andi t2, 1 + move ra,s0 + + beq t2, zero, 2f + nop + + li t0, DDR_BASE + li t1, 0x00070000 // send new phase value to PLL every 8 cycles + sw t1, DDR_CTL_PI_UBUS_CTL(t0) + ori t1, 0x4080 // shift 128 steps in the positive direction to be 180 degree's offset VCO 1.6GHz + sw t1, DDR_CTL_PI_UBUS_CTL(t0) + li t1, 0x00000001 + sw t1, DDR_CTL_PI_GCF(t0) + + li t1, 0x10000 // delay +1: + bnez t1, 1b + addi t1, -1 + +2: + /**----- Set 1.2V and 2.5V Voltage regulators ------------------**/ + li t1, GPIO_BASE + lw t2, GPIO_SWREG_CONFIG(t1) + and t2, ~GPIO_SW_VREG_SEL_MASK + or t2, (0x0 << GPIO_SW_VREG_SEL_SHIFT) + and t2, ~GPIO_LIN_VREG_ADJ_MASK + or t2, (0x0 << GPIO_LIN_VREG_ADJ_SHIFT) + sw t2, GPIO_SWREG_CONFIG(t1) + + li t1, 0x10000 +1: + bnez t1, 1b + addi t1, -1 +#endif + +#if defined (_BCM96328_) || defined (_BCM96362_) + /* slow down mips clk (div 4) to unlock memory */ + mfc0 t1, C0_BCM_CONFIG, 5 + or t2, t1, 0x40000000 + mtc0 t2, C0_BCM_CONFIG, 5 + nop + + mtc0 t1, C0_BCM_CONFIG, 5 + nop +#endif + +#if defined (_BCM96362_) + /* Adjust VREG frequency up by 50% to improve DSL performance */ + li t2, MISC_BASE + + /* First set ramp control */ + lw t1, MISC_VREG_CONTROL0(t2) + or t1, (0x2 << MISC_VREG_CONTROL0_VREG_RAMP1P8_SHIFT) | (0x2 << MISC_VREG_CONTROL0_VREG_RAMP1P2_SHIFT) + sw t1, MISC_VREG_CONTROL0(t2) + + /* wait 10ms for the setting to take effect */ + li t8, -2000000 + mtc0 t8, C0_COUNT +1: + bltz t8, 1b + mfc0 t8, C0_COUNT + + and t1, ~((0x7 << MISC_VREG_CONTROL0_VREG_RAMP1P8_SHIFT) | (0x7 << MISC_VREG_CONTROL0_VREG_RAMP1P2_SHIFT)) + or t1, (0x3 << MISC_VREG_CONTROL0_VREG_ADJ_SHIFT) + sw t1, MISC_VREG_CONTROL0(t2) + + /* Increase 2.5V regulator to provide increased range for 1.8V */ + lw t1, MISC_VREG_CONTROL1(t2) + and t1, ~MISC_VREG_CONTROL1_VREG_ISEL2P5_MASK + or t1, (MISC_VREG_LDO_2P61 << MISC_VREG_CONTROL1_VREG_ISEL2P5_SHIFT) + sw t1, MISC_VREG_CONTROL1(t2) +#endif + +#if 0 + /* wait for a while to allow catch by jtag debugger */ + li t8, -(200000000*3) /* we will count up to 0 to delay a couple of seconds */ + /* and give the emulator a chance to catch us */ + mtc0 t8, C0_COUNT +catchloop: + bltz t8, catchloop + mfc0 t8, C0_COUNT +#endif + + /**----- Enable I Cache -----------------------------------------**/ + mfc0 t1, C0_BCM_CONFIG + or t1, (CP0_BCM_CFG_ICSHEN | CP0_BCM_CFG_DCSHEN) + mtc0 t1, C0_BCM_CONFIG # Enable I Cache + + // In the begining MIPS core registers are mapped to 0xbfax_xxxx + li t1, 0x1FA0000C # Set up CBR to 1FAx_xxxx + mtc0 t1, C0_BCM_CONFIG, 6 + + li t1, MIPS_BASE_BOOT + lw t2, MIPS_LMB_CR(t1) + or t2, 0xC0000000 # enable ffxx_xxxx space + sw t2, MIPS_LMB_CR(t1) + li t2, 0xFFF80001 # SBR FFF8_xxxx and enable + sw t2, MIPS_SBR(t1) + + // Now map MIPS core registers to 0xFF4x_xxxx space + li t1, 0xFF40000C # CBR FF4x_xxxx (and reserved bits 0xc). + mtc0 t1, C0_BCM_CONFIG, 6 + +#if defined(_BCM96816_) + /**----- Initialize EBI -----------------------------------------**/ + li t1, MPI_BASE + li t2, EBI_SIZE_32M + or t2, a0 + sw t2, CS0BASE(t1) # CS[0] Base + li t2, THREEWT|EBI_WORD_WIDE|EBI_ENABLE + sw t2, CS0CNTL(t1) # CS[0] Control +#endif + + /**----- Initialize Serial --------------------------------------**/ + li t3, ((FPERIPH / 115200) / 16) + /* + # Baudword = (FPeriph)/Baud/32-1. We have to perform rounding + # and subtraction. Above we divided by 16 (instead of 32). If + # bit0 is set, we round up. However, we then subtract 1, so final + # result should be t3/2. If bit0 is 0, then we truncate and subtract + # 1, t3=t3/2-1. + */ + andi t0, t3, 0x1 + bne t0,zero,1f # do shift only (in delay slot) + # and jump to apply + srl t3,1 # do divide by 2 + addiu t3, -1 # subtract 1 +1: + + // t3 contains the UART BAUDWORD + li t0, UART_BASE + sw t3, UART0BAUD(t0) # Store BaudRate + li t1, BITS8SYM|ONESTOP + sb t1, UART0CONFIG(t0) # 8 Bits/1 Stop + li t1, TXEN|RXEN|BRGEN + sb t1, UART0CONTROL(t0) # Enable, No Parity + move t1, zero + sh t1, UART0INTMASK(t0) + + .set reorder +3: + j ra +END(board_earlyinit) + +/* ********************************************************************* + * BOARD_DRAMINFO + * + * Return the address of the DRAM information table + * + * Input parameters: + * nothing + * + * Return value: + * v0 - DRAM info table, return 0 to use default table + ********************************************************************* */ +LEAF(board_draminfo) + j ra +END(board_draminfo) + +/* ********************************************************************* + * BOARD_DRAMINIT + * + * This routine should activate memory. + * + * Input parameters: + * None + * + * Return value: + * None + * + * Registers used: + * can use all registers. + ********************************************************************* */ +LEAF(board_draminit) + .set noreorder + + move s0,ra + +/***** Load DDR Base *************************************/ + li t0, DDR_BASE + +/***** Disable Auto refresh ******************************/ + li t1, 0x10000 + sw t1, DDR_CTL_CLKS(t0) + SETLEDS1('-','-','-', '-') + SETLEDS1('P','H','Y','S') + + li t1, 0x10 // Loop count value + li t3, 1 + +zq_loop: + sub t1, t3 // Decrement count by 1 + beq t1, zero, zq_error + nop + + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + li t4, (1 << 26) + sw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Start the calibration + + li t2, 0x100 // Timeout value + +wait_zq1: + beq t2, zero, zq_timeout + nop + + lw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Read the calibration result + move t5, t4 // Save calibration result1 + and t4, (1 << 28) + beq t4, zero, wait_zq1 + sub t2, t3 + + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + li t4, (1 << 26) + sw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Start the calibration + + li t2, 0x100 // Timeout value + +wait_zq2: + beq t2, zero, zq_timeout + nop + + lw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Read the calibration result + move t6, t4 // Save calibration result1 + and t4, (1 << 28) + beq t4, zero, wait_zq2 + sub t2, t3 + + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + li t4, (1 << 26) + sw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Start the calibration + + li t2, 0x100 // Timeout value + +wait_zq3: + beq t2, zero, zq_timeout + nop + + lw t4, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Read the calibration result + move t7, t4 // Save calibration result1 + and t4, (1 << 28) + beq t4, zero, wait_zq3 + sub t2, t3 + + bne t5, t6, zq_loop + nop + bne t5, t7, zq_loop + nop + bne t6, t7, zq_loop + nop + + b zq_done; + nop + +zq_error: + SETLEDS1('Z','Q','E','R') + b zq_done + nop + +zq_timeout: + SETLEDS1('Z','Q','T','O') + nop +zq_done: + sw zero, PHY_CONTROL_REGS_ZQ_PVT_COMP_CTL(t0) // Reset the calibration engine + + SETLEDS1('Z','Q','D','N') + nop + +/****** Set control pad strength to half ********/ + lw t2, PHY_CONTROL_REGS_DRIVE_PAD_CTL(t0) + or t2, 0x4 + sw t2, PHY_CONTROL_REGS_DRIVE_PAD_CTL(t0) + +#if defined(_BCM96816_) +/****** Disable byte lanes 2 and 3 ********/ + li t1, 0x800fffff + sw t1, PHY_BYTE_LANE_2_IDLE_PAD_CONTROL(t0) + sw t1, PHY_BYTE_LANE_3_IDLE_PAD_CONTROL(t0) +#endif + +/****** Disable byte lane 1 clock ********/ + li t1, 1 + sw t1, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + +ddr_x8: + +/****** Change the slew and receiver power to full strength in the byte lanes ********/ + li t1, 0xFFFFFFFC + lw t2, PHY_BYTE_LANE_0_DRIVE_PAD_CTL(t0) + and t2, t2, t1 + sw t2, PHY_BYTE_LANE_0_DRIVE_PAD_CTL(t0) + lw t2, PHY_BYTE_LANE_1_DRIVE_PAD_CTL(t0) + and t2, t2, t1 + sw t2, PHY_BYTE_LANE_1_DRIVE_PAD_CTL(t0) + +/****** Hardware calibrate VDL *******/ + li t1, 3 + sw t1, PHY_BYTE_LANE_0_VDL_CALIBRATE(t0) + sw t1, PHY_BYTE_LANE_1_VDL_CALIBRATE(t0) + + li t1, 0x1000 +1: + bnez t1, 1b + addi t1, -1 + +/****** Check strap value to figure out 400MHz or 200Mhz DDR ******/ + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + LOADREL(t2, dram_speed_table) + + add t2, t1 + lb t1, 0x00(t2) + beq t1, zero, ddr_clk_200 + li t2, 1 + beq t1, t2, ddr_clk_300 + nop + +/****** Software override rd_en VDL and ADDRESS VDL ********/ +ddr_clk_450: +ddr_clk_400: + li a1, 2 // Set speed to 400MHz (2) + b 1f + nop +ddr_clk_300: + li a1, 1 // Set speed to 300MHz (1) + +/* At higher frequencies set Read_en VDL value to calibrated VDL value + 10 */ +1: li t2, 0x10000 + lw t1, PHY_BYTE_LANE_0_VDL_STATUS(t0) + srl t1, 8 + addi t1, 0xA + or t1, t1, t2 + sw t1, PHY_BYTE_LANE_0_VDL_OVERRIDE_2(t0) + lw t1, PHY_BYTE_LANE_1_VDL_STATUS(t0) + srl t1, 8 + addi t1, 0xA + or t1, t1, t2 + sw t1, PHY_BYTE_LANE_1_VDL_OVERRIDE_2(t0) + b vdl_override_cont + nop + +ddr_clk_200: + li a1, 0 // Set speed to 200MHz (0) + li t3, 0x1f // Set maximum VDL step size for 200MHz + b 1f + nop + +vdl_override_cont: + lw t2, PHY_BYTE_LANE_0_VDL_STATUS(t0) + andi t3, t2, 0x1f00 + srl t3, 8 + addi t3, t3, 0x4 // Add Stepsize 4 + +1: li t1, 0x110000 // Enable & Force Override + or t1, t3 // Fine rise and fine fall are set to 0 + + sw t1, PHY_CONTROL_REGS_STATIC_VDL_OVERRIDE(t0) + li t1, 0x0c + sw t1, DDR_CTL_DCMD(t0) // Set VDL + + SETLEDS1('P','H','Y','E') + +/* Program MC Timing Registers + + Read each timing parameter based on the speed and then create the + timing registers and program them. +*/ + LOADREL(t2, dram_timing_table) + + li t1, 0x10 // size of dram_timing_table element + mult t1, a1 + mflo t1 // dram_timing_table offset + add t2, t1 + + move t3, zero + lb t1, 0x00(t2) // tRCD + andi t1, 0xf + move t3, t1 + lb t1, 0x01(t2) // tCL + andi t1, 0xf + + move t4, t1 + and t4, 0x7 // Make sure that only 3 bits are written to DRAM's tCL field + sll t4, 20 + sw t4, DDR_CTL_DMODE_0 (t0) // Write tCL to the MRS register holder + + sll t1, 4 + or t3, t1 + lb t1, 0x02(t2) // tWR + andi t1, 0xf + + // Here we create the MRS register values + move t4, t1 + li t5, 1 + subu t4, t5 // tWR written to DRAM is 1 less than real tWR value + andi t4, 0x7 + sll t4, 25 + li t5, 0x01030000 // Sequential burst mode, burst of 8, reset DLL + or t4, t5 + lw t5, DDR_CTL_DMODE_0 (t0) + or t5, t4 + sw t5, DDR_CTL_DMODE_0 (t0) // Add tWR to the MRS register holder + + sll t1, 9 + or t3, t1 + lb t1, 0x03(t2) // tWL + andi t1, 0xf + sll t1, 12 + or t3, t1 + lb t1, 0x04(t2) // tRP + andi t1, 0xf + sll t1, 16 + or t3, t1 + lb t1, 0x05(t2) // tRRD + andi t1, 0xf + sll t1, 20 + or t3, t1 + lb t1, 0x06(t2) // tRC + andi t1, 0x1f + sll t1, 24 // tRCw + or t3, t1 + sw t3, DDR_CTL_TIM1_0(t0) // Program TIM1_0 register + + move t3, zero + lb t1, 0x06(t2) // tRC + andi t1, 0x1f + or t3, t1 // tRCr + lb t1, 0x07(t2) // tFAW + andi t1, 0x3f + sll t1, 8 + or t3, t1 + li t1, 0xff // tRFC = 0xff (Set to max value first. + sll t1, 16 // We'll fix it after we determine dram size) + or t3, t1 + + // We skip tFIFO since it needs to be 0 + + lb t1, 0x08(t2) // tW2R + andi t1, 0x3 + sll t1, 26 + or t3, t1 + lb t1, 0x09(t2) // tR2W + andi t1, 0x3 + sll t1, 28 + or t3, t1 + lb t1, 0x0a(t2) // tR2R + andi t1, 0x1 + sll t1, 30 + or t3, t1 + sw t3, DDR_CTL_TIM1_1(t0) // Program TIM1_1 register + + move t3, zero + lb t1, 0x0b(t2) // tAL + andi t1, 0xf + + // Here we create the EMRS register values + move t4, t1 + andi t4, 0x7 + sll t4, 3 + li t5, 0x384 // RTT=75ohm, OCD Enter + or t4, t5 + lw t5, DDR_CTL_DMODE_0 (t0) + or t5, t4 + sw t5, DDR_CTL_DMODE_0 (t0) // Store required values in EMRS holding register + + or t3, t1 + lb t1, 0x0c(t2) // tRTP + andi t1, 0x7 + sll t1, 4 + or t3, t1 + lb t1, 0x0d(t2) // tW2W + andi t1, 0x3 + sll t1, 8 + or t3, t1 + sw t3, DDR_CTL_TIM2(t0) // Program TIM2 register + +/* +// (tRRD is incremented by 1 due to tFAW bug for >=1Gb devices) + li t1, 0x18564c55 // tRCD=5,tWR=6,tCL=5,tWL=4,tRP=6,tRRD=5,tRCw=0x18 +// li t1, 0x13554a55 // tRCD=5,tWR=5,tCL=5,tWL=4,tRP=5,tRRD=5,tRCw=0x13 + sw t1, DDR_CTL_TIM1_0(t0) + li t1, 0x18330018 // tR2W=1,tR2R=0,tW2R=2,tFIFO=0,tRFC=0x33,tFAW=0,tRCr=0x18 +// li t1, 0x182b0013 // tR2W=1,tR2R=0,tW2R=2,tFIFO=0,tRFC=0x2b,tFAW=0,tRCr=0x13 + sw t1, DDR_CTL_TIM1_1(t0) + li t1, 0x00000034 // tAL=4 (tRCD-1), tRTP=3, tW2W=0 + sw t1, DDR_CTL_TIM2(t0) +*/ + +// Set x16 mode and Page policy + li t1, 0x100 + sw t1, DDR_CTL_DMODE_1(t0) + +// Enable ODT for writes + li t1, 0x104 + sw t1, DDR_CTL_ODT(t0) + +/***** Turn on CKE ***************/ + li t1, 0x35 + sw t1, DDR_CTL_DCMD(t0) + + li t1, 0x200 +2: + bnez t1, 2b + addi t1, -1 + +/***** Set arbitor for Burst Round Robin Mode ***/ + lw t1, DDR_CTL_ARB(t0) + or t1, 4 << 16 + sw t1, DDR_CTL_ARB(t0) + +/***** Issue Precharge All Banks Command ***/ + li t1, 0x32 + sw t1, DDR_CTL_DCMD(t0) + +/***** Issue EMRS2 Command ***/ + li t1, 0x0 + lw t2, DDR_CTL_DMODE_0 (t0) // Load previous value to t2 to preserve it + nop + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x38 + sw t1, DDR_CTL_DCMD(t0) + +/***** Issue EMRS3 Command***/ + li t1, 0x0 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x39 + sw t1, DDR_CTL_DCMD(t0) + +// Enable DLL by issuing EMRS Command +// li t1, 0x0 +// sw t1, DDR_CTL_DMODE_0 (t0) + sw t2, DDR_CTL_DMODE_0 (t0) // Use the saved value back to DMODE_0 register + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) + +/* +// Issue MRS Command tCL=5 tWL=4 + li t1, 0x0b530000 +// li t1, 0x07530000 // tCL=5 tWR=5, Reset DLL, Sequential Mode, Burst Length = 8 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) +*/ +// Issue MRS Command. Set Reset DLL bit + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) + +// Issue Precharge All Banks Command + li t1, 0x32 + sw t1, DDR_CTL_DCMD(t0) + +// Issue Autorefresh Command + li t1, 0x33 + sw t1, DDR_CTL_DCMD(t0) + li t1, 0x33 + sw t1, DDR_CTL_DCMD(t0) + + li t1, 0x200 +3: + bnez t1, 3b + addi t1, -1 + +/* +// Clear DLL Reset by Issuing MRS Command, tCL=5 tWL=4 + li t1, 0x0a530000 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) +*/ + +// Issue MRS Command w/ DLL Reset bit set to 0 + lw t1, DDR_CTL_DMODE_0 (t0) + li t2, 0xFEFFFFFF // Reset DLL reset bit + and t1, t2 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x31 + sw t1, DDR_CTL_DCMD(t0) + +/* +// Issue EMRS Command (Enter OCD Calibration) + li t1, 0x380 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) +*/ + +// Issue EMRS Command (Enter OCD Calibration) 75 Ohm, Full strength Drive, tAL=tRCD-1 + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) + +// Issue EMRS Command (Exit OCD Calibration) + lw t1, DDR_CTL_DMODE_0 (t0) + li t2, 0xFC7F // Reset OCD field for exit mode + and t1, t2 + sw t1, DDR_CTL_DMODE_0 (t0) + li t1, 0x30 + sw t1, DDR_CTL_DCMD(t0) + +// Check x8 or x16 DDR + li t1, 0x12345678 + li t3, 0xA0000000 + sw zero, 0(t3) + sw t1, 0(t3) + lw t2, 0(t3) + bne t1, t2, 3f // Failed + nop +// Do the test twice. Just in case random values match... + li t1, 0x87654321 + sw t1, 0(t3) + lw t2, 0(t3) + beq t1, t2, 1f // Clock lines are enabled as needed + nop + +3: +// Memory test failed. Need to re-enable byte lane 1 clock + sw zero, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + li t1, 0x200 +2: + bnez t1, 2b // Delay after enabling clocks + addi t1, -1 + b ddr_x8 + nop + +1: +// Find memory size. a3 keeps the size: 0=256Mb, 1=512Mb, 2=1Gb, 3=2Gb +// Start from 2Gb device + LOADREL(t7, dram_map_table_x8) + lw t1, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + beqz t1, 1f + nop + LOADREL(t7, dram_map_table_x16) + +1: + li a3, 4 +ddr_size: + addi a3, -1 + + li t1, 0x2c // size of dram_map_table element + mult t1, a3 + mflo t2 // dram_map_table offset + add t2, t7 + + lw t1, 0x00(t2) // Row00_0 + sw t1, DDR_CTL_ROW00_0(t0) + + lw t1, 0x04(t2) // Row00_1 + sw t1, DDR_CTL_ROW00_1(t0) + + lw t1, 0x08(t2) // Row01_0 + sw t1, DDR_CTL_ROW01_0(t0) + + lw t1, 0x0C(t2) // Row01_1 + sw t1, DDR_CTL_ROW01_1(t0) + + lw t1, 0x10(t2) // Col00_0 + sw t1, DDR_CTL_COL00_0(t0) + + lw t1, 0x14(t2) // Col00_1 + sw t1, DDR_CTL_COL00_1(t0) + + lw t1, 0x18(t2) // Col01_0 + sw t1, DDR_CTL_COL01_0(t0) + + lw t1, 0x1C(t2) // Col01_1 + sw t1, DDR_CTL_COL01_1(t0) + + lw t1, 0x20(t2) // Bank + sw t1, DDR_CTL_BNK10(t0) + + li t1, 0x0 // CS_Start + sw t1, DDR_CTL_CSST(t0) + + lw t1, 0x24(t2) // CS_End + sw t1, DDR_CTL_CSEND(t0) + + li t1, 0x0 // CS Interleaving CFG + sw t1, DDR_CTL_CNFG(t0) + + lw t3, 0x28(t2) // Dram Size + lw t1, DDR_CTL_GCFG(t0) // GCFG + li t2, 0xFFFFFF00 + and t1, t1, t2 // Mask out Dram Size Fields + or t1, t3, t1 // insert new DRAM Size value + sw t1, DDR_CTL_GCFG(t0) + beqz a3, ddr_speed + nop + +// Check for memory aliasing +// This assumes that the bank interleaving is below address bits 8. + li t1, 8 + li t2, 24 + add t2, a3 // Scan up to maximum memory size + li t3, 0xA0000000 + +check_alias: + li t4, 1 + sll t4, t1 + add t4, t3 + + sw zero, 0(t3) + li t5, -1 + sw t5, 0(t4) + lw t6, 0(t3) + + beq t5, t6, ddr_size + nop + + bne t1, t2, check_alias + addi t1, 1 + +ddr_speed: + li t1, 3 + lw t2, PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE(t0) + beqz t2, 1f + nop + li t1, 2 +1: + blt a3, t1, tRefi_update // If smaller than 1Gb device, keep tRRD same + nop + + lw t1, DDR_CTL_TIM1_0(t0) // Load DDR_CTL_TIM1_0 register + move t2, t1 + srl t2, 20 + andi t2, 0xf + addi t2, 1 // Increment ttRRD by one (software work around for a bug) + sll t2, 20 + li t3, 0xFF0FFFFF + and t1, t3 // Clear tRRD field + or t1, t2 // Insert the new tRRD value + sw t1, DDR_CTL_TIM1_0(t0) // Store DDR_CTL_TIM1_0 register + nop + +tRefi_update: + LOADREL(t2, dram_tRefi_table) + + li t1, 0x4 // size of dram_tRefi_table entry + mult t1, a1 + mflo t1 // dram_tRefi_table offset + add t2, t1 + + lw t1, 0x0(t2) // tRefi + sll t1, 8 + sw t1, DDR_CTL_CLKS(t0) + + LOADREL(t2, dram_tRFC_table) + + li t1, 0x4 // size of dram_tRFC_table entry + mult t1, a1 + mflo t1 // dram_tRefi_table offset + add t2, t1 // Calculate address in the row + + li t1, 0xc // size of dram_tRFC_table row + mult t1, a3 + mflo t1 // dram_tRefi_table offset + add t2, t1 // Calculate address in the column + + lw t3, 0x0(t2) // Load tRFC value + andi t3, 0xFF // Mask tRFC to 8-bits + sll t3, 16 // Move it to bit location [23:16] + + lw t1, DDR_CTL_TIM1_1(t0) // Load DDR_CTL_TIM1_1 register + li t2, 0xFF00FFFF + and t1, t1, t2 // Mask out tRFC Field + or t1, t3, t1 // insert new tRFC value + sw t1, DDR_CTL_TIM1_1(t0) // Write to TIM1_1 register + + SETLEDS1('D','I','N','T') + +/***** UBUS align to MEMC *****/ +align_memc: + +/*** check MEMC clk ratio to set sampling freq *****/ + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + +#if defined(_BCM96816_) + LOADREL(t2, periph_fix_table) + lw t2, 0(t2) + srl t2, t1 + andi t2, 1 + bne t2, zero, 2f +#endif + + LOADREL(t2, memc_ubus_ratio_table) + + add t2, t1 + lb t1, 0x00(t2) + sll t4,t1,28 // Update Sampling Period Field + +pi_ubus: + li t2, 4048 + li t3, 1 + + sw zero, DDR_CTL_PI_GCF(t0) + li t1, 0x00001c0b // send feedback command every 11 cycles + or t1, t1, t4 + sw t1, DDR_CTL_PI_UBUS_SMPL(t0) + ori t1, 0x80 // trigger stoke signal to latch in new counter value + sw t1, DDR_CTL_PI_UBUS_SMPL(t0) + li t1, 0x00040000 // send new phase value to PLL every 5 cycles + sw t1, DDR_CTL_PI_UBUS_CTL(t0) + li t1, 0x00000001 // enable enable counter that change PLL phase + sw t1, DDR_CTL_PI_GCF(t0) + nop + +#if defined (_BCM96328_) || defined(_BCM96362_) +// Enable PHY MIPS PI + li t1, 0x00130000 + sw t1, DDR_CTL_PI_DSL_MIPS_CTL(t0) + nop +#endif + +1: + lw t4, DDR_CTL_PI_UBUS_SMPL(t0) // Read a sample value. + srl t4, 16 // The sample is in the upper 16 bits. + + andi t4, t4, 0x22 // Look at the 2 outermost bits; if the LSB is 0 and the MSB is 1, + beq t4, 0x20, 2f // then there is an edge somewhere in the sample. + nop + lw t5, DDR_CTL_PI_UBUS_CTL(t0) + and t5, 0xffff0000 + or t5, t3 + or t5, (1<<14) // move phase in positive direction + sw t5, DDR_CTL_PI_UBUS_CTL(t0) + nop + lw t5, DDR_CTL_PI_UBUS_CTL(t0) // Delay before reading another sample. + add t3, 1 + bne t2, t3, 1b + nop + + SETLEDS1('U','A','S','Y') + SETLEDS1('L','A','S','Y') + SETLEDS1('M','A','S','Y') + b run_async // failed to set sync mode + nop + +2: +/*** check MIPS clk ratio *****/ + li t4, 0xff410010 + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + b _mips_align_2_ubus // none of the above means it is either 1/1 or 2/1 + nop + + +_mips_align_2_ubus: + +/***** MIPS align to UBUS *****/ + li t1, 0xff410000 + + li t2, 0x00040000 // update PLL phase value every 5 MC cycles + sw t2, DDR_CTL_PI_MIPS_CTL(t0) + + li t2, 0xc0001c03 // force update on mclk_period + sw t2, 0x40(t1) + li t2, 0x80001c83 + sw t2, 0x40(t1) + + lw t2, DDR_CTL_PI_MIPS_CTL(t0) // add delay + li t3, 1 + +1: lw t4, 0x40(t1) // Read a sample value. + srl t4, 16 // The sample is in the upper 16 bits. + + andi t4, t4, 0x22 // Look at the 2 outermost bits, if the LSB is 0 and the MSB is 1, + beq t4, 0x20, 2f // then there is an edge somewhere in the sample. + nop + lw t5, DDR_CTL_PI_MIPS_CTL(t0) + and t5, 0xffff0000 + or t5, t3 + or t5, (1<<14) // move phase in positive direction + sw t5, DDR_CTL_PI_MIPS_CTL(t0) + nop + lw t5, DDR_CTL_PI_MIPS_CTL(t0) // Delay before reading another sample. + add t3, 1 + bne t2, t3, 1b + nop + + SETLEDS1('U','A','S','Y') + SETLEDS1('L','A','S','Y') + SETLEDS1('M','A','S','Y') + b run_async // failed to set sync mode + nop +2: + // Success + lw t2, DDR_CTL_PI_MIPS_CTL(t0) // Turn on auto-PI mode. + or t2, (1 << 20) // PI_UBUS_CTL_Hw_Cntr_En = 1 + sw t2, DDR_CTL_PI_MIPS_CTL(t0) + + /**----- Enable DDR/UBUS and DDR/LMB sync mode ------------------**/ + /*** only MIPS in sync mode for these strap options */ + + li t2, MISC_BASE + lw t1, MISC_STRAP_BUS(t2) + + srl t1, MISC_STRAP_BUS_MIPS_PLL_FVCO_SHIFT + andi t1, 0x1f // Mask out strap bits + + li t3, 0 // Used to keep MC/MIPS and MC/UBUS sync/async mode + + LOADREL(t2, dram_sync_table) + + lw t4, 0x0(t2) // Ubus Sync vector + lw t5, 0x4(t2) // Lmb Sync vector + +#if defined (_96816_) + move t4, t6 +#endif + lw t6, 0x8(t2) // Mips Sync vector + + srl t4, t1 // Get the ubus sync flag + srl t5, t1 // Get the lmb sync flag + srl t6, t1 // Get the mips sync flag + andi t4, 1 // Mask out other bits + andi t5, 1 // Mask out other bits + andi t6, 1 // Mask out other bits + + li t2, 1 + bne t4, t2, ubus_async // 1f below. If ubus is not sync, lmb can't be in sync + nop // Go to ubus_async (1f) + + // Ubus Sync Mode. Turn on Ubus Clock tracking + lw t2, DDR_CTL_PI_UBUS_CTL(t0) // Turn on auto-PI mode. + or t2, (1 << 20) // PI_UBUS_CTL_Hw_Cntr_En = 1 + sw t2, DDR_CTL_PI_UBUS_CTL(t0) + + // Is LMB Sync as well? + li t2, 1 + beq t5, t2, memc_all_sync // If both ubus and lmb are sync, go to memc_all_sync + nop + +memc_ubus_sync: +#if UBUS_SYNC_ENABLE +// set MC/UBUS to SYNC + li t3, 0x4 + SETLEDS1('L','A','S','Y') + SETLEDS1('U','S','Y','N') +#else +// set MC/UBUS to ASYNC + li t3, 0xc + SETLEDS1('L','A','S','Y') + SETLEDS1('U','A','S','Y') +#endif + + b update_sync_mode + nop + +memc_all_sync: +#if LMB_SYNC_ENABLE +// set MC/MIPS to SYNC + nop + SETLEDS1('L','S','Y','N') +#else +// set MC/MIPS to ASYNC + li t1, 0x4 + or t3, t1 + SETLEDS1('L','A','S','Y') +#endif +#if UBUS_SYNC_ENABLE +// set MC/UBUS to SYNC + nop + SETLEDS1('U','S','Y','N') +#else +// set MC/UBUS to ASYNC + li t1, 0x8 + or t3, t1 + SETLEDS1('U','A','S','Y') +#endif + +update_sync_mode: + li t1, MISC_BASE + sw t3, MISC_MEMC_CONTROL(t1) + b 2f + nop +1: +ubus_async: + SETLEDS1('L','A','S','Y') + SETLEDS1('U','A','S','Y') + +2: + // Can Mips run in sync mode? If not, skip all below + beq t6, zero, run_async + nop + +#if MIPS_SYNC_ENABLE + /**----- Clear MIPS Async mode bit ------------------------------**/ + mfc0 t1, C0_BCM_CONFIG, 5 + and t1, ~(0x1 << 28) + mtc0 t1, C0_BCM_CONFIG, 5 + + SETLEDS1('M','S','Y','N') +#else + SETLEDS1('M','A','S','Y') +#endif + +3: + /**----- Enable RAC and LMB -------------------------------------**/ + li t0, MIPS_BASE + lw t2, MIPS_LMB_CR(t0) +#if LMB_ENABLE + or t2, LMB_EN // Enable LMB + SETLEDS1('L','M','B','E') +#else + SETLEDS1('L','M','B','D') +#endif + sw t2, MIPS_LMB_CR(t0) + + li t2, 0xFFF << RAC_UPB_SHFT // Enable prefetch for RAM address range up to 256MB + sw t2, MIPS_RAC_ARR(t0) + + lw t2, MIPS_RAC_CR0(t0) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR0(t0) + + lw t2, MIPS_RAC_CR1(t0) + or t2, (RAC_C_INV | RAC_I | RAC_PF_I) + sw t2, MIPS_RAC_CR1(t0) + +run_async: + /**----- Enable branch prediction and non-blocking data cache ---**/ + mfc0 t1, C0_BCM_CONFIG + and t1, ~CP0_BCM_CFG_BTHD + or t1, CP0_BCM_CFG_NBK + or t1, CP0_BCM_CFG_CLF + mtc0 t1, C0_BCM_CONFIG + +#if DDR_TEST +####################################### +# Run test on DRAM using Test Engine # +####################################### +#define BACKGND_MODE_DATA 0x0 +#define BACKGND_MODE_LFSR 0x400 +#define BACKGND_MODE_PRBS 0x800 +#define BACKGND_MODE_NOT_PRBS 0xc00 +#define BACKGND_MODE_PAT 0x1000 +#define BACKGND_MODE_NOT_PAT 0x1400 + +#define VICT_MODE_PRBS 0 +#define VICT_MODE_NOT_PRBS 0x100 +#define VICT_MODE_PAT 0x200 +#define VICT_MODE_NOT_PAT 0x300 + +#define VICT_ENABLE 0x8000 +#define VICT_SWEEP_ENABLE 0x10000 +#define VICT_COUNT 0x0 + +#define PRBS_ORDER(x) ((x & 0x3) << 13) + +#define TEST_COUNT 0x1000 +#define TEST_ADDR 0x0 +#define TEST_ADDR_UPDT 0x1 +#define TEST_PATTERN0 0x5555 +#define TEST_PATTERN1 0xaaaa +#define TEST_PATTERN (TEST_PATTERN1 << 16 | TEST_PATTERN0) + +#define TEST_ENABLE 0x1 +#define TEST_DONE 0x2 +#define TEST_ERROR 0x4 +#define TEST_WRITE 0x10 +#define TEST_READ 0x0 + +#define BACKGND_DATA0 0xa5a5a5a5 +#define BACKGND_DATA1 0x5a5a5a5a +#define BACKGND_DATA2 0xa5a5a5a5 +#define BACKGND_DATA3 0x5a5a5a5a + +#define TEST_DATA0 0x02468ace +#define TEST_DATA1 0x13579bdf +#define TEST_DATA2 0x33cccc33 +#define TEST_DATA3 0x55aaaa55 + +/***** Load DDR Base *************************************/ + li t0, DDR_BASE + li t1, BACKGND_DATA0 + sw t1, DDR_CTL_TEST_DATA0(t0) + li t1, BACKGND_DATA1 + sw t1, DDR_CTL_TEST_DATA1(t0) + li t1, BACKGND_DATA2 + sw t1, DDR_CTL_TEST_DATA2(t0) + li t1, BACKGND_DATA3 + sw t1, DDR_CTL_TEST_DATA3(t0) + li t1, TEST_COUNT + li t2, VICT_COUNT + or t1, t2 # add victim count value + sw t1, DDR_CTL_TEST_COUNT(t0) + li t1, TEST_ADDR + sw t1, DDR_CTL_TEST_ADDR(t0) + li t1, TEST_ADDR_UPDT + sw t1, DDR_CTL_TEST_ADDR_UPDT(t0) + li t1, TEST_PATTERN + sw t1, DDR_CTL_TEST_PAT(t0) + +# Write a background pattern first + li t1, BACKGND_MODE_DATA + li t2, TEST_WRITE + or t1, t2 + li t2, TEST_ENABLE + or t1, t2 + sw t1, DDR_CTL_TEST_CFG1(t0) + + li t2, 0x2 + li t3, MISC_BASE + + li t5, 0x10000 +2: li t1, 0x100 +1: addiu t1, -1 + bnez t1, 1b + nop + + lw t4, MISC_MEMC_CONTROL(t3) + and t4, 0x2 + beq t4, t2, backgnd_write_done + nop + addiu t5, -1 + bnez t5, 2b + nop + +# Background write operation is finished + +backgnd_write_done: + li t1, TEST_DATA0 + sw t1, DDR_CTL_TEST_DATA0(t0) + li t1, TEST_DATA1 + sw t1, DDR_CTL_TEST_DATA1(t0) + li t1, TEST_DATA2 + sw t1, DDR_CTL_TEST_DATA2(t0) + li t1, TEST_DATA3 + sw t1, DDR_CTL_TEST_DATA3(t0) + li t1, TEST_COUNT + li t2, VICT_COUNT + or t1, t2 # add victim count value + sw t1, DDR_CTL_TEST_COUNT(t0) + li t1, TEST_ADDR + sw t1, DDR_CTL_TEST_ADDR(t0) + li t1, TEST_ADDR_UPDT + sw t1, DDR_CTL_TEST_ADDR_UPDT(t0) + li t1, TEST_PATTERN + sw t1, DDR_CTL_TEST_PAT(t0) + +# li t1, BACKGND_MODE_DATA +# li t1, BACKGND_MODE_PAT +# li t2, VICT_MODE_NOT_PAT + li t1, BACKGND_MODE_PRBS + li t2, VICT_MODE_NOT_PRBS + + or t1, t2 + li t2, VICT_ENABLE + or t1, t2 + li t2, VICT_SWEEP_ENABLE + or t1, t2 + li t2, PRBS_ORDER(0) + or t1, t2 + li t2, TEST_WRITE + or t1, t2 + li t2, TEST_ENABLE + or t1, t2 + sw t1, DDR_CTL_TEST_CFG1(t0) + + li t2, 0x2 + li t3, MISC_BASE + + li t5, 0x10000 +2: li t1, 0x100 +1: addiu t1, -1 + bnez t1, 1b + nop + + lw t4, MISC_MEMC_CONTROL(t3) + and t4, 0x2 + beq t4, t2, test_write_done + nop + addiu t5, -1 + bnez t5, 2b + nop + +# Test write operation is finished + +test_write_done: + li t1, TEST_DATA0 + sw t1, DDR_CTL_TEST_DATA0(t0) + li t1, TEST_DATA1 + sw t1, DDR_CTL_TEST_DATA1(t0) + li t1, TEST_DATA2 + sw t1, DDR_CTL_TEST_DATA2(t0) + li t1, TEST_DATA3 + sw t1, DDR_CTL_TEST_DATA3(t0) + li t1, TEST_COUNT + li t2, VICT_COUNT + or t1, t2 # add victim count value + sw t1, DDR_CTL_TEST_COUNT(t0) + li t1, TEST_ADDR + sw t1, DDR_CTL_TEST_ADDR(t0) + li t1, TEST_ADDR_UPDT + sw t1, DDR_CTL_TEST_ADDR_UPDT(t0) + li t1, TEST_PATTERN + sw t1, DDR_CTL_TEST_PAT(t0) + +# li t1, BACKGND_MODE_DATA +# li t1, BACKGND_MODE_PAT +# li t2, VICT_MODE_NOT_PAT + li t1, BACKGND_MODE_PRBS + li t2, VICT_MODE_NOT_PRBS + + or t1, t2 + li t2, VICT_ENABLE + or t1, t2 + li t2, VICT_SWEEP_ENABLE + or t1, t2 + li t2, PRBS_ORDER(0) + or t1, t2 + li t2, TEST_READ + or t1, t2 + li t2, TEST_ENABLE + or t1, t2 + sw t1, DDR_CTL_TEST_CFG1(t0) + + li t3, MISC_BASE + li t2, 0x2 + + li t5, 0x10000 +2: li t1, 0x100 +1: addiu t1, -1 + bnez t1, 1b + nop + + lw t4, MISC_MEMC_CONTROL(t3) + and t4, 0x2 + beq t4, t2, test_read_done + nop + addiu t5, -1 + bnez t5, 2b + nop + +# Test read operation is finished + +test_read_done: + lw t1, DDR_CTL_TEST_CFG1(t0) + srl t1, 2 + and t1, 1 + beq t1, zero, test_passed + nop + +test_failed: + SETLEDS1('F','A','I','L') + b 1f + nop +test_passed: + SETLEDS1('P','A','S','S') +1: + SETLEDS1('-','-','-', '-') +#endif + + move ra,s0 + j ra + nop + + .set reorder + +END(board_draminit) + +/* ********************************************************************* + * BOARD_SETLEDS(x) + * + * Set LEDs for boot-time progress indication. Not used if + * the board does not have progress LEDs. This routine + * must not call any other routines, since it may be invoked + * either from KSEG0 or KSEG1 and it may be invoked + * whether or not the icache is operational. + * + * Input parameters: + * a0 - LED value (8 bits per character, 4 characters) + * + * Return value: + * nothing + * + * Registers used: + * t7,t8,t9 + ********************************************************************* */ +LEAF(board_setleds) +#if 1 + li t7, UART_BASE + li t8, TXFIFOEMT + +1: lh t9, UART0INTSTAT(t7) + and t9, t8 + bne t9, t8, 1b + + srl t8, a0, 24 + sb t8, UART0DATA(t7) + srl t8, a0, 16 + sb t8, UART0DATA(t7) + srl t8, a0, 8 + sb t8, UART0DATA(t7) + sb a0, UART0DATA(t7) + li a0, '\r' + sb a0, UART0DATA(t7) + li a0, '\n' + sb a0, UART0DATA(t7) +#endif + j ra +END(board_setleds) + +/* ********************************************************************* + * BCMCORE_TP1_SWITCH() + * + * Check if the thread switch is required. If we are already + * running on thread 1 this function will do nothing and just return + * If we are running on thread 0 this function will take thread 1 + * out of reset and put thread 0 to sleep waiting for singnal from + * thread 1. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +LEAF(bcmcore_tp1_switch) + +#if defined(_BCM96328_) + li t1, OTP_BASE + addi t1, OTP_USER_BITS + addi t1, 0xc - ((OTP_TP1_DISABLE_BIT / 8) & ~3) + lw t0, 0(t1) + andi t0, 1 << (OTP_TP1_DISABLE_BIT % 32) + beqz t0, 1f + j ra +1: +#endif + mfc0 t1, C0_BCM_CONFIG, 3 + li t2, CP0_CMT_TPID + and t1, t2 + bnez t1, tp1 # Already running on thread 1 + +# Start TP1 +# Set boot address for TP1 + li t1, MIPS_BASE + li t2, 0x98000000 | ENABLE_ALT_BV + sw t2, MIPS_TP1_ALT_BV(t1) + +# Set a flag so we can wait for TP1 to catch up + li t1, 0x0 + mtc0 t1, $31 # CO_DESAVE + +# Take TP1 out of reset + mfc0 t1, C0_BCM_CONFIG, 2 + or t1, CP0_CMT_RSTSE + mtc0 t1, C0_BCM_CONFIG, 2 + + /* wait until second thread catches up with the first */ +waittp1: + mfc0 t0, $31 # CO_DESAVE + beqz t0, waittp1 + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + bne t0, t1, return # Linux will run on TP0, continue running bootloader + +# Voice will run on TP0. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set all ints except IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_4 | CP0_CMT_XIR_3 | CP0_CMT_XIR_2 | CP0_CMT_XIR_0 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP1) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP1, give priority to TP0, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_DSU_TP1 | CP0_CMT_PRIO_TP0 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP0 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR0(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR0(t1) + +2: + b wait_for_wake + +tp1: +# Running on TP1.... +# First signal to TP0 that TP1 is up + li t1, 0x1 + mtc0 t1, $31 # CO_DESAVE + + li t0, THREAD_NUM_ADDRESS + FIXUP(t0) + lw t0, 0(t0) + li t1, 1 + beq t0, t1, return # Linux will run on TP1, continue running bootloader + +# Voice will run on TP1. Set it up and put it to sleep + + # enable interrupts and enable SW IRQ 0 + li t0, M_SR_IE | M_SR_IBIT1 + mtc0 t0, C0_SR + + # Set up to use alternate exception vector 0x80000200 + li t0, M_CAUSE_IV + mtc0 t0, C0_CAUSE + + mfc0 t1, C0_BCM_CONFIG, 1 + # set IRQ1 to TP1 and cross over SW IRQ 0 + or t1, (CP0_CMT_XIR_1 | CP0_CMT_SIR_0 | CP0_CMT_NMIR_TP0) + mtc0 t1, C0_BCM_CONFIG, 1 + + mfc0 t1, C0_BCM_CONFIG, 2 + # Set debug on TP0, give priority to TP1, and + # set TLB exception serialization to ignore SCNT value in CP0 reg22 sel 4 + and t1, ~CP0_CMT_TPS_MASK; + or t1, (CP0_CMT_PRIO_TP1 | (1 << CP0_CMT_TPS_SHFT)) + mtc0 t1, C0_BCM_CONFIG, 2 + + # Enable Data RAC on TP1 + li t1, MIPS_BASE + lw t2, MIPS_RAC_CR1(t1) + or t2, (RAC_D | RAC_PF_D) + sw t2, MIPS_RAC_CR1(t1) + b 2b + +return: + j ra + +END(bcmcore_tp1_switch) + +# align this code to cache line. NAND flash is not memory mapped after system boots +# so when we are signaling to the second TP to wake we need +# jal instruction to be in cache + .align 4 +LEAF(wait_for_wake) + sync + wait # wait for interrupt + jal t8 # jump to entry point +END(wait_for_wake) diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c new file mode 100755 index 0000000..201d6d8 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/bcm63xx_main.c @@ -0,0 +1,649 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Main Module File: bcm63xxBoot_main.c + * + * This module contains the main "C" routine for CFE bootstrap loader + * and decompressor to decompress the real CFE to ram and jump over. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * Revised: seanl + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_timer.h" + +#include "env_subr.h" +#include "ui_command.h" +#include "cfe_mem.h" +#include "cfe.h" + +#include "bsp_config.h" +#include "bcm_hwdefs.h" +#include "bcm_map.h" + +#include "exception.h" + +#include "segtable.h" + +#include "initdata.h" + +#if defined(_BCM96368_) || defined(_BCM96362_) || defined(_BCM96328_) || defined(_BCM96816_) +#include "flash_api.h" +#include "jffs2.h" +#endif + +#if CFG_PCI +#include "pcivar.h" +#endif + + + +int cfe_size_ram(void); +inline static int is_aliased(int max_bits) __attribute__((always_inline)); + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#ifndef CFG_STACK_SIZE +#define STACK_SIZE 8192 +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +inline static int is_aliased(int max_bits) +{ + volatile uint32 *mem_base; + volatile uint32 *test_ptr; + uint32 tmp; + int bit; + int res = 0; + + mem_base = (uint32*)DRAM_BASE_NOCACHE; + + *mem_base = 0; + + for (bit = 8; bit < max_bits; bit++) { + test_ptr = (uint32*)((uint32)mem_base | 1 << bit); + /* ram may contain useful data, save location before modifying */ + tmp = *test_ptr; + *test_ptr = -1; + if (*mem_base == *test_ptr) { + *test_ptr = tmp; + res = 1; + break; + } + *test_ptr = tmp; + } + return res; +} + +#define MEMC_MAX_ROWS 14 + +int cfe_size_ram(void) +{ +#if !(defined(_BCM96328_) || defined (_BCM96362_) || defined(_BCM96816_)) + uint32 col_bits, row_bits, bus_bits, bank_bits; + uint32 size; + + /* Bus width is configured during early boot */ + if (((MEMC->Config & MEMC_WIDTH_MASK) >> MEMC_WIDTH_SHFT) == MEMC_32BIT_BUS) + bus_bits = 2; + else + bus_bits = 1; + + bank_bits = 2; + /* Start from setting to the lowest possible configuration */ + col_bits = 8; + row_bits = 11; + + MEMC->Config &= ~MEMC_COL_MASK; + MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); + + MEMC->Config &= ~MEMC_ROW_MASK; + MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); + + /* Determine number of rows */ + for (row_bits = 12; row_bits <= MEMC_MAX_ROWS; row_bits++) { + MEMC->Config &= ~MEMC_ROW_MASK; + MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); + /* check if this address bit is valid */ + if (is_aliased (col_bits + row_bits + bus_bits + bank_bits)) + break; + } + row_bits -= 1; + MEMC->Config &= ~MEMC_ROW_MASK; + MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); + + /* Determine number of columns */ + for (col_bits = 9; col_bits <= 11; col_bits++) { + MEMC->Config &= ~MEMC_COL_MASK; + MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); + /* check if this address bit is valid */ + if (is_aliased (col_bits + row_bits + bus_bits + bank_bits)) + break; + } + col_bits -= 1; + MEMC->Config &= ~MEMC_COL_MASK; + MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); + + /* Compute memory size in MB */ + size = 1 << (bus_bits + col_bits + row_bits + bank_bits - 20); + + return size; +#else + return (DDR->CSEND << 24); +#endif +} + +// fake functions for not to modifying init_mips.S +void _exc_entry(void); +void cfe_command_restart(void); +void cfe_doxreq(void); + +void _exc_entry(void) +{ +} + +void cfe_command_restart(void) +{ +} +void cfe_doxreq(void) +{ +} + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +void cfe_main(int,int); + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +void cfe_ledstr(const char *leds) +{ +} + +#if !defined(CONFIG_BRCM_IKOS) +extern void _binArrayStart(void); +extern void _binArrayEnd(void); +extern int decompressLZMA(unsigned char *in, unsigned insize, unsigned char *out, unsigned outsize); + +#if (INC_NAND_FLASH_DRIVER==1) || (INC_SPI_PROG_NAND==1) +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) +extern void rom_nand_flash_init(void); +extern int nand_flash_get_sector_size(unsigned short sector); +extern int nand_flash_get_numsectors(void); +extern int nand_flash_read_buf(unsigned short blk, int offset, + unsigned char *buffer, int len); +extern void board_setleds(unsigned long); + +void *lib_memcpy(void *dest,const void *src,size_t cnt) +{ + unsigned char *d; + const unsigned char *s; + + d = (unsigned char *) dest; + s = (const unsigned char *) src; + + while (cnt) { + *d++ = *s++; + cnt--; + } + + return dest; +} + +int lib_memcmp(const void *dest,const void *src,size_t cnt) +{ + const unsigned char *d; + const unsigned char *s; + + d = (const unsigned char *) dest; + s = (const unsigned char *) src; + + while (cnt) { + if (*d < *s) return -1; + if (*d > *s) return 1; + d++; s++; cnt--; + } + + return 0; +} + +#if (INC_NAND_FLASH_DRIVER==1) +/* Find uncompressed file cferam.bin on the JFFS2 file system, load it into + * memory and jump to its entry point function. + */ +char g_fname[] = NAND_CFE_RAM_NAME; +int g_fname_actual_len = sizeof(g_fname) - 1; +int g_fname_cmp_len = sizeof(g_fname) - 4; /* last three are digits */ +static void bootImageFromNand(void) +{ + const unsigned long bv_invalid = 0xfffffff; + const int max_not_jffs2 = 10; + + struct rootfs_info + { + int rootfs; + int start_blk; + int end_blk; + unsigned long boot_val; + unsigned long ino; + } rfs_info[2], *prfs_info[2], *rfsi; + + unsigned char *buf = (unsigned char *) mem_heapstart; + unsigned long version = 0; + struct jffs2_raw_dirent *pdir; + struct jffs2_raw_inode *pino; + unsigned char *p; + int i, j, k, done, not_jffs2; + int num_blks; + int len; + int boot_prev; + PNVRAM_DATA nd; + static int err0=0, err1=1; + + rom_nand_flash_init(); + num_blks = nand_flash_get_numsectors(); + len = nand_flash_get_sector_size(0); + nd = (PNVRAM_DATA) (buf + len); + + NAND->NandNandBootConfig = NBC_AUTO_DEV_ID_CFG | 0x101; + NAND->NandCsNandXor = 1; + + memcpy((unsigned char *) nd, (unsigned char *) + FLASH_BASE + NVRAM_DATA_OFFSET, sizeof(NVRAM_DATA)); + + NAND->NandNandBootConfig = NBC_AUTO_DEV_ID_CFG | 0x2; + NAND->NandCsNandXor = 0; + + /* Look at config to determine whether to boot current or previous image.*/ + for( i = 0, p = (unsigned char *) nd->szBootline, boot_prev = 0; + i < NVRAM_BOOTLINE_LEN; i++, p++ ) + { + if( p[0] == ' ' && p[1] == 'p' && p[2] == '=' ) + { + boot_prev = p[3] - '0'; + if( boot_prev != 0 && boot_prev != 1 ) + boot_prev = '0'; + break; + } + } + + /* Find the CFE ram inode entry point for both root file systems. */ + board_setleds((boot_prev == 0) ? 0x4e414e30 : 0x4e414e31); + for( k = 0, rfsi = rfs_info; k < 2; k++, rfsi++ ) + { + version = 0; + not_jffs2 = 0; + rfsi->rootfs = k + NP_ROOTFS_1; + rfsi->boot_val = bv_invalid; + if( nd->ulNandPartOfsKb[rfsi->rootfs] > 0 && + nd->ulNandPartOfsKb[rfsi->rootfs] < ((num_blks * len) / 1024)) + { + rfsi->start_blk = nd->ulNandPartOfsKb[rfsi->rootfs] / (len/1024); + rfsi->end_blk = rfsi->start_blk + + (nd->ulNandPartSizeKb[rfsi->rootfs] / (len / 1024)); + } + else + rfsi->start_blk = rfsi->end_blk = 0; + + if( rfsi->start_blk == 0 || rfsi->start_blk >= rfsi->end_blk || + rfsi->start_blk >= num_blks || rfsi->end_blk >= num_blks ) + { + /* NVRAM_DATA fields for this rootfs are not valid. */ + if( k == 0 ) + { + /* Skip this rootfs. */ + board_setleds(0x4e414e36); + continue; + } + + if( rfs_info[0].boot_val == bv_invalid ) + { + /* File system info cannot be found for either rootfs. + * NVRAM_DATA may not be set. Use default values. + */ + board_setleds(0x4e414e37); + rfsi = rfs_info; + rfsi->start_blk = 1; + rfsi->end_blk = num_blks; + } + } + + /* Find the directory entry. */ + for( i = rfsi->start_blk, done = 0; i < rfsi->end_blk && done == 0; i++ ) + { + /* This loop sequentially reads a NAND flash block into memory and + * processes it. + */ + if( nand_flash_read_buf(i, 0, buf, len) > 0 ) + { + /* This loop reads inodes in a block. */ + p = buf; + while( p < buf + len ) + { + pdir = (struct jffs2_raw_dirent *) p; + if( je16_to_cpu(pdir->magic) == JFFS2_MAGIC_BITMASK ) + { + if( je16_to_cpu(pdir->nodetype) == + JFFS2_NODETYPE_DIRENT && + g_fname_actual_len == pdir->nsize && + !memcmp(g_fname, pdir->name, g_fname_cmp_len) ) + { + /* The desired directory was found. */ + if( je32_to_cpu(pdir->version) > version ) + { + if( (rfsi->ino = je32_to_cpu(pdir->ino)) != 0 ) + { + unsigned char *fname = + pdir->name + g_fname_cmp_len; + rfsi->boot_val = + ((fname[0] - '0') * 100) + + ((fname[1] - '0') * 10) + + ((fname[2] - '0') * 1); + version = je32_to_cpu(pdir->version); + + board_setleds(0x42540000 + + ((unsigned long) fname[1] << 8) + + (unsigned long) fname[2]); + + /* Setting 'done = 1' assumes there is only + * one version of the directory entry. This + * may not be correct if the file is + * updated after it was initially flashed. + * + * TBD. Look for a higher version of the + * directory entry without searching the + * entire flash part. + */ + done = 1; + break; + } + } + } + + p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; + not_jffs2 = 0; + } + else + { + if( not_jffs2++ > max_not_jffs2 ) + { + /* No JFFS2 magic bitmask for consecutive blocks. + * Assume this partion does not have a file system + * on it. + */ + board_setleds(0x53544F50); + done = 1; + } + break; + } + } + } + else + { + if(!err0) + { + err0=1; + board_setleds(0x45525230); + } + } + } + board_setleds(0x4e414e39); + } + + /* Set the rfs_info to the index to boot from. */ + if( (boot_prev == 0 && rfs_info[0].boot_val > rfs_info[1].boot_val) || + (boot_prev == 1 && rfs_info[0].boot_val < rfs_info[1].boot_val) || + rfs_info[1].boot_val == bv_invalid ) + { + /* Boot from the most recent image. */ + prfs_info[0] = &rfs_info[0]; + prfs_info[1] = &rfs_info[1]; + } + else + { + /* Boot from the previous image. */ + prfs_info[0] = &rfs_info[1]; + prfs_info[1] = &rfs_info[0]; + } + + /* If the directory entry for the desired file, which is the CFE RAM image, + * is found, read it into memory and jump to its entry point function. + * This loop checks for CFE RAM image in two possible rootfs file sytems. + */ + for( k = 0; k < 2; k++ ) + { + unsigned char *pucDest = NULL; + unsigned char *pucEntry = NULL; + long isize = 0; + + board_setleds(0x4e414e33); + rfsi = prfs_info[k]; + if( rfsi->boot_val == bv_invalid ) + continue; + + /* When j == 0, get the first inode to find the entry point address. + * When j == 1, read the file contents into memory. + */ + for( j = 0; j < 2; j++ ) + { + /* This loop sequentially reads a NAND flash block into memory and + * processes it. + */ + for(i = rfsi->start_blk, done = 0; iend_blk && done==0; i++) + { + if( nand_flash_read_buf(i, 0, buf, len) > 0 ) + { + /* This loop reads inodes in a block. */ + p = buf; + while( p < buf + len ) + { + /* Verify the first short word is the JFFS2 magic + * number. + */ + pino = (struct jffs2_raw_inode *) p; + if( je16_to_cpu(pino->magic) == JFFS2_MAGIC_BITMASK ) + { + if( je16_to_cpu(pino->nodetype) == + JFFS2_NODETYPE_INODE && + je32_to_cpu(pino->ino) == rfsi->ino ) + { + unsigned long size = je32_to_cpu(pino->dsize); + unsigned long ofs = je32_to_cpu(pino->offset); + + if( size ) + { + /* A node of the CFE RAM file was found + * with data. */ + if( pucDest == NULL ) + { + /* The entry point and copy destination + * addresses have not been obtained. + * If this is the first node of the CFE + * RAM file, obtain this information. + */ + if( ofs == 0 ) + { + /* The first 12 bytes contain a + * header. The first word is the + * entry point address. + */ + pucEntry = (unsigned char *) + *(unsigned long *) pino->data; + pucDest = pucEntry - 12; + isize = je32_to_cpu(pino->isize); + done = 1; + board_setleds(0x52465330 | + rfsi->rootfs); + break; + } + } + else + { + /* Copy the image to memory. Stop when + * the entire image has been copied. + */ + memcpy(pucDest+ofs, pino->data, size); + if( (isize -= size) <= 0 ) + { + done = 1; + break; + } + } + } + } + + /* Skip to the next inode entry. */ + p += (je32_to_cpu(pino->totlen) + 0x03) & ~0x03; + } + else + break; + } + } + else + { + if(!err1) + { + err1=1; + board_setleds(0x45525231); + } + } + } + } + + if( pucEntry && isize <= 0 ) + { + board_setleds(0x4e414e35); + + /* Save the rootfs partition that the CFE RAM image boots from + * at the memory location before the CFE RAM load address. The + * CFE RAM image uses this value to determine the partition to + * flash a new rootfs to. + */ + *(pucEntry - 1) = (unsigned char) rfsi->rootfs; + + cfe_launch((unsigned long) pucEntry); // never return... + } + board_setleds(0x4e414e38); + } + + /* Error occurred. */ + board_setleds(0x44494530); + while(1); +} +#endif +#endif + +/* ********************************************************************* + * cfe_main(a,b) + * + * It's gotta start somewhere. + * Input parameters: + * a,b - not used + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_main(int a,int b) +{ + unsigned char *pucSrc; + unsigned char *pucDst; + unsigned int *entryPoint; + unsigned int binArrayStart = (unsigned int) _binArrayStart; + unsigned int binArrayEnd = (unsigned int) _binArrayEnd; + unsigned int dataLen = binArrayEnd - binArrayStart - 4; + int ret; + + KMEMINIT((unsigned char *) (uint32_t) mem_heapstart, + ((CFG_HEAP_SIZE)*1024)); + +#if (INC_NAND_FLASH_DRIVER==1) && (defined(_BCM96816_) || defined(_BCM96362_) || defined(_BCM96328_)) + if( ((MISC->miscStrapBus & MISC_STRAP_BUS_BOOT_SEL_MASK) >> + MISC_STRAP_BUS_BOOT_SEL_SHIFT) == MISC_STRAP_BUS_BOOT_NAND ) + { + bootImageFromNand(); /* Will not return. */ + } +#elif (INC_NAND_FLASH_DRIVER==1) && defined(_BCM96368_) + if( ((GPIO->StrapBus & MISC_STRAP_BUS_BOOT_SEL_MASK) >> + MISC_STRAP_BUS_BOOT_SEL_SHIFT) == MISC_STRAP_BUS_BOOT_NAND ) + { + bootImageFromNand(); /* Will not return. */ + } +#endif + + entryPoint = (unsigned int*) binArrayStart; + pucSrc = (unsigned char *) (binArrayStart + 4); + + pucDst = (unsigned char *) *entryPoint; + ret = decompressLZMA((unsigned char*)pucSrc, + (unsigned int)dataLen, + (unsigned char *) pucDst, + 23*1024*1024); + + if (ret != 0) + while (1); // if not decompressed ok, loop for EJTAG + + cfe_launch((unsigned long) pucDst); // never return... +} +#else +/* 0x694b6f31 (iKo1) is replaced with actual address during the build process.*/ +unsigned long cfeRamStartAddr=0x694b6f31; +void cfe_main(int a,int b) +{ + cfe_size_ram(); + cfe_launch(cfeRamStartAddr); // never return... +} +#endif + diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c new file mode 100755 index 0000000..310fb40 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/memtest.c @@ -0,0 +1,1031 @@ +/* + *----------------------------------------------------------------------------* + * Collection of Memory Tests. + *----------------------------------------------------------------------------* + */ + +// +// NOTE: Blatant inlining ... (not sure whether caller supports EABI calls). +// WARNING CFE: Must NOT use function calls !!! +// +#define _ALWAYS_INLINE_ __attribute__((always_inline)) +#define _INLINE_ inline static + +typedef enum memTestResult { + MEMTEST_FAILURE = 0, + MEMTEST_SUCCESS, + MEMTEST_ERROR, +} MemTestResult_t; + +/* ------------------------------------------------------------------------- */ + +#undef PATTERN +#define PATTERN(x) PATTERN_##x, + +/* + * For each pattern listed, the inverse pattern is also automatically used. + * E.g. 0x55555555, the inverse of defined 0xAAAAAAAA is covered. + */ +typedef enum pattern { + PATTERN(0x00000000) + PATTERN(0xAAAAAAAA) + PATTERN(0xCCCCCCCC) + PATTERN(0x77777777) + PATTERN(0xF0F0F0F0) + PATTERN(0xFF00FF00) + PATTERN(0xFFFF0000) + PATTERN(0x01234567) + PATTERN(0x89ABCDEF) + PATTERN_MAX, +} Pattern_t; + +#undef PATTERN +#define PATTERN(x) x, +const uint32_t pattern[] = { + PATTERN(0x00000000) + PATTERN(0xAAAAAAAA) + PATTERN(0xCCCCCCCC) + PATTERN(0x77777777) + PATTERN(0xF0F0F0F0) + PATTERN(0xFF00FF00) + PATTERN(0xFFFF0000) + PATTERN(0x01234567) + PATTERN(0x89ABCDEF) + PATTERN_MAX, +}; + +/* ------------------------------------------------------------------------- */ + +#ifndef NBBY +#define NBBY 8 /* FreeBSD style: Number Bits per BYte */ +#endif + +/* ------------------------------------------------------------------------- */ + +#define NBITS(type) (sizeof(type) * NBBY) +#define NBITVAL(nbits) (1 << (nbits)) +#define MAXBITVAL(nbits) ( NBITVAL(nbits) - 1) +#define NBITMASK(nbits) MAXBITVAL(nbits) +#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * NBBY) + +#define DIVBY(val32,by) ((val32)>>(by)) +#define MODBY(val32,by) ((val32) & ((1 <<(by)) - 1) ) + +#define IS_POWEROF2(val32) ( (((val32)-1) & (val32)) == 0 ) + +#define ROUNDDN(addr, align) ( (addr) & ~((align) - 1) ) +#define ROUNDUP(addr, align) ( ((addr) + (align) - 1) & ~((align) - 1) ) +//#define ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define ALIGN_ADDR(addr, bytes) (void *)( ((uint32_t *)(addr) + (bytes) - 1) \ + & ~((bytes) - 1) ) +#define IS_ALIGNED(addr, bytes) (((uint32_t)(addr) & ((bytes)-1)) == 0) + +#define OFFSET_OF(stype,member) ((uint32_t) &((struct stype *)0)->member) +#define RELOC(base,stype,member) ((base) + OFFSET_OF(stype, member)) + +#define RROTATE32(val32) (((val32) << 31) | ((val32) >> 1)) +#define LROTATE32(val32) (((val32) << 1) | ((val32) >> 31)) + +/* ------------------------------------------------------------------------- */ + +/* Aligned (32bit register) read/write access */ +#define RD16(addr16) (*(volatile uint32_t *)(addr16)) +#define WR16(addr16,val16) (*(volatile uint32_t *)(addr16))=(val16) +#define RD32(addr32) (*(volatile uint32_t *)(addr32)) +#define WR32(addr32,val32) (*(volatile uint32_t *)(addr32))=(val32) + +/*---------------------------------------------------------------------------*/ + +/* Forward declaration */ +_INLINE_ void fill_memory( uint32_t * addr, uint32_t bytes, uint32_t fill32) + _ALWAYS_INLINE_; +_INLINE_ void fill_alt_memory(uint32_t * addr, uint32_t bytes, + uint32_t fillA32, uint32_t fillB32) _ALWAYS_INLINE_; + +void fill_memory( uint32_t * addr, uint32_t bytes, uint32_t fill32) +{ + uint32_t * at, * end_p; + uint32_t words; + words = bytes / sizeof(uint32_t); + if ( words == 0 ) return; + + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + WR32( at, fill32 ); +} + +void fill_alt_memory( uint32_t * addr, uint32_t bytes, + uint32_t fillA32, uint32_t fillB32) +{ + uint32_t * at, * end_p; + uint32_t words; + words = bytes / sizeof(uint32_t); + words = ROUNDDN( words, 2 ); + if ( words == 0 ) return; + + end_p = addr + words; + for ( at = addr; at < end_p; at+=2 ) + { + WR32( at+0, fillA32 ); + WR32( at+1, fillB32 ); + } +} + +/* Forward declaration */ +_INLINE_ MemTestResult_t scanWordValue( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanBulkValue( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanBulkAltInv( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanWordSelf( uint32_t * addr, uint32_t bytes ) + _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t scanBulkSelf( uint32_t * addr, uint32_t bytes ) + _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t slidingAltInv( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t slidingDiag( uint32_t * addr, uint32_t bytes, + uint32_t pat32 ) _ALWAYS_INLINE_; +_INLINE_ MemTestResult_t memoryBulkCopy( uint32_t * saddr, uint32_t * daddr, + uint32_t bytes ) _ALWAYS_INLINE_; + +/* + *----------------------------------------------------------------------------- + * Function: scanWordValue + * + * Description: + * 4 Passes are conducted on the memory region. + * Pass 1. In INcreasing memory address, write a word with value and verify. + * Pass 2. In DEcreasing memory address, write a word with value and verify. + * Pass 3. In INcreasing memory address, write a word with INVERSE and verify. + * Pass 4. In DEcreasing memory address, write a word with INVERSE and verify. + * Pass 5. In INcreasing shifted memory address, write word with value verify. + * Pass 6. In INcreasing shifted memory address, write word with INVERSE verify. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: 32bit pattern, e.g. 0x0U, 0xAAAAAAAA, 0xFF00FF00, 0xFFFF0000, + * 0xF0F0F0F0, 0xC3C3C3C3, 0x87878787 + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanWordValue( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) + return MEMTEST_ERROR; + + expected = pat32; /* ORIGINAL value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* PASS 5: Shifting address walk, ORIGINAL */ + expected = pat32; /* ORIGINAL value */ + + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + + /* PASS 6: Shifting address walk, INVERSE */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: scanBulkValue + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with value + * then in INcreasing memory address read and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with value + * then in DEcreasing memory address read and verify. + * Pass 3. Fill entire memory in INcreasing memory address with inverse value + * then in INcreasing memory address read and verify. + * Pass 4. Fill entire memory in DEcreasing memory address with inverse value + * then in DEcreasing memory address read and verify. + * Pass 5. INcreasing shifted, ORIGINAL + * Pass 6. INcreasing shifted, INVERSE + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: 32bit pattern, e.g. 0x0U, 0xAAAAAAAA, 0xFF00FF00, 0xFFFF0000, + * 0xF0F0F0F0, 0xC3C3C3C3, 0x87878787 + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanBulkValue( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + expected = pat32; /* ORIGINAL value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* Pass 5. INCREASING Shifted traversal */ + expected = pat32; /* ORIGINAL value */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + expected = ~pat32; /* INVERSE value */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, expected ); + WR32( addr, ~expected ); /* noise at base addr */ + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: scanBulkAltInv + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with alternating + * value, then in INcreasing memory address read and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with alternating + * value, then in DEcreasing memory address read and verify. + * Pass 3. Same as one but with shifted address. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: 32bit pattern, e.g. 0x0U, 0xAAAAAAAA, 0xFF00FF00, 0xFFFF0000, + * 0xF0F0F0F0, 0xC3C3C3C3, 0x87878787 + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanBulkAltInv( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + words = ROUNDDN( words, 2 ); + if ( words == 0 ) return MEMTEST_ERROR; + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at+=2 ) + { + WR32( at+0, pat32 ); + WR32( at+1, ~pat32 ); + } + for ( at = addr; at < end_p; at+=2 ) + { + read = RD32( at+0 ); + if ( read != pat32 ) + { + return MEMTEST_FAILURE; + } + read = RD32( at+1 ); + if ( read != ~pat32 ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-=2 ) + { + WR32( at+0, pat32 ); + WR32( at+1, ~pat32 ); + } + for ( at = addr + words - 1; at >= end_p; at-=2 ) + { + read = RD32( at+0 ); + if ( read != pat32 ) + { + return MEMTEST_FAILURE; + } + read = RD32( at+1 ); + if ( read != ~pat32 ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING SHIFTED traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at+0, pat32 ); + WR32( addr, 0 ); + WR32( at+1, ~pat32 ); + WR32( addr, 0 ); + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32( at+0 ); + if ( read != pat32 ) + { + return MEMTEST_FAILURE; + } + read = RD32( at+1 ); + if ( read != ~pat32 ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + + +/* + *----------------------------------------------------------------------------- + * Function: scanWordSelf + * + * Description: + * 4 Passes are conducted on the memory region. + * Pass 1. In INcreasing memory address, write a word with selfaddr and verify. + * Pass 2. In DEcreasing memory address, write a word with INVERSE and verify. + * Pass 3. In INcreasing memory address, write a word with INVERSE and verify. + * Pass 4. In DEcreasing memory address, write a word with selfaddr and verify. + * Pass 5. value = ORIGINAL address, INCREASING SHIFTED traversal. + * Pass 6. value = INVERSE address, INCREASING SHIFTED traversal. + * + * In Pass 2 Read+Modify+Write, and in Pass 3, Read+Write is used + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanWordSelf( uint32_t * addr, uint32_t bytes ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_FAILURE; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + /* ORIGINAL value */ + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + expected = (uint32_t)at; + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + expected = ~( (uint32_t)RD32(at) ); + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + expected = ((uint32_t)RD32(at)); + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + expected = ~((uint32_t)at); + WR32( at, expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* value = ORIGINAL address, INCREASING SHIFTED traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + expected = (uint32_t)at; /* Not read modify write */ + WR32( at, expected ); + WR32( addr, ~expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* value = INVERSE address, INCREASING SHIFTED traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + expected = ~(uint32_t)(at); /* Not read modify write */ + WR32( at, expected ); + WR32( addr, ~expected ); + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: scanBulkSelf + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with self address + * then in INcreasing memory address read and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with self address + * then in DEcreasing memory address read and verify. + * Pass 3. Fill entire memory in INcreasing memory address with inverse addr + * then in INcreasing memory address read and verify. + * Pass 4. Fill entire memory in DEcreasing memory address with inverse addr + * then in DEcreasing memory address read and verify. + * Pass 5. Same as Pass 1 but with shifted address + * Pass 6. Same as Pass 3 but with shifted address + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + *----------------------------------------------------------------------------- + */ +MemTestResult_t scanBulkSelf( uint32_t * addr, uint32_t bytes ) +{ + volatile uint32_t * at, * end_p; + uint32_t read, words; + uint32_t shift; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, (uint32_t)at ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != (uint32_t)at ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, (uint32_t)at ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != (uint32_t)at ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, ~((uint32_t)at) ); + } + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != ~((uint32_t)at) ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, ~((uint32_t)at) ); + } + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != ~((uint32_t)at) ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, (uint32_t)at ); + WR32( addr, ~((uint32_t)at) ); + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != (uint32_t)at ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal */ + end_p = addr + words; + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + WR32( at, ~((uint32_t)at) ); + WR32( addr, ((uint32_t)at) ); + } + shift = sizeof(uint32_t); + for ( at = addr + shift; at < end_p; shift <<= 1, at = addr + shift ) + { + read = RD32(at); + if ( read != ~((uint32_t)at) ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + + +/* + *----------------------------------------------------------------------------- + * Function: slidingAltInv + * + * Description: + * This is the same as scanBulkAltInv, where in each invocation the value is + * rotated to the right. The starting value is usedefined. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: pattern to slide per pass + *----------------------------------------------------------------------------- + */ +MemTestResult_t slidingAltInv( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + uint32_t sliding_pat32, i; + + if ( pat32 == 0x0 ) pat32 = 0x80000000; + if ( pat32 == ~0x0 ) pat32 = 0x7FFFFFFF; + + sliding_pat32 = pat32; + + for ( i=0; i<32; i++ ) + { + if ( scanBulkAltInv( addr, bytes, sliding_pat32 ) + == MEMTEST_FAILURE ) + { + return MEMTEST_FAILURE; + } + + sliding_pat32 = RROTATE32( sliding_pat32 ); + } + + sliding_pat32 = pat32; + for (i=0; i<32; i++) + { + if ( scanBulkAltInv( addr, bytes, sliding_pat32 ) + == MEMTEST_FAILURE ) + { + return MEMTEST_FAILURE; + } + + sliding_pat32 = LROTATE32( sliding_pat32 ); + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: slidingDiag + * + * Description: + * Pass 1. Fill entire memory in INcreasing memory address with pattern right + * shifted. Then read in INcreasing order and verify. + * Pass 2. Fill entire memory in DEcreasing memory address with inverse of + * read value. Then read in DEcreasing order and verify. + * Pass 3. Fill entire memory in DEcreasing memory address with pattern right + * shifted. Then read in DEcreasing order and verify. + * Pass 4. Fill entire memory in INcreasing memory address with inverse of + * read value. Then read in INcreasing order and verify. + * + * Parameters: + * addr: word aligned pointer to memory region + * bytes: size in bytes of memory region to test + * pat32: pattern to be filled shifted each write + *----------------------------------------------------------------------------- + */ +MemTestResult_t slidingDiag( uint32_t * addr, uint32_t bytes, uint32_t pat32 ) +{ + volatile uint32_t * at, * end_p; + uint32_t expected, read = 0, words, last; + + if ( ! IS_ALIGNED(addr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + + /* INCREASING traversal */ + expected = pat32; /* ORIGINAL value */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + WR32( at, expected ); + expected = RROTATE32( expected ); /* next expected */ + } + expected = pat32; /* ORIGINAL value */ + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = RROTATE32( expected ); /* next expected */ + } + + last = ~( read ); /* Starting value for decreasing traversal, next */ + + /* DECREASING traversal */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + expected = ~( RD32(at) ); + WR32( at, expected ); + } + expected = last; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = LROTATE32( expected ); + } + + /* DECREASING traversal */ + expected = pat32; /* ORIGINAL value */ + end_p = addr; + for ( at = addr + words - 1; at >= end_p; at-- ) + { + WR32( at, expected ); + expected = RROTATE32( expected ); /* next expected */ + } + expected = pat32; /* ORIGINAL value */ + for ( at = addr + words - 1; at >= end_p; at-- ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = RROTATE32( expected ); /* next expected */ + } + + last = ~( read ); + + /* INCREASING traversal */ + end_p = addr + words; + for ( at = addr; at < end_p; at++ ) + { + expected = ~( RD32(at) ); + WR32( at, expected ); + } + expected = last; + for ( at = addr; at < end_p; at++ ) + { + read = RD32(at); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + expected = LROTATE32( expected ); + } + + return MEMTEST_SUCCESS; +} + +/* + *----------------------------------------------------------------------------- + * Function: memoryBulkCopy + * + * Description: + * Pass 1. Copy entire ORIGINAL memory in INcreasing memory address, then verify + * Pass 2. Copy entire ORIGINAL memory in DEcreasing memory address, then verify + * Pass 3. Copy entire INVERSE memory in INcreasing memory address, then verify + * Pass 4. Copy entire INVERSE memory in DEcreasing memory address, then verify + *----------------------------------------------------------------------------- + */ +MemTestResult_t memoryBulkCopy( uint32_t * saddr, uint32_t * daddr, + uint32_t bytes ) +{ + volatile uint32_t * src_p, * dst_p, * end_p; + uint32_t expected, read, words; + + if ( ! IS_ALIGNED(saddr,4) ) return MEMTEST_ERROR; + if ( ! IS_ALIGNED(daddr,4) ) return MEMTEST_ERROR; + + words = bytes / sizeof(uint32_t); /* in whole words (4byte multiple) */ + if ( words == 0 ) return MEMTEST_ERROR; + + if ( (uint32_t)saddr < (uint32_t)daddr ) + { + if ( (uint32_t)(saddr + words) > (uint32_t)daddr ) + return MEMTEST_ERROR; + } + else if ( (uint32_t)daddr < (uint32_t)saddr ) + { + if ( (uint32_t)(daddr + words) > (uint32_t)saddr ) + return MEMTEST_ERROR; + } + + /* INCREASING traversal ORIGINAL */ + end_p = saddr + words; + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = RD32( dst_p ); + WR32( src_p, expected ); + } + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = RD32( dst_p ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal ORIGINAL */ + end_p = saddr; + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = RD32( dst_p ); + WR32( src_p, expected ); + } + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = RD32( dst_p ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* INCREASING traversal INVERSE */ + end_p = saddr + words; + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = ~( RD32( dst_p ) ); + WR32( src_p, expected ); + } + for ( src_p = saddr, dst_p = daddr; src_p < end_p; src_p++, dst_p++ ) + { + expected = ~( RD32( dst_p ) ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + /* DECREASING traversal INVERSE */ + end_p = saddr; + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = ~( RD32( dst_p ) ); + WR32( src_p, expected ); + } + for ( src_p = saddr + words - 1, dst_p = daddr + words - 1; + src_p >= end_p; src_p--, dst_p-- ) + { + expected = ~( RD32( dst_p ) ); + read = RD32( src_p ); + if ( read != expected ) + { + return MEMTEST_FAILURE; + } + } + + return MEMTEST_SUCCESS; +} + +/*---------------------------------------------------------------------------*/ diff --git a/cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk new file mode 100755 index 0000000..c45aea7 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_rom/src/rom_cfe.mk @@ -0,0 +1,370 @@ + +# +# CFE's version number +# + +include ${TOP}/main/cfe_version.mk + +# +# Default values for certain parameters +# + +CFG_MLONG64 ?= 0 +CFG_LITTLE ?= 0 +CFG_RELOC ?= 0 +CFG_UNCACHED ?= 0 +CFG_NEWRELOC ?= 0 +CFG_BOOTRAM ?= 0 +CFG_VGACONSOLE ?= 0 +CFG_PCI ?= 1 +CFG_LDT_REV_017 ?= 0 +CFG_ZLIB ?= 0 +CFG_BIENDIAN ?= 0 +CFG_DOWNLOAD ?= 0 +CFG_RAMAPP ?= 0 +CFG_USB ?= 0 + +# +# Paths to other parts of the firmware. Everything's relative to ${TOP} +# so that you can actually do a build anywhere you want. +# + +ARCH_TOP = ${TOP}/arch/${ARCH} +ARCH_SRC = ${ARCH_TOP}/common/src +ARCH_INC = ${ARCH_TOP}/common/include +CPU_SRC = ${ARCH_TOP}/cpu/${CPU}/src +CPU_INC = ${ARCH_TOP}/cpu/${CPU}/include +# +# It's actually optional to have a 'board' +# directory. If you don't specify BOARD, +# don't include the files. +# + +ifneq ("$(strip ${BOARD})","") +BOARD_SRC = ${ARCH_TOP}/board/${BOARD}/src +BOARD_INC = ${ARCH_TOP}/board/${BOARD}/include +endif + +# +# Preprocessor defines for CFE's version number +# + +VDEF = -DCFE_VER_MAJ=${CFE_VER_MAJ} -DCFE_VER_MIN=${CFE_VER_MIN} -DCFE_VER_ECO=${CFE_VER_ECO} + +# +# Construct the list of paths that will eventually become the include +# paths and VPATH +# + +SRCDIRS = ${ARCH_SRC} ${CPU_SRC} ${BOARD_SRC} ${TOP}/main ${TOP}/vendor ${TOP}/include ${TOP}/net ${TOP}/dev ${TOP}/pci ${TOP}/ui ${TOP}/lib ${TOP}/common ${TOP}/verif ${TOP}/lzma + +CFE_INC = ${TOP}/include ${TOP}/pci ${TOP}/net + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +SRCDIRS += ${TOP}/x86emu ${TOP}/pccons +CFE_INC += ${TOP}/x86emu ${TOP}/pccons +endif + +ifeq ($(strip ${CFG_VAPI}),1) +SRCDIRS += ${TOP}/verif +CFE_INC += ${TOP}/verif +endif + +ifeq ($(strip ${CFG_ZLIB}),1) +SRCDIRS += ${TOP}/zlib +CFE_INC += ${TOP}/zlib +endif + + +INCDIRS = $(patsubst %,-I%,$(subst :, ,$(ARCH_INC) $(CPU_INC) $(BOARD_INC) $(CFE_INC))) + +VPATH = $(SRCDIRS) + +# +# Bi-endian support: If we're building the little-endian +# version, use a different linker script so we can locate the +# ROM at a higher address. You'd think we could do this with +# normal linker command line switches, but there appears to be no +# command-line way to override the 'AT' qualifier in the linker script. +# + +CFG_TEXTAT1MB=0 +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),1) + CFG_TEXTAT1MB=1 + endif +endif + + +# +# Configure tools and basic tools flags. This include sets up +# macros for calling the C compiler, basic flags, +# and linker scripts. +# + +include ${ARCH_SRC}/tools.mk + +# +# Add some common flags that are used on any architecture. +# + +CFLAGS += -I. $(INCDIRS) +CFLAGS += -D_CFE_ ${VDEF} -DCFG_BOARDNAME=\"${CFG_BOARDNAME}\" + +# +# Gross - allow more options to be supplied from command line +# + +ifdef CFG_OPTIONS +OPTFLAGS = $(patsubst %,-D%,$(subst :, ,$(CFG_OPTIONS))) +CFLAGS += ${OPTFLAGS} +endif + +ifeq ($(strip $(BRCM_IKOS)),y) +CFLAGS += -DCONFIG_BRCM_IKOS +endif + +# +# Add flash driver support. +# + +ifeq ($(strip $(BLD_NAND)),1) +# BUILD NAND flash boot loader +ifeq ($(strip $(BRCM_CHIP)),6328) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif +ifeq ($(strip $(BRCM_CHIP)),6362) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif +ifeq ($(strip $(BRCM_CHIP)),6368) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif +ifeq ($(strip $(BRCM_CHIP)),6816) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=0 +INC_NAND_FLASH_DRIVER=1 +endif + +else +# BUILD NOR flash boot loader +ifeq ($(strip $(BRCM_CHIP)),6328) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +ifeq ($(strip $(BRCM_CHIP)),6362) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +ifeq ($(strip $(BRCM_CHIP)),6368) +INC_CFI_FLASH_DRIVER=1 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +ifeq ($(strip $(BRCM_CHIP)),6816) +INC_CFI_FLASH_DRIVER=1 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +endif +endif + +ifeq ($(strip $(BLD_SPI_NAND)),1) +INC_CFI_FLASH_DRIVER=0 +INC_SPI_FLASH_DRIVER=1 +INC_NAND_FLASH_DRIVER=0 +INC_SPI_PROG_NAND=1 +else +INC_SPI_PROG_NAND=0 +endif + +CFLAGS += -DINC_CFI_FLASH_DRIVER=$(INC_CFI_FLASH_DRIVER) +CFLAGS += -DINC_SPI_FLASH_DRIVER=$(INC_SPI_FLASH_DRIVER) +CFLAGS += -DINC_NAND_FLASH_DRIVER=$(INC_NAND_FLASH_DRIVER) +CFLAGS += -DINC_SPI_PROG_NAND=$(INC_SPI_PROG_NAND) + +# +# This is the makefile's main target. Note that we actually +# do most of the work in 'ALL' not 'all', since we include +# other makefiles after this point. +# + +all : build_date.c ALL + +# +# Macros that expand to the list of arch-independent files +# + +LZMAOBJS = LzmaDecode.o dcapi.o +DEVOBJS = lib_malloc.o +## dev_newflash.o dev_null.o dev_promice.o dev_ide_common.o dev_ns16550.o dev_ds17887clock.o dev_flash.o + +##lib_hssubr.o lib_physio.o lib_printf.o lib_misc.o \ lib_arena.o lib_queue.o +## lib_qsort.o lib_string.o lib_string2.o + +NETOBJS = +## net_tcp.o net_tcpbuf.o dev_tcpconsole.o net_dhcp.o net_icmp.o net_ether.o net_tftp.o net_ip.o net_udp.o net_dns.o net_arp.o net_api.o + +CFEOBJS = +## cfe_iocb_dispatch.o cfe_devfuncs.o \ cfe_console.o cfe_timer.o cfe_attach.o cfe_background.o cfe_zlibfs.o +## cfe_mem.o +## cfe_error.o build_date.o \ +## cfe_rawfs.o cfe_xreq.o cfe_filesys.o +## cfe_fatfs.o cfe_httpfs.o cfe_ldr_srec.o cfe_autoboot.o cfe_boot.o cfe_ldr_elf.o cfe_ldr_raw.o cfe_loader.o +## cfe_main.o nvram_subr.o url.o cfe_savedata.o env_subr.o +UIOBJS = +##ui_command.o ui_cmddisp.o +## ui_pcicmds.o \ui_tcpcmds.o ui_memcmds.o ui_loadcmds.o ui_flash.o ui_netcmds.o ui_envcmds.o ui_devcmds.o +## ui_examcmds.o ui_misccmds.o \ +## ui_test_disk.o ui_test_ether.o ui_test_flash.o ui_test_uart.o + +# +# Add more object files if we're supporting PCI +# + +ifeq ($(strip ${CFG_PCI}),1) +PCIOBJS = pciconf.o ldtinit.o pci_subr.o +PCIOBJS += pci_devs.o +DEVOBJS += dev_sp1011.o dev_ht7520.o +DEVOBJS += dev_ide_pci.o dev_ns16550_pci.o +DEVOBJS += dev_tulip.o dev_dp83815.o +CFLAGS += -DCFG_PCI=1 +ifeq ($(strip ${CFG_LDT_REV_017}),1) +CFLAGS += -DCFG_LDT_REV_017=1 +endif +ifeq ($(strip ${CFG_DOWNLOAD}),1) +DEVOBJS += dev_bcm1250.o download.data +CFLAGS += -DCFG_DOWNLOAD=1 +endif +endif + +# +# If doing bi-endian, add the compiler switch to change +# the way the vectors are generated. These switches are +# only added to the big-endian portion of the ROM, +# which is located at the real boot vector. +# + +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),0) + CFLAGS += -DCFG_BIENDIAN=1 + endif +endif + +# +# Include the makefiles for the architecture-common, cpu-specific, +# and board-specific directories. Each of these will supply +# some files to "ALLOBJS". The BOARD directory is optional +# as some ports are so simple they don't need boad-specific stuff. +# + +include ${ARCH_SRC}/Makefile +include ${CPU_SRC}/Makefile + +ifneq ("$(strip ${BOARD})","") +include ${BOARD_SRC}/Makefile +endif + +# +# Add the common object files here. +# + +ALLOBJS += $(LIBOBJS) $(DEVOBJS) $(CFEOBJS) $(VENOBJS) $(UIOBJS) $(NETOBJS) +#$(PCIOBJS) + +# +# VAPI continues to be a special case. +# + +ifeq ($(strip ${CFG_VAPI}),1) +include ${TOP}/verif/Makefile +endif + +# +# USB support +# + +ifeq ($(strip ${CFG_USB}),1) +SRCDIRS += ${TOP}/usb +CFE_INC += ${TOP}/usb +include ${TOP}/usb/Makefile +endif + +# +# If we're doing the VGA console thing, pull in the x86 emulator +# and the pcconsole subsystem +# + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +include ${TOP}/x86emu/Makefile +include ${TOP}/pccons/Makefile +endif + +# +# If we're including ZLIB, then add its makefile. +# + +##ifeq ($(strip ${CFG_ZLIB}),1) +##include ${TOP}/zlib/Makefile +CFLAGS += -DCFG_ZLIB=1 -DMY_ZCALLOC -DNO_MEMCPY +##endif + +.PHONY : all +.PHONY : ALL +.PHONY : build_date.c + +# +# Build the local tools that we use to construct other source files +# + +mkpcidb : ${TOP}/hosttools/mkpcidb.c + gcc -o mkpcidb ${TOP}/hosttools/mkpcidb.c + +memconfig : ${TOP}/hosttools/memconfig.c + gcc -o memconfig -D_MCSTANDALONE_ -D_MCSTANDALONE_NOISY_ -I${TOP}/arch/mips/cpu/sb1250/include ${TOP}/hosttools/memconfig.c ${TOP}/arch/${ARCH}/cpu/${CPU}/src/sb1250_draminit.c + +pcidevs_data2.h : mkpcidb ${TOP}/pci/pcidevs_data.h + ./mkpcidb > pcidevs_data2.h + +mkflashimage : ${TOP}/hosttools/mkflashimage.c + gcc -o mkflashimage -I${TOP}/include ${TOP}/hosttools/mkflashimage.c + +pci_subr.o : ${TOP}/pci/pci_subr.c pcidevs_data2.h + +##build_date.c : +## echo "const char *builddate = \"`date`\";" > build_date.c +## echo "const char *builduser = \"`whoami`@`hostname`\";" >> build_date.c + +# +# Make a define for the board name +# + +CFLAGS += -D_$(patsubst "%",%,${CFG_BOARDNAME})_ + +LIBCFE = libcfe.a + +%.o : %.c + $(GCC) $(CFLAGS) -o $@ $< + +%.o : %.S + $(GCC) $(CFLAGS) -o $@ $< + +# +# This rule constructs "libcfe.a" which contains most of the object +# files. +# + +$(LIBCFE) : $(ALLOBJS) + rm -f $(LIBCFE) + $(AR) cr $(LIBCFE) $(ALLOBJS) + $(RANLIB) $(LIBCFE) + + + + diff --git a/cfe/cfe/arch/mips/common/include/addrspace.h b/cfe/cfe/arch/mips/common/include/addrspace.h new file mode 100644 index 0000000..6330851 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/addrspace.h @@ -0,0 +1,63 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Address space macros File: addrspace.h + * + * Macros to deal with physical, virtual, and uncached addresses. + * for MIPS, these map to the appropriate KSEG0/KSEG1 macros + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" + +#define PHYSADDR(x) K0_TO_PHYS(x) + +/* If running uncached, force all kernel addresses to be uncached */ +#if CFG_RUNFROMKSEG0 +#define KERNADDR(x) PHYS_TO_K0(x) +#else +#define KERNADDR(x) PHYS_TO_K1(x) +#endif + +#define UNCADDR(x) PHYS_TO_K1(x) + + + diff --git a/cfe/cfe/arch/mips/common/include/disasm.h b/cfe/cfe/arch/mips/common/include/disasm.h new file mode 100644 index 0000000..8a8e7b7 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/disasm.h @@ -0,0 +1,61 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * MIPS disassembler File: disasm.h + * + * MIPS disassembler (used by ui_examcmds.c) + * + * Author: Justin Carlson (carlson@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef DISASM_H +#define DISASM_H + +/* Returns a pointer to a read-only string containing the intstruction name */ +char *disasm_inst_name(uint32_t inst); + +/* Copies a disassembled version of the instruction into buf, null terminating the +string. Will not exceed buf_size bytes written; if the disassembled string is +longer than buf_size, buf_size-1 bytes of the string will be written and that string +will be null-terminated */ +void disasm_inst(char *buf, int buf_size, uint32_t inst, uint64_t pc); +#endif + + + diff --git a/cfe/cfe/arch/mips/common/include/exception.h b/cfe/cfe/arch/mips/common/include/exception.h new file mode 100644 index 0000000..70e87c2 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/exception.h @@ -0,0 +1,223 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Exception/trap handler defs File: exception.h + * + * This module describes the exception handlers, exception + * trap frames, and dispatch. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifdef __ASSEMBLER__ +#define _XAIDX(x) (8*(x)) +#else +#define _XAIDX(x) (x) +#endif + + +/* ********************************************************************* + * Exception vectors from the MIPS specification + ********************************************************************* */ + +#define MIPS_ROM_VEC_RESET 0x0000 +#define MIPS_ROM_VEC_TLBFILL 0x0200 +#define MIPS_ROM_VEC_XTLBFILL 0x0280 +#define MIPS_ROM_VEC_CACHEERR 0x0300 +#define MIPS_ROM_VEC_EXCEPTION 0x0380 +#define MIPS_ROM_VEC_INTERRUPT 0x0400 +#define MIPS_ROM_VEC_EJTAG 0x0480 + +#define MIPS_RAM_VEC_TLBFILL 0x0000 +#define MIPS_RAM_VEC_XTLBFILL 0x0080 +#define MIPS_RAM_VEC_EXCEPTION 0x0180 +#define MIPS_RAM_VEC_INTERRUPT 0x0200 +#define MIPS_RAM_VEC_CACHEERR 0x0100 +#define MIPS_RAM_VEC_END 0x0300 + +#define MIPS_RAM_EXL_VEC_TLBFILL 0x0100 +#define MIPS_RAM_EXL_VEC_XTLBFILL 0x0180 + + +/* ********************************************************************* + * Fixed locations of other low-memory objects. We stuff some + * important data in the spaces between the vectors. + ********************************************************************* */ + +#define CFE_LOCORE_GLOBAL_GP 0x0040 /* our "handle" */ +#define CFE_LOCORE_GLOBAL_SP 0x0048 /* Stack pointer for exceptions */ +#define CFE_LOCORE_GLOBAL_K0TMP 0x0050 /* Used by cache error handler */ +#define CFE_LOCORE_GLOBAL_K1TMP 0x0058 /* Used by cache error handler */ +#define CFE_LOCORE_GLOBAL_RATMP 0x0060 /* Used by cache error handler */ +#define CFE_LOCORE_GLOBAL_GPTMP 0x0068 /* Used by cache error handler */ +#define CFE_LOCORE_GLOBAL_CERRH 0x0070 /* Pointer to cache error handler */ + +#define CFE_LOCORE_GLOBAL_T0TMP 0x0240 /* used by cache error handler */ +#define CFE_LOCORE_GLOBAL_T1TMP 0x0248 /* used by cache error handler */ +#define CFE_LOCORE_GLOBAL_T2TMP 0x0250 /* used by cache error handler */ +#define CFE_LOCORE_GLOBAL_T3TMP 0x0258 /* used by cache error handler */ + +/* ********************************************************************* + * Offsets into our exception handler table. + ********************************************************************* */ + +#define XTYPE_RESET 0 +#define XTYPE_TLBFILL 8 +#define XTYPE_XTLBFILL 16 +#define XTYPE_CACHEERR 24 +#define XTYPE_EXCEPTION 32 +#define XTYPE_INTERRUPT 40 +#define XTYPE_EJTAG 48 + +/* ********************************************************************* + * Exception frame definitions. + ********************************************************************* */ + +/* + * The exception frame is divided up into pieces, representing the different + * parts of the processor that the data comes from: + * + * CP0: Words 0..7 + * Int Regs: Words 8..41 + * FP Regs: Words 42..73 + * Total size: 74 words + */ + +#define EXCEPTION_SIZE _XAIDX(74) + +#define XCP0_BASE 0 +#define XGR_BASE 8 +#define XFR_BASE 42 + +#define _XCP0IDX(x) _XAIDX((x)+XCP0_BASE) +#define XCP0_SR _XCP0IDX(0) +#define XCP0_CAUSE _XCP0IDX(1) +#define XCP0_EPC _XCP0IDX(2) +#define XCP0_VADDR _XCP0IDX(3) +#define XCP0_PRID _XCP0IDX(4) + +#define _XGRIDX(x) _XAIDX((x)+XGR_BASE) +#define XGR_ZERO _XGRIDX(0) +#define XGR_AT _XGRIDX(1) +#define XGR_V0 _XGRIDX(2) +#define XGR_V1 _XGRIDX(3) +#define XGR_A0 _XGRIDX(4) +#define XGR_A1 _XGRIDX(5) +#define XGR_A2 _XGRIDX(6) +#define XGR_A3 _XGRIDX(7) +#define XGR_T0 _XGRIDX(8) +#define XGR_T1 _XGRIDX(9) +#define XGR_T2 _XGRIDX(10) +#define XGR_T3 _XGRIDX(11) +#define XGR_T4 _XGRIDX(12) +#define XGR_T5 _XGRIDX(13) +#define XGR_T6 _XGRIDX(14) +#define XGR_T7 _XGRIDX(15) +#define XGR_S0 _XGRIDX(16) +#define XGR_S1 _XGRIDX(17) +#define XGR_S2 _XGRIDX(18) +#define XGR_S3 _XGRIDX(19) +#define XGR_S4 _XGRIDX(20) +#define XGR_S5 _XGRIDX(21) +#define XGR_S6 _XGRIDX(22) +#define XGR_S7 _XGRIDX(23) +#define XGR_T8 _XGRIDX(24) +#define XGR_T9 _XGRIDX(25) +#define XGR_K0 _XGRIDX(26) +#define XGR_K1 _XGRIDX(27) +#define XGR_GP _XGRIDX(28) +#define XGR_SP _XGRIDX(29) +#define XGR_FP _XGRIDX(30) +#define XGR_RA _XGRIDX(31) +#define XGR_LO _XGRIDX(32) +#define XGR_HI _XGRIDX(33) + + +#define _XFRIDX(x) _XAIDX((x)+XFR_BASE) +#define XR_F0 _XFRIDX(0) +#define XR_F1 _XFRIDX(1) +#define XR_F2 _XFRIDX(2) +#define XR_F3 _XFRIDX(3) +#define XR_F4 _XFRIDX(4) +#define XR_F5 _XFRIDX(5) +#define XR_F6 _XFRIDX(6) +#define XR_F7 _XFRIDX(7) +#define XR_F8 _XFRIDX(8) +#define XR_F9 _XFRIDX(9) +#define XR_F10 _XFRIDX(10) +#define XR_F11 _XFRIDX(11) +#define XR_F12 _XFRIDX(12) +#define XR_F13 _XFRIDX(13) +#define XR_F14 _XFRIDX(14) +#define XR_F15 _XFRIDX(15) +#define XR_F16 _XFRIDX(16) +#define XR_F17 _XFRIDX(17) +#define XR_F18 _XFRIDX(18) +#define XR_F19 _XFRIDX(19) +#define XR_F20 _XFRIDX(20) +#define XR_F21 _XFRIDX(21) +#define XR_F22 _XFRIDX(22) +#define XR_F23 _XFRIDX(23) +#define XR_F24 _XFRIDX(24) +#define XR_F25 _XFRIDX(25) +#define XR_F26 _XFRIDX(26) +#define XR_F27 _XFRIDX(27) +#define XR_F28 _XFRIDX(28) +#define XR_F29 _XFRIDX(29) +#define XR_F30 _XFRIDX(30) +#define XR_F31 _XFRIDX(31) +#define XR_FCR _XFRIDX(32) +#define XR_FID _XFRIDX(33) + + +#ifndef __ASSEMBLER__ +extern void _exc_setvector(int vectype, void *vecaddr); +extern void _exc_crash_sim(void); +extern void _exc_cache_crash_sim(void); +extern void _exc_restart(void); +extern void _exc_clear_sr_exl(void); +extern void _exc_clear_sr_erl(void); +void cfe_exception(int code,uint64_t *info); +void cfe_setup_exceptions(void); +#endif + + + + + diff --git a/cfe/cfe/arch/mips/common/include/exchandler.h b/cfe/cfe/arch/mips/common/include/exchandler.h new file mode 100644 index 0000000..af268f1 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/exchandler.h @@ -0,0 +1,85 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Exception Handler definitions File: exchandler.h + * + * Exception handler functions and constants + * + * Author: Binh Vo (binh@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _LIB_SETJMP_H +#include "lib_setjmp.h" +#endif + +#ifndef _LIB_QUEUE_H +#include "lib_queue.h" +#endif + +#define MEM_BYTE 1 +#define MEM_HALFWORD 2 +#define MEM_WORD 3 +#define MEM_QUADWORD 4 + +#define EXC_NORMAL_RETURN 0 +#define EXC_CHAIN_EXC 1 + +typedef struct jmpbuf_s { + queue_t stack; + jmp_buf jmpbuf; +} jmpbuf_t; + +typedef struct exc_handler_s { + int catch_exc; + int chain_exc; + queue_t jmpbuf_stack; +} exc_handler_t; + +extern exc_handler_t exc_handler; + +jmpbuf_t *exc_initialize_block(void); +void exc_cleanup_block(jmpbuf_t *); +void exc_cleanup_handler(jmpbuf_t *, int); +void exc_longjmp_handler(void); +int mem_peek(void*, long, int); +int mem_poke(long, uint64_t, int); + + +#define exc_try(jb) (lib_setjmp(((jb)->jmpbuf))) diff --git a/cfe/cfe/arch/mips/common/include/initdata.h b/cfe/cfe/arch/mips/common/include/initdata.h new file mode 100644 index 0000000..c5fc0d8 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/initdata.h @@ -0,0 +1,68 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Data stored in initialization module File: initdata.h + * + * This file contains data declared by the init module. It also + * contains externs for that data so we can keep the types straight. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#if defined(__ASSEMBLER__) +#define DECLARE_INITVAR(x) \ + .globl x ; \ +x: _LONG_ 0 +#else +#define DECLARE_INITVAR(x) \ + extern long x; +#endif + +DECLARE_INITVAR(mem_textreloc) +DECLARE_INITVAR(mem_textbase) +DECLARE_INITVAR(mem_textsize) +DECLARE_INITVAR(mem_totalsize) +DECLARE_INITVAR(mem_topofmem) +DECLARE_INITVAR(mem_heapstart) +DECLARE_INITVAR(mem_bottomofmem) +DECLARE_INITVAR(mem_datareloc) +DECLARE_INITVAR(cpu_prid) + + diff --git a/cfe/cfe/arch/mips/common/include/lib_hssubr.h b/cfe/cfe/arch/mips/common/include/lib_hssubr.h new file mode 100644 index 0000000..b4df439 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/lib_hssubr.h @@ -0,0 +1,84 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "Hyperspace" access routines File: lib_hssubr.h + * + * Constants, macros, and definitions for routines to deal with + * hyperspace (beyond 256MB) on MIPS processors. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _LIB_HSSUBR_H +#define _LIB_HSSUBR_H + +/* + * If __long64 we can do this via macros. Otherwise, call + * the magic functions. + */ + +#if __long64 + +typedef long hsaddr_t; + +#define hs_write8(a,b) *((volatile uint8_t *) (a)) = (b) +#define hs_write16(a,b) *((volatile uint16_t *) (a)) = (b) +#define hs_write32(a,b) *((volatile uint32_t *) (a)) = (b) +#define hs_write64(a,b) *((volatile uint32_t *) (a)) = (b) +#define hs_read8(a) *((volatile uint8_t *) (a)) +#define hs_read16(a) *((volatile uint16_t *) (a)) +#define hs_read32(a) *((volatile uint32_t *) (a)) +#define hs_read64(a) *((volatile uint64_t *) (a)) + +#else /* not __long64 */ + +typedef long long hsaddr_t; + +extern void hs_write8(hsaddr_t a,uint8_t b); +extern void hs_write16(hsaddr_t a,uint16_t b); +extern void hs_write32(hsaddr_t a,uint32_t b); +extern void hs_write64(hsaddr_t a,uint64_t b); +extern uint8_t hs_read8(hsaddr_t a); +extern uint16_t hs_read16(hsaddr_t a); +extern uint32_t hs_read32(hsaddr_t a); +extern uint64_t hs_read64(hsaddr_t a); +#endif + +#endif diff --git a/cfe/cfe/arch/mips/common/include/lib_physio.h b/cfe/cfe/arch/mips/common/include/lib_physio.h new file mode 100644 index 0000000..00d0093 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/lib_physio.h @@ -0,0 +1,100 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Physical memory peek/poke routines File: lib_physio.h + * + * Little stub routines to allow access to arbitrary physical + * addresses. In most cases this should not be needed, as + * many physical addresses are within kseg1, but this handles + * the cases that are not automagically, so we don't need + * to mess up the code with icky macros and such. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _LIB_PHYSIO_H +#define _LIB_PHYSIO_H + +//#ifndef _SB_MIPS_H +//#include "sbmips.h" +//#endif + +/* + * If __long64 we can do this via macros. Otherwise, call + * the magic functions. + */ + +#if __long64 + +typedef long physaddr_t; +#define _PHYSADDR_T_DEFINED_ + +/*#define __UNCADDRX(x) PHYS_TO_XKSEG_UNCACHED(x)*/ +#define __UNCADDRX(x) (((physaddr_t)(x))|0x9000000000000000) + + +#define phys_write8(a,b) *((volatile uint8_t *) __UNCADDRX(a)) = (b) +#define phys_write16(a,b) *((volatile uint16_t *) __UNCADDRX(a)) = (b) +#define phys_write32(a,b) *((volatile uint32_t *) __UNCADDRX(a)) = (b) +#define phys_write64(a,b) *((volatile uint64_t *) __UNCADDRX(a)) = (b) +#define phys_read8(a) *((volatile uint8_t *) __UNCADDRX(a)) +#define phys_read16(a) *((volatile uint16_t *) __UNCADDRX(a)) +#define phys_read32(a) *((volatile uint32_t *) __UNCADDRX(a)) +#define phys_read64(a) *((volatile uint64_t *) __UNCADDRX(a)) + +#else /* not __long64 */ + +#ifdef _MIPSREGS32_ +typedef long physaddr_t; /* 32-bit-only processors can't have >32bit pa's */ +#else +typedef long long physaddr_t; /* Otherwise, they might. */ +#endif + +extern void phys_write8(physaddr_t a,uint8_t b); +extern void phys_write16(physaddr_t a,uint16_t b); +extern void phys_write32(physaddr_t a,uint32_t b); +extern void phys_write64(physaddr_t a,uint64_t b); +extern uint8_t phys_read8(physaddr_t a); +extern uint16_t phys_read16(physaddr_t a); +extern uint32_t phys_read32(physaddr_t a); +extern uint64_t phys_read64(physaddr_t a); +#endif + +#endif diff --git a/cfe/cfe/arch/mips/common/include/lib_setjmp.h b/cfe/cfe/arch/mips/common/include/lib_setjmp.h new file mode 100644 index 0000000..b673222 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/lib_setjmp.h @@ -0,0 +1,81 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * setjmp/longjmp defs File: lib_setjmp.h + * + * Description of the jmp_buf structure for setjmp and longjmp + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* + * Note that while lib_setjmp() and lib_longjmp() behave like setjmp() + * and longjmp() normally do, gcc 3.1.x (and later) assumes things about + * how setjmp() and longjmp() should work (even with -fno-builtins). We + * don't want it to do those, so these functions must be named differently. + */ + +#ifdef __ASSEMBLER__ +#define _JBIDX(x) (8*(x)) +#else +#define _JBIDX(x) (x) +#endif + + +#define JMPB_S0 _JBIDX(0) +#define JMPB_S1 _JBIDX(1) +#define JMPB_S2 _JBIDX(2) +#define JMPB_S3 _JBIDX(3) +#define JMPB_S4 _JBIDX(4) +#define JMPB_S5 _JBIDX(5) +#define JMPB_S6 _JBIDX(6) +#define JMPB_S7 _JBIDX(7) +#define JMPB_FP _JBIDX(8) +#define JMPB_SP _JBIDX(9) +#define JMPB_RA _JBIDX(10) + +#define JMPB_SIZE _JBIDX(11) + +#ifndef __ASSEMBLER__ +typedef long long jmp_buf[JMPB_SIZE]; +extern int lib_setjmp(jmp_buf); +extern void lib_longjmp(jmp_buf,int val); +#endif + diff --git a/cfe/cfe/arch/mips/common/include/mipsmacros.h b/cfe/cfe/arch/mips/common/include/mipsmacros.h new file mode 100755 index 0000000..072a5e6 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/mipsmacros.h @@ -0,0 +1,376 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * MIPS Macros File: mipsmacros.h + * + * Macros to deal with various mips-related things. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * 32/64-bit macros + ********************************************************************* */ + +#ifdef __long64 +#define _VECT_ .dword +#define _LONG_ .dword +#define SR sd +#define LR ld +#define ADD dadd +#define SUB dsub +#define MFC0 dmfc0 +#define MTC0 dmtc0 +#define REGSIZE 8 +#define BPWSIZE 3 /* bits per word size */ +#define _TBLIDX(x) ((x)*REGSIZE) +#else +#define _VECT_ .word +#define _LONG_ .word +#define SR sw +#define LR lw +#define ADD add +#define SUB sub +#define MFC0 mfc0 +#define MTC0 mtc0 +#define REGSIZE 4 +#define BPWSIZE 2 +#define _TBLIDX(x) ((x)*REGSIZE) +#endif + + +/* ********************************************************************* + * NORMAL_VECTOR(addr,vecname,vecdest) + * NORMAL_XVECTOR(addr,vecname,vecdest,code) + * + * Declare a trap or dispatch vector. There are two flavors, + * DECLARE_XVECTOR sets up an indentifying code in k0 before + * jumping to the dispatch routine. + * + * Input parameters: + * addr - vector address + * vecname - for label at that address + * vecdest - destination (place vector jumps to) + * code - code to place in k0 before jumping + * + * Return value: + * nothing + ********************************************************************* */ + + +#define NORMAL_VECTOR(addr,vecname,vecdest) \ + .globl vecname ; \ + .org addr ; \ +vecname: b vecdest ; \ + nop; + +#define NORMAL_XVECTOR(addr,vecname,vecdest,code) \ + .globl vecname ; \ + .org addr ; \ +vecname: b vecdest ; \ + li k0,code ; \ + nop; + + +/* ********************************************************************* + * Evil macros for bi-endian support. + * + * The magic here is in the instruction encoded as 0x10000014. + * + * This instruction in big-endian is: "b .+0x54" + * this instruction in little-endian is: "bne zero,zero,.+0x44" + * + * So, depending on what the system endianness is, it will either + * branch to .+0x54 or not branch at all. + * + * the instructions that follow are: + * + * 0x10000014 "magic branch" (either-endian) + * 0x00000000 nop (bds) (either-endian) + * 0xD0BF1A3C lui k0,0xBFD0 (little-endian) + * 0xxxxx5A27 addu k0,vector (little-endian) + * 0x08004003 jr k0 (little-endian) + * 0x00000000 nop (bds) (little-endian) + * ... space up to offset 0x54 + * ......... b vecaddr (big-endian) + * + * The idea is that the big-endian firmware is first, from 0..1MB + * in the flash, and the little-endian firmware is second, + * from 1..2MB in the flash. The little-endian firmware is + * set to load at BFD00000, so that its initial routines will + * work until relocation is completed. + * + * the instructions at the vectors will either jump to the + * big-endian or little-endian code based on system endianness. + * + * The ROM is built by compiling CFE twice, first with + * CFG_BIENDIAN=1 and CFG_LITTLE=0 (big-endian) and again + * with CFG_BIENDIAN=1 and CFG_LITTLE=1. The resulting + * cfe.bin files are located at 0xBFC00000 and 0xBFD00000 + * for big and little-endian versions, respectively. + * + * More information about how this works can be found in the + * CFE Manual. + ********************************************************************* */ + +#define __SWAPW(x) ((((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8)) + +#define BIENDIAN_VECTOR(addr,vecname,vecdest) \ + .globl vecname ; \ + .org addr ; \ +vecname: .word 0x10000014 ; \ + .word 0 ; \ + .word ((__SWAPW(BIENDIAN_LE_BASE >> 16)) << 16) | 0x1A3C ; \ + .word (0x00005A27 | (((addr) & 0xFF) << 24) | (((addr) & 0xFF00) << 8)) ; \ + .word 0x08004003 ; \ + .word 0 ; \ + .org ((addr) + 0x54) ; \ + b vecdest ; \ + nop; + +#define BIENDIAN_XVECTOR(addr,vecname,vecdest,code) \ + .globl vecname ; \ + .org addr ; \ +vecname: .word 0x10000014 ; \ + .word 0 ; \ + .word ((__SWAPW(BIENDIAN_LE_BASE >> 16)) << 16) | 0x1A3C ; \ + .word (0x00005A27 | (((addr) & 0xFF) << 24) | (((addr) & 0xFF00) << 8)) ; \ + .word 0x08004003 ; \ + .word 0 ; \ + .org ((addr) + 0x54) ; \ + b vecdest ; \ + li k0,code ; \ + nop; + + + +/* ********************************************************************* + * Declare the right versions of DECLARE_VECTOR and + * DECLARE_XVECTOR depending on how we're building stuff. + * Generally, we only use the biendian version if we're building + * as CFG_BIENDIAN=1 and we're doing the big-endian MIPS version. + ********************************************************************* */ + +#if (CFG_BIENDIAN) && defined(__MIPSEB) +#define DECLARE_VECTOR BIENDIAN_VECTOR +#define DECLARE_XVECTOR BIENDIAN_XVECTOR +#else +#define DECLARE_VECTOR NORMAL_VECTOR +#define DECLARE_XVECTOR NORMAL_XVECTOR +#endif + + + +/* ********************************************************************* + * LOADREL(reg,label) + * + * Load the address of a label, but do it in a position-independent + * way. + * + * Input parameters: + * reg - register to load + * label - label whose address to load + * + * Return value: + * ra is trashed! + ********************************************************************* */ + +#if (!(CFG_RAMAPP)) +#define LOADREL(reg,label) \ + la reg, label ; \ + la ra, 100f ; \ + sub reg, ra ; \ + .set push ; \ + .set noreorder ; \ + bal 100f ; \ + nop ; \ + .set pop ; \ +100: ; \ + addu reg, ra +#else +#define LOADREL(reg,label) \ + la reg,label +#endif + +#if (CFG_RAMAPP) +#define FIXUP(addr) +#else +#define FIXUP(addr) \ + addu addr, s6 +#endif + + + +/* ********************************************************************* + * CALLINIT_KSEG1(label,table,offset) + * CALLINIT_KSEG0(label,table,offset) + * + * Call an initialization routine (usually in another module). + * If initialization routine lives in KSEG1 it may need + * special fixing if using the cached version of CFE (this is + * the default case). CFE is linked at a KSEG0 address. + * + * Embedded PIC is especially tricky, since the "la" + * instruction expands to calculations involving GP. + * In that case, use our table of offsets to + * load the routine address from a table in memory. + * + * Input parameters: + * label - routine to call if we can call directly + * table - symbol name of table containing routine addresses + * offset - offset within the above table + * + * Return value: + * k1,ra is trashed. + ********************************************************************* */ + + +#if CFG_RUNFROMKSEG0 +/* Cached PIC code - call indirect through table */ +#define CALLINIT_KSEG1(table,tableoffset) \ + LOADREL(k1,table) ; \ + or k1,K1BASE ; \ + LR k1,tableoffset(k1) ; \ + FIXUP (k1); \ + or k1,K1BASE ; \ + jal k1 +#define CALLINIT_KSEG0(table,tableoffset) \ + LOADREL(k1,table) ; \ + LR k1,tableoffset(k1) ; \ + FIXUP (k1); \ + jal k1 +#else +/* Uncached PIC code - call indirect through table, always same KSEG */ +#define CALLINIT_KSEG1(table,tableoffset) \ + LOADREL(k1,table) ; \ + LR k1,tableoffset(k1) ; \ + FIXUP (k1); \ + jal k1 +#define CALLINIT_KSEG0 CALLINIT_KSEG1 +#endif + +/* + * CALLINIT_RELOC is used once CFE's relocation is complete and + * the "mem_textreloc" variable is set up. (yes, this is nasty.) + * If 'gp' is set, we can presume that we've relocated + * and it's safe to read "mem_textreloc", otherwise use the + * address as-is from the table. + */ + +#define CALLINIT_RELOC CALLINIT_KSEG0 + +/* ********************************************************************* + * SPIN_LOCK(lock,reg1,reg2) + * + * Acquire a spin lock. + * + * Input parameters: + * lock - symbol (address) of lock to acquire + * reg1,reg2 - registers we can use to acquire lock + * + * Return value: + * nothing (lock acquired) + ********************************************************************* */ + +#define SPIN_LOCK(lock,reg1,reg2) \ + la reg1,lock ; \ +1: sync ; \ + ll reg2,0(reg1) ; \ + bne reg2,zero,1b ; \ + li reg2,1 ; \ + sc reg2,0(reg1) ; \ + beq reg2,zero,1b ; \ + nop + +/* ********************************************************************* + * SPIN_UNLOCK(lock,reg1) + * + * Release a spin lock. + * + * Input parameters: + * lock - symbol (address) of lock to release + * reg1 - a register we can use + * + * Return value: + * nothing (lock released) + ********************************************************************* */ + + +#define SPIN_UNLOCK(lock,reg1) \ + la reg1,lock ; \ + sw zero,0(reg1) + + +/* ********************************************************************* + * SETCCAMODE(treg,mode) + * + * Set cacheability mode. For some of the pass1 workarounds we + * do this alot, so here's a handy macro. + * + * Input parameters: + * treg - temporary register we can use + * mode - new mode (K_CFG_K0COH_xxx) + * + * Return value: + * nothing + ********************************************************************* */ + +#define SETCCAMODE(treg,mode) \ + mfc0 treg,C0_CONFIG ; \ + srl treg,treg,3 ; \ + sll treg,treg,3 ; \ + or treg,treg,mode ; \ + mtc0 treg,C0_CONFIG ; \ + HAZARD + + +/* ********************************************************************* + * Declare variables + ********************************************************************* */ + +#define DECLARE_LONG(x) \ + .global x ; \ +x: _LONG_ 0 + + + + +/* + * end + */ diff --git a/cfe/cfe/arch/mips/common/include/segtable.h b/cfe/cfe/arch/mips/common/include/segtable.h new file mode 100755 index 0000000..8a003f0 --- /dev/null +++ b/cfe/cfe/arch/mips/common/include/segtable.h @@ -0,0 +1,97 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Segment Table definitions File: segtable.h + * + * The 'segment table' (bad name) is just a list of addresses + * of important stuff used during initialization. We use these + * indirections to make life less complicated during code + * relocation. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#if !defined(__ASSEMBLER__) +#define _TBLIDX(x) (x) /* C handles indexing for us */ +typedef long segtable_t; /* 32 for long32, 64 for long64 */ +#endif + +/* + * Definitions for the segment_table + */ + +#define R_SEG_ETEXT _TBLIDX(0) /* end of text segment */ +#define R_SEG_FDATA _TBLIDX(1) /* Beginning of data segment */ +#define R_SEG_EDATA _TBLIDX(2) /* end of data segment */ +#define R_SEG_END _TBLIDX(3) /* End of BSS */ +#define R_SEG_FTEXT _TBLIDX(4) /* Beginning of text segment */ +#define R_SEG_FBSS _TBLIDX(5) /* Beginning of BSS */ +#define R_SEG_GP _TBLIDX(6) /* Global Pointer */ +#define R_SEG_RELOCSTART _TBLIDX(7) /* Start of reloc table */ +#define R_SEG_RELOCEND _TBLIDX(8) /* End of reloc table */ +#define R_SEG_APIENTRY _TBLIDX(9) /* API Entry address */ + +/* + * Definitions for the init_table + */ + +#define R_INIT_EARLYINIT _TBLIDX(0) /* pointer to board_earlyinit */ +#define R_INIT_SETLEDS _TBLIDX(1) /* pointer to board_setleds */ +#define R_INIT_DRAMINFO _TBLIDX(2) /* pointer to board_draminfo */ +#define R_INIT_CPUINIT _TBLIDX(3) /* pointer tp cpuinit */ +#define R_INIT_ALTCPU_START1 _TBLIDX(4) /* pointer to altcpu_start1 */ +#define R_INIT_ALTCPU_START2 _TBLIDX(5) /* pointer to altcpu_start2 */ +#define R_INIT_ALTCPU_RESET _TBLIDX(6) /* pointer to altcpu_reset */ +#define R_INIT_CPURESTART _TBLIDX(7) /* pointer to cpurestart */ +#define R_INIT_DRAMINIT _TBLIDX(8) /* pointer to draminit */ +#define R_INIT_CACHEOPS _TBLIDX(9) /* pointer to cacheops */ +#define R_INIT_TLBHANDLER _TBLIDX(10) /* pointer to TLB fault handler */ +#define R_INIT_CMDSTART _TBLIDX(11) /* pointer to cfe_main */ +#define R_INIT_CMDRESTART _TBLIDX(12) /* pointer to cfe_cmd_restart */ +#define R_INIT_DOXREQ _TBLIDX(13) /* pointer to cfe_doxreq */ +#define R_INIT_TP1_SWITCH _TBLIDX(14) /* pointer to tp1_switch */ +#define R_INIT_SIZERAM _TBLIDX(15) /* pointer to board_sizeram */ + +/* + * Definitions for the diag_table + */ + +#define R_DIAG_TEST1 _TBLIDX(0) /* after CPU and cache init, before DRAM init */ +#define R_DIAG_TEST2 _TBLIDX(1) /* after DRAM init, before main */ diff --git a/cfe/cfe/arch/mips/common/src/Makefile b/cfe/cfe/arch/mips/common/src/Makefile new file mode 100755 index 0000000..638113d --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/Makefile @@ -0,0 +1,38 @@ + +# +# This is just a Makefile fragment -- it is included by the master +# makefile, cfe.mk +# +# This file should just append object file names to "ALLOBJS", +# but since it is mean to be linked *first*, it will append +# modules to "CRT0OBJS" +# + +ifndef INIT_MIPS +INIT_MIPS = init_mips.o +endif + +ifeq ($(strip ${CFG_RAMAPP}),1) +CRT0OBJS += init_ram.o exception.o +else +CRT0OBJS += $(INIT_MIPS) +endif + +ifeq ($(strip ${CFG_RAMAPP}),1) +ALLOBJS += lib_hssubr.o lib_setjmp.o mips_arena.o exchandler.o +ALLOBJS += dev_flash_all.o dev_flashop_engine.o +ALLOBJS += ui_memtest.o +endif + +makereg : ${TOP}/hosttools/makereg.c + gcc -o makereg ${TOP}/hosttools/makereg.c + +%.inc : %.regdef makereg + ./makereg $< $@ + +ui_soccmds.o : ${CPU_SRC}/ui_soccmds.c ${CPU}_socregs.inc + +vapi.o : ${TOP}/verif/vapi.S sb1250_socregs.inc + + + diff --git a/cfe/cfe/arch/mips/common/src/cfe_ram_cached.lds b/cfe/cfe/arch/mips/common/src/cfe_ram_cached.lds new file mode 100644 index 0000000..4b8ce87 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_ram_cached.lds @@ -0,0 +1,40 @@ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0x9fc00000; /* was 0x9fc00000 */ + .text : +/* AT ( 0xBFC00000 ) */ /* was 0xbfc00000 */ + { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + *(.fini) + *(.rodata) + _etext = .; + } + + .data : + { + _fdata = ALIGN(16) ; + *(.data) + CONSTRUCTORS + . = ALIGN(16); + _gp = . + 0x8000; + *(.sdata) + } + . = ALIGN(16); + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/cfe_ram_uncached.lds b/cfe/cfe/arch/mips/common/src/cfe_ram_uncached.lds new file mode 100644 index 0000000..4295fe4 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_ram_uncached.lds @@ -0,0 +1,40 @@ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0xbfc00000; /* was 0x9fc00000 */ + .text : +/* AT ( 0xBFC00000 ) */ /* was 0xbfc00000 */ + { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + *(.fini) + *(.rodata) + _etext = .; + } + + .data : + { + _fdata = ALIGN(16) ; + *(.data) + CONSTRUCTORS + . = ALIGN(16); + _gp = . + 0x8000; + *(.sdata) + } + . = ALIGN(16); + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/cfe_ramapp.lds b/cfe/cfe/arch/mips/common/src/cfe_ramapp.lds new file mode 100755 index 0000000..5a7a377 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_ramapp.lds @@ -0,0 +1,41 @@ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0x80601000; + .text : + { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + *(.fini) + *(.rodata) + *(.rodata.str1.4) + *(.gnu.linkonce.r.*) + _etext = .; + } + + .data : + { + _fdata = ALIGN(16) ; + *(.data) + CONSTRUCTORS + . = ALIGN(16); + _gp = . + 0x8000; + *(.sdata) + } + . = ALIGN(16); + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/cfe_rom_cached.lds b/cfe/cfe/arch/mips/common/src/cfe_rom_cached.lds new file mode 100755 index 0000000..2ca1353 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_rom_cached.lds @@ -0,0 +1,40 @@ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0x80000000; + .text : + { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + *(.fini) + *(.rodata) + _etext = .; + } + + .data : + { + _fdata = ALIGN(16) ; + *(.data) + CONSTRUCTORS + . = ALIGN(16); + _gp = . + 0x8000; + *(.sdata) + } + . = ALIGN(16); + _edata = .; + .reginfo : {} + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached.lds b/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached.lds new file mode 100644 index 0000000..ee94831 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached.lds @@ -0,0 +1,43 @@ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0x9FC00000; + .text : + AT ( 0xBFC00000 ) + { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + PROVIDE (__runtime_reloc_start = .); + *(.rel.sdata) + PROVIDE (__runtime_reloc_stop = .); + *(.fini) + *(.rodata) + _etext = .; + } + .data 0x80001000 : + AT ( ((ADDR(.text)|0xB0000000) + SIZEOF ( .text ) + 15) & 0xFFFFFFF0) + { + _gp = ALIGN(16) + 0x8000; + _fdata = .; + *(.rdata) + *(.data) + CONSTRUCTORS + *(.sdata) + } + . = ALIGN(16); + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached_biendian.lds b/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached_biendian.lds new file mode 100644 index 0000000..78421a4 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_cached_biendian.lds @@ -0,0 +1,49 @@ +/* + * This linker script is exactly the same as cfe_rom_reloc_cached.lds + * except our start address is at BFD00000, 1MB into the + * ROM. We locate the little-endian version of CFE at this address + * in bi-endian ROM support. + */ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0x9FD00000; + .text : + AT ( 0xBFD00000 ) + { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + PROVIDE (__runtime_reloc_start = .); + *(.rel.sdata) + PROVIDE (__runtime_reloc_stop = .); + *(.fini) + *(.rodata) + _etext = .; + } + .data 0x80001000 : + AT ( ((ADDR(.text)|0xB0000000) + SIZEOF ( .text ) + 15) & 0xFFFFFFF0) + { + _gp = ALIGN(16) + 0x8000; + _fdata = .; + *(.rdata) + *(.data) + CONSTRUCTORS + *(.sdata) + } + . = ALIGN(16); + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_uncached.lds b/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_uncached.lds new file mode 100644 index 0000000..0c62889 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_rom_reloc_uncached.lds @@ -0,0 +1,41 @@ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0xBFC00000; + .text : { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + PROVIDE (__runtime_reloc_start = .); + *(.rel.sdata) + PROVIDE (__runtime_reloc_stop = .); + *(.fini) + *(.rodata) + _etext = .; + } + .data 0xA0001000 : + AT ( ((ADDR(.text)|0xB0000000) + SIZEOF ( .text ) + 15) & 0xFFFFFFF0) + { + _gp = ALIGN(16) + 0x8000; + _fdata = .; + *(.rdata) + *(.data) + CONSTRUCTORS + *(.sdata) + } + . = ALIGN(16); + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/cfe_rom_uncached.lds b/cfe/cfe/arch/mips/common/src/cfe_rom_uncached.lds new file mode 100644 index 0000000..a0362ba --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/cfe_rom_uncached.lds @@ -0,0 +1,39 @@ +OUTPUT_ARCH(mips) +ENTRY(vec_reset) +SECTIONS +{ + . = 0xBFC00000; + .text : { + _ftext = . ; + *(.init) + eprol = .; + *(.text) + *(.fini) + *(.rodata) + _etext = .; + } + + .data 0xA1F00000 : + AT ( ((ADDR(.text)|0xB0000000) + SIZEOF ( .text ) + 15) & 0xFFFFFFF0) + { + _fdata = ALIGN(16) ; + *(.data) + CONSTRUCTORS + . = ALIGN(16); + _gp = . + 0x8000; + *(.sdata) + } + . = ALIGN(16); + _edata = .; + _fbss = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + *(.bss) + *(COMMON) + } + . = ALIGN(16); + _end = .; +} diff --git a/cfe/cfe/arch/mips/common/src/dev_flash_all.S b/cfe/cfe/arch/mips/common/src/dev_flash_all.S new file mode 100644 index 0000000..6dbb581 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/dev_flash_all.S @@ -0,0 +1,220 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash "self-write" module File: flash_write_all.S + * + * This module takes care of the case of writing to the flash + * memory that CFE is currently reading its code from. It is + * assumed that you'll be doing a complete flash update, + * so this code erases the affected sectors, reprograms them, + * and jumps to the boot sector. + * + * Note: this code is written to be position-independent, even + * for non-PIC versions of CFE! It will be copied (with memcpy) + * into the heap for execution. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" +#include "dev_flash.h" +#include "mipsmacros.h" + +#define WRITEFLASH(base,offset,value) \ + li t0,value ; \ + sb t0,offset(base) + + +/* ********************************************************************* + * flash_write_all(data,flashbase,size,secsize) + * + * Write bytes to flash, erasing affected sectors first. + * + * Input parameters: + * a0 - data - pointer to data to write + * a1 - flashbase - base (phys addr) of flash area + * a2 - size - number of bytes to write + * a3 - secsize - flash sector size + * + * Return value: + * does not return + ********************************************************************* */ + +#define data a0 +#define flashbase a1 +#define datasize a2 +#define secsize a3 + +#define secidx t4 +#define secptr t5 + +LEAF(flash_write_all) + + /* + * Mask all interrupts. An exception with BEV set would be very bad. + */ + + mfc0 v0,C0_SR # Get current interrupt flag + li v1,M_SR_IE # master interrupt control + not v1 # disable interrupts + and v0,v1 # SR now has IE=0 + mtc0 v0,C0_SR # put back into CP0 + + /* + * Get KSEG1 addr of flash + */ + + or flashbase,K1BASE + + + /* + * Do an "unlock write" sequence (cycles 1-2) + */ + + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* + * send the erase command (cycle 3) + */ + + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3) + + /* + * Do an "unlock write" sequence (cycles 4-5) + */ + + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* + * Send the "erase all" qualifier (cycle 6) + */ + + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_ALL_6) + + /* + * Wait for the erase to complete + */ + +1: lb t0,0(secptr) # get byte + and t0,0xFF # test hi byte + bne t0,0xFF,1b # go till bit is set + + + /* + * Okay, now loop through the bytes and write them to the + * flash. + */ + + move secptr,flashbase + move secidx,datasize + +proglp: + + /* + * Do an "unlock write" sequence + */ + + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* + * Send a program command + */ + WRITEFLASH(flashbase,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM) + + /* + * Write a byte + */ + + lbu t0,0(data) + sb t0,0(secptr) # t0 = byte written to flash + + + /* + * Wait for write to complete + */ + +1: lbu t2,0(secptr) # t2 = byte from flash + + and t1,t2,0x80 # done if bit7 of flash + and t0,t0,0x80 # is same as bit7 of data + beq t1,t0,2f + + and t1,t2,0x20 # not done if bit5 + bne t1,0x20,1b # is still set +2: + + /* + * next byte... + */ + + add a0,1 # next source byte + add secptr,1 # next dest byte + sub datasize,1 # one less count + bgt datasize,0,proglp + + /* + * All done, reboot system + */ + + li v0,0xBFC00000 + j v0 + +flash_write_all_end: + nop + +END(flash_write_all) + +/* ********************************************************************* + * Data + ********************************************************************* */ + + .sdata + + .globl flash_write_all_ptr + .globl flash_write_all_len + +flash_write_all_ptr: + _VECT_ flash_write_all +flash_write_all_len: + .word flash_write_all_end-flash_write_all + + diff --git a/cfe/cfe/arch/mips/common/src/dev_flashop_engine.S b/cfe/cfe/arch/mips/common/src/dev_flashop_engine.S new file mode 100644 index 0000000..29ade6a --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/dev_flashop_engine.S @@ -0,0 +1,695 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash "self-write" module File: dev_flashop_engine.S + * + * This module takes care of the case of writing to the flash + * memory that CFE is currently reading its code from. + * + * Note: this code is written to be position-independent, even + * for non-PIC versions of CFE! It will be copied (with memcpy) + * into the heap for execution. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" +#include "mipsmacros.h" + +#include "bsp_config.h" +#include "dev_newflash.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define FLASHCMD_8(base,offset,value) \ + li t0,value ; \ + sb t0,offset(base) + +#define FLASHCMD_16(base,offset,value) \ + li t0,value ; \ + sh t0,((offset)<<1)(base) + +#define FLASHCMD_16B(base,offset,value) \ + li t0,value ; \ + sb t0,((offset)<<1)(base) + + +/* ********************************************************************* + * flashop_engine + * + * This routine is written in a PIC method to allow us to do + * flash operations without any help from CFE. We need to do + * this when we're not relocated and want to muck with the + * flash we're running from. + * + * This routine follows some simple instructions in a table, + * so you can batch up the operations in one place. + * + * Input parameters: + * a0 - pointer to instruction list + * + * Return value: + * v0 - 0 if all instructions succeeded + * else less than zero, # of failing instructions + ********************************************************************* */ + + .text + +#define reg_op t3 +#define reg_base t4 +#define reg_dest t5 +#define reg_src t6 +#define reg_cnt t7 + +LEAF(flashop_engine) + +instloop: LR reg_op,FEINST_OP(a0) /* Load instruction */ + LR reg_base,FEINST_BASE(a0) + LR reg_dest,FEINST_DEST(a0) + LR reg_src,FEINST_SRC(a0) + LR reg_cnt,FEINST_CNT(a0) + li v0,0 /* total of result values */ + li v1,0 /* result for this function */ + +#ifdef __long64 + dli t0,0x9000000000000000 /* uncached - XKPHYS */ + or reg_base,t0 /* so we can access flash beyond KSEG */ +#else + or reg_base,K1BASE /* 32-bit, regular KSEG */ +#endif + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + bne reg_op,FEOP_RETURN,99f /* Return to main prog */ + + j ra +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_REBOOT,99f /* restart system */ + + li t0,0xBFC00000 /* jump to boot vector */ + j t0 +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_READ8,99f /* Read, 8-bit mode */ + + ADD reg_src,reg_src,reg_base + +1: lbu t0,0(reg_src) /* Copy user data */ + sb t0,0(reg_dest) + ADD reg_src,1 + add reg_dest,1 + sub reg_cnt,1 + bgt reg_cnt,zero,1b + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_READ16,99f /* Read, 16-bit mode */ + + ADD reg_src,reg_src,reg_base + + li t0,1 /* test bottom bit */ + and t0,t0,reg_src /* t0 == 1 if odd */ + beq t0,zero,1f /* no odd byte to worry about */ + + SUB reg_src,reg_src,t0 /* make even value */ + lh t0,0(reg_src) /* interesting byte is odd */ +#ifdef __MIPSEB + sb t0,0(reg_dest) /* interesting byte in low 8 bits */ +#else + srl t0,t0,8 /* little endian */ + sb t0,0(reg_dest) /* interesting byte is high 8 bits */ +#endif + + ADD reg_src,2 /* advance one word (we made addr even above) */ + add reg_dest,1 /* dest always written by bytes */ + sub reg_cnt,1 + +1: beq reg_cnt,zero,nextinst + + lh t0,0(reg_src) /* Copy user data */ + +#ifdef __MIPSEB + sb t0,1(reg_dest) /* Big endian to memory */ + srl t0,t0,8 /* t0 = 0x1234 -> 0x12 0x34 */ + sb t0,0(reg_dest) +#else + sb t0,0(reg_dest) /* little endian */ + srl t0,t0,8 /* t0 = 0x1234 -> 0x34 0x12 */ + sb t0,1(reg_dest) +#endif + + ADD reg_src,2 + add reg_dest,2 + sub reg_cnt,2 + bgt reg_cnt,1,1b + + beq reg_cnt,zero,nextinst /* no straggler */ + + lh t0,0(reg_src) /* interesting byte is odd */ +#ifdef __MIPSEB + srl t0,t0,8 /* little endian */ + sb t0,0(reg_dest) /* interesting byte in high 8 bits */ +#else + sb t0,0(reg_dest) /* interesting byte is low 8 bits */ +#endif + + b nextinst +/* CFI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#if (FLASH_DRIVERS & FLASH_DRIVER_CFI) +99: bne reg_op,FEOP_CFIQUERY8,99f /* CFI Query 8-bit */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_8(reg_base,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE) + +1: lbu t0,0(reg_src) /* Copy CFI data */ + sb t0,0(reg_dest) + ADD reg_src,1 + add reg_dest,1 + sub reg_cnt,1 + bgt reg_cnt,zero,1b + + FLASHCMD_8(reg_base,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_CFIQUERY16,99f /* CFI Query 16-bit in word mode */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_16(reg_base,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE) + +1: lh t0,0(reg_src) /* Copy CFI data */ + sh t0,0(reg_dest) + ADD reg_src,2 + add reg_dest,2 + sub reg_cnt,2 + bgt reg_cnt,zero,1b + + FLASHCMD_16(reg_base,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_CFIQUERY16B,99f /* CFI Query 16-bit in byte mode */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_16B(reg_base,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE) + +1: lb t0,0(reg_src) /* Copy CFI data */ + sb t0,0(reg_dest) + ADD reg_src,1 + add reg_dest,1 + sub reg_cnt,1 + bgt reg_cnt,zero,1b + + FLASHCMD_16B(reg_base,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT) + + b nextinst +#endif + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_MEMCPY,99f /* Generic memcpy */ + +1: lbu t0,0(reg_src) + sb t0,0(reg_dest) + add reg_src,1 + add reg_dest,1 + sub reg_cnt,1 + bgt reg_cnt,zero,1b + + b nextinst + + +/* AMD - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#if (FLASH_DRIVERS & FLASH_DRIVER_AMD) +99: bne reg_op,FEOP_AMD_ERASE8,99f /* AMD erase (8-bit) */ + + ADD reg_dest,reg_dest,reg_base + + /* Do an "unlock write" sequence (cycles 1-2) */ + + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* send the erase command (cycle 3) */ + + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3) + + /* Do an "unlock write" sequence (cycles 4-5) */ + + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* Send the "erase sector" qualifier (cycle 6) */ + + FLASHCMD_8(reg_dest,0,AMD_FLASH_ERASE_SEC_6) + + /* Wait for the erase to complete */ + +1: lb t0,0(reg_dest) # get byte + and t0,0xFF # test hi byte + bne t0,0xFF,1b # go till bit is set + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_ERASE16,99f /* AMD erase (16-bit in word mode) */ + + ADD reg_dest,reg_dest,reg_base + + /* Do an "unlock write" sequence (cycles 1-2) */ + + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* send the erase command (cycle 3) */ + + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3) + + /* Do an "unlock write" sequence (cycles 4-5) */ + + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* Send the "erase sector" qualifier (cycle 6) */ + + FLASHCMD_16(reg_dest,0,AMD_FLASH_ERASE_SEC_6) + + /* Wait for the erase to complete */ + +1: lh t0,0(reg_dest) # get word + and t0,0xFF # test byte + bne t0,0xFF,1b # go till erased + + b nextinst + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_ERASE16B,99f /* AMD erase (16-bit in byte mode) */ + + ADD reg_dest,reg_dest,reg_base + + /* Do an "unlock write" sequence (cycles 1-2) */ + + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* send the erase command (cycle 3) */ + + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3) + + /* Do an "unlock write" sequence (cycles 4-5) */ + + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* Send the "erase sector" qualifier (cycle 6) */ + + FLASHCMD_16B(reg_dest,0,AMD_FLASH_ERASE_SEC_6) + + /* Wait for the erase to complete */ + +1: lh t0,0(reg_dest) # get word + and t0,0xFF # test byte + bne t0,0xFF,1b # go till erased + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_PGM8,99f /* AMD 8-bit program */ + + ADD reg_dest,reg_dest,reg_base + + /* Do an "unlock write" sequence (cycles 1-2) */ +11: + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* Send a program command (cycle 3) */ + + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM) + + /* Write a byte (cycle 4) */ + + lbu t0,0(reg_src) + sb t0,0(reg_dest) # t0 = byte written to flash + + /* Wait for write to complete */ + +1: lbu t2,0(reg_dest) # t2 = byte from flash + + and t1,t2,0x80 # done if bit7 of flash + and t0,t0,0x80 # is same as bit7 of data + beq t1,t0,2f + + and t1,t2,0x20 # not done if bit5 + bne t1,0x20,1b # is still set +2: + + /* next byte... */ + + add reg_src,1 # next source byte + ADD reg_dest,1 # next dest byte + sub reg_cnt,1 # one less count + bgt reg_cnt,0,11b + + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_PGM16,99f /* AMD 16-bit program */ + + ADD reg_dest,reg_dest,reg_base + + /* Do an "unlock write" sequence (cycles 1-2) */ +11: + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* Send a program command (cycle 3) */ + + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM) + + /* Write a byte (cycle 4) */ + + lh t0,0(reg_src) + sh t0,0(reg_dest) # t0 = byte written to flash + + /* Wait for write to complete */ + +1: lh t2,0(reg_dest) # t2 = byte from flash + + and t1,t2,0x80 # done if bit7 of flash + and t0,t0,0x80 # is same as bit7 of data + beq t1,t0,2f + + and t1,t2,0x20 # not done if bit5 + bne t1,0x20,1b # is still set +2: + + /* next byte... */ + + add reg_src,2 # next source word + ADD reg_dest,2 # next dest word + sub reg_cnt,2 # one less count + bgt reg_cnt,0,11b + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_PGM16B,99f /* AMD 16-bit pgm in 8-bit mode */ + + ADD reg_dest,reg_dest,reg_base + + /* Do an "unlock write" sequence (cycles 1-2) */ +11: + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + + /* Send a program command (cycle 3) */ + + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM) + + /* Write a byte (cycle 4) */ + + lb t0,0(reg_src) + sb t0,0(reg_dest) # t0 = byte written to flash + + /* Wait for write to complete */ + +1: lb t2,0(reg_dest) # t2 = byte from flash + + and t1,t2,0x80 # done if bit7 of flash + and t0,t0,0x80 # is same as bit7 of data + beq t1,t0,2f + + and t1,t2,0x20 # not done if bit5 + bne t1,0x20,1b # is still set +2: + + /* next byte... */ + + add reg_src,1 # next source word + ADD reg_dest,1 # next dest word + sub reg_cnt,1 # one less count + bgt reg_cnt,0,11b + + b nextinst + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_DEVCODE8,99f /* AMD 8-bit - Boot Block Location */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL) + + lbu t0,AMD_FLASH_DEVCODE8(reg_src) + sb t0,0(reg_dest) + li t0,AMD_FLASH_RESET + sb t0,0(reg_src) + + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_DEVCODE16,99f /* AMD 8-bit - Boot Block Location */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL) + + lw t0,0(reg_src) +#ifdef __MIPSEB + srl t0,t0,8 /* ((3-AMD_FLASH_DEVCODE16)*8) */ +#else + srl t0,t0,16 /* (AMD_FLASH_DEVCODE16*8) */ +#endif + sb t0,0(reg_dest) + li t0,AMD_FLASH_RESET + sb t0,0(reg_src) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_DEVCODE16B,99f /* AMD 8-bit - Boot Block Location */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL) + + lw t0,0(reg_src) +#ifdef __MIPSEB +#else + srl t0,t0,16 /* (AMD_FLASH_DEVCODE16B*8)*/ +#endif + + sb t0,0(reg_dest) + li t0,AMD_FLASH_RESET + sb t0,0(reg_src) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_MANID8,99f /* AMD 8-bit - Boot Block Location */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + FLASHCMD_8(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL) + + lbu t0,AMD_FLASH_MANID(reg_src) + sb t0,0(reg_dest) + li t0,AMD_FLASH_RESET + sb t0,0(reg_src) + + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_MANID16,99f /* AMD 8-bit - Boot Block Location */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + FLASHCMD_16(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL) + + lw t0,0(reg_src) +#ifdef __MIPSEB + srl t0,t0,((3-AMD_FLASH_MANID)*8) +#else + srl t0,t0,(AMD_FLASH_MANID*8) +#endif + sb t0,0(reg_dest) + li t0,AMD_FLASH_RESET + sb t0,0(reg_src) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_AMD_MANID16B,99f /* AMD 8-bit - Boot Block Location */ + + ADD reg_src,reg_src,reg_base + + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1) + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2) + FLASHCMD_16B(reg_base,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL) + + lbu t0,AMD_FLASH_MANID(reg_src) + + sb t0,0(reg_dest) + li t0,AMD_FLASH_RESET + sb t0,0(reg_src) + + b nextinst + +#endif + +/* INTEL - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#if (FLASH_DRIVERS & FLASH_DRIVER_INTEL) +99: bne reg_op,FEOP_INTEL_ERASE8,99f /* Intel erase 8-bit */ + + ADD reg_dest,reg_dest,reg_base + + FLASHCMD_8(reg_dest,0,INTEL_FLASH_ERASE_BLOCK) + FLASHCMD_8(reg_dest,0,INTEL_FLASH_ERASE_CONFIRM) + +1: lbu t0,0(reg_dest) /* loop till bit 7 is set */ + andi t0,0x80 + beq t0,zero,1b + + FLASHCMD_8(reg_dest,0,INTEL_FLASH_READ_MODE) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_INTEL_ERASE16,99f /* Intel erase 16-bit */ + + ADD reg_dest,reg_dest,reg_base + +/* XXX copy of 8-bit erase, is this right? */ + + FLASHCMD_8(reg_dest,0,INTEL_FLASH_ERASE_BLOCK) + FLASHCMD_8(reg_dest,0,INTEL_FLASH_ERASE_CONFIRM) + +1: lbu t0,0(reg_dest) /* loop till bit 7 is set */ + andi t0,0x80 + beq t0,zero,1b + + FLASHCMD_8(reg_dest,0,INTEL_FLASH_READ_MODE) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_INTEL_PGM8,99f /* Intel 8-bit program */ + + ADD reg_dest,reg_dest,reg_base + +11: FLASHCMD_8(reg_dest,0,INTEL_FLASH_PROGRAM) + + lbu t0,0(reg_src) + sb t0,0(reg_dest) + +1: lbu t0,0(reg_dest) /* loop till bit 7 is set */ + andi t0,0x80 + beq t0,zero,1b + + lbu t0,0(reg_dest) /* contains final result */ + /* If good, bits 1, 3, 4 will not be set */ + + add reg_src,1 + ADD reg_dest,1 + sub reg_cnt,1 + bgt reg_cnt,zero,11b + + FLASHCMD_8(reg_dest,0,INTEL_FLASH_READ_MODE) + + b nextinst +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: bne reg_op,FEOP_INTEL_PGM16,99f /* Intel 16-bit prog */ + + ADD reg_dest,reg_dest,reg_base + +11: FLASHCMD_16(reg_dest,0,INTEL_FLASH_PROGRAM) + + lh t0,0(reg_src) + sh t0,0(reg_dest) + +1: lh t0,0(reg_dest) /* loop till bit 7 is set */ + andi t0,0x80 + beq t0,zero,1b + + lh t0,0(reg_dest) /* contains final result */ + /* If good, bits 1, 3, 4 will not be set */ + + add reg_src,2 + ADD reg_dest,2 + sub reg_cnt,2 + bgt reg_cnt,zero,11b + + FLASHCMD_16(reg_dest,0,INTEL_FLASH_READ_MODE) + + b nextinst +#endif +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +99: li v1,-1 /* invalid command */ + +nextinst: SR v1,FEINST_RESULT(a0) /* store result of instruction */ + ADD v0,v0,v1 /* add to total */ + ADD a0,FEINST_SIZE /* advance to next instr. */ + b instloop + +flashop_engine_end: + nop + +END(flashop_engine) + + .sdata + + .globl flashop_engine_ptr + .globl flashop_engine_len + +flashop_engine_ptr: + _VECT_ flashop_engine +flashop_engine_len: + .word flashop_engine_end-flashop_engine + + + +/* ********************************************************************* + * end + ********************************************************************* */ + + diff --git a/cfe/cfe/arch/mips/common/src/disasm.c b/cfe/cfe/arch/mips/common/src/disasm.c new file mode 100644 index 0000000..1b76fee --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/disasm.c @@ -0,0 +1,2111 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * MIPS disassembler File: disasm.c + * + * MIPS disassembler (used by ui_examcmds.c) + * + * Author: Justin Carlson (carlson@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "disasm.h" +#include "lib_printf.h" + +#define UINT64_T(x) ((uint64_t) (x)) +#define PF_64 "ll" +#define PF_32 "" +/* These aren't guaranteed to be portable, either */ +#define SEXT_32(bit, val) \ + ((((int32_t)(val))<<(31-(bit)))>>(31-(bit))) +#define SEXT_64(bit, val) \ + ((((int64_t)(val))<<(63-(bit)))>>(63-(bit))) + +#define DATASEG __attribute__ ((section(".text"))) + + +#define REGNAME(r) (&_regnames[(r)*5]) +static const char * const _regnames = + "zero\0" + "AT\0 " + "v0\0 " + "v1\0 " + "a0\0 " + "a1\0 " + "a2\0 " + "a3\0 " + "t0\0 " + "t1\0 " + "t2\0 " + "t3\0 " + "t4\0 " + "t5\0 " + "t6\0 " + "t7\0 " + "s0\0 " + "s1\0 " + "s2\0 " + "s3\0 " + "s4\0 " + "s5\0 " + "s6\0 " + "s7\0 " + "t8\0 " + "t9\0 " + "k0\0 " + "k1\0 " + "gp\0 " + "sp\0 " + "fp\0 " + "ra\0 "; + +#define CP0REGNAME(r) (&_cp0names[(r)*12]) +static const char * const _cp0names = + "C0_INX\0 " + "C0_RAND\0 " + "C0_TLBLO0\0 " + "C0_TLBLO1\0 " + + "C0_CTEXT\0 " + "C0_PGMASK\0 " + "C0_WIRED\0 " + "C0_reserved\0" + + "C0_BADVADDR\0" + "C0_COUNT\0 " + "C0_TLBHI\0 " + "C0_COMPARE\0 " + + "C0_SR\0 " + "C0_CAUSE\0 " + "C0_EPC\0 " + "C0_PRID\0 " + + "C0_CONFIG\0 " + "C0_LLADDR\0 " + "C0_WATCHLO\0 " + "C0_WATCHHI\0 " + + "C0_XCTEXT\0 " + "C0_reserved\0" + "C0_reserved\0" + "C0_reserved\0" + + "C0_reserved\0" + "C0_reserved\0" + "C0_reserved\0" + "C0_reserved\0" + + "C0_TAGLO\0 " + "C0_TAGHI\0 " + "C0_ERREPC\0 " + "C0_reserved\0"; + + + +/* + * MIPS instruction set disassembly module. + */ + +typedef enum { + DC_RD_RS_RT, + DC_RD_RT_RS, + DC_RT_RS_SIMM, + DC_RT_RS_XIMM, + DC_RS_RT_OFS, + DC_RS_OFS, + DC_RD_RT_SA, + DC_RT_UIMM, + DC_RD, + DC_J, + DC_RD_RS, + DC_RS_RT, + DC_RT_RS, + DC_RT_RD_SEL, + DC_RT_CR_SEL, + DC_RS, + DC_RS_SIMM, + DC_RT_OFS_BASE, + DC_FT_OFS_BASE, + DC_FD_IDX_BASE, + DC_FS_IDX_BASE, + DC_FD_FS_FT, + DC_FD_FS_RT, + DC_FD_FS, + DC_PREF_OFS, + DC_PREF_IDX, + DC_CC_OFS, + DC_FD_FS_CC, + DC_RD_RS_CC, + DC_FD_FR_FS_FT, + DC_FD_FS_FT_RS, + DC_CC_FS_FT, + DC_BARE, + DC_RT_FS, + DC_SYSCALL, + DC_BREAK, + DC_VD_VS_VT_VEC, + DC_VD_VS_VT, + DC_VS_VT, + DC_VS_VT_VEC, + DC_VD_VS_VT_RS, + DC_VD_VS_VT_IMM, + DC_VD_VT, + DC_VD, + DC_VS, + DC_DEREF, + DC_OOPS +} DISASM_CLASS; + + + + +/* We're pulling some trickery here. Most of the time, this structure operates + exactly as one would expect. The special case, when type == DC_DREF, + means name points to a byte that is an index into a dereferencing array. */ + +/* + * To make matters worse, the whole module has been coded to reduce the + * number of relocations present, so we don't actually store pointers + * in the dereferencing array. Instead, we store fixed-width strings + * and use digits to represent indicies into the deref array. + * + * This is all to make more things fit in the relocatable version, + * since every initialized pointer goes into our small data segment. + */ + +typedef struct { + char name[15]; + char type; +} disasm_t; + +typedef struct { + const disasm_t *ptr; + int shift; + uint32_t mask; +} disasm_deref_t; + +/* Forward declaration of deref array, we need this for the disasm_t definitions */ + + +extern const disasm_deref_t disasm_deref[]; + +static const disasm_t disasm_normal[64] DATASEG = +{{"$1" , DC_DEREF }, + {"$2" , DC_DEREF }, + {"j" , DC_J }, + {"jal" , DC_J }, + {"beq" , DC_RS_RT_OFS }, + {"bne" , DC_RS_RT_OFS }, + {"blez" , DC_RS_OFS }, + {"bgtz" , DC_RS_OFS }, + {"addi" , DC_RT_RS_SIMM }, + {"addiu" , DC_RT_RS_SIMM }, + {"slti" , DC_RT_RS_SIMM }, + {"sltiu" , DC_RT_RS_SIMM }, + {"andi" , DC_RT_RS_XIMM }, + {"ori" , DC_RT_RS_XIMM }, + {"xori" , DC_RT_RS_XIMM }, + {"lui" , DC_RT_UIMM }, + {"$4" , DC_DEREF }, + {"$6" , DC_DEREF }, + {"invalid" , DC_BARE }, + {"$15" , DC_DEREF }, + {"beql" , DC_RS_RT_OFS }, + {"bnel" , DC_RS_RT_OFS }, + {"blezl" , DC_RS_OFS }, + {"bgtzl" , DC_RS_OFS }, + {"daddi" , DC_RT_RS_SIMM }, + {"daddiu" , DC_RT_RS_SIMM }, + {"ldl" , DC_RT_OFS_BASE }, + {"ldr" , DC_RT_OFS_BASE }, + {"$3" , DC_DEREF }, + {"invalid" , DC_BARE }, + {"$18" , DC_DEREF }, + {"invalid" , DC_BARE }, + {"lb" , DC_RT_OFS_BASE }, + {"lh" , DC_RT_OFS_BASE }, + {"lwl" , DC_RT_OFS_BASE }, + {"lw" , DC_RT_OFS_BASE }, + {"lbu" , DC_RT_OFS_BASE }, + {"lhu" , DC_RT_OFS_BASE }, + {"lwr" , DC_RT_OFS_BASE }, + {"lwu" , DC_RT_OFS_BASE }, + {"sb" , DC_RT_OFS_BASE }, + {"sh" , DC_RT_OFS_BASE }, + {"swl" , DC_RT_OFS_BASE }, + {"sw" , DC_RT_OFS_BASE }, + {"sdl" , DC_RT_OFS_BASE }, + {"sdr" , DC_RT_OFS_BASE }, + {"swr" , DC_RT_OFS_BASE }, + {"cache" , DC_BARE }, + {"ll" , DC_RT_OFS_BASE }, + {"lwc1" , DC_FT_OFS_BASE }, + {"invalid" , DC_BARE }, + {"pref" , DC_PREF_OFS }, + {"lld" , DC_RT_OFS_BASE }, + {"ldc1" , DC_FT_OFS_BASE }, + {"invalid" , DC_BARE }, + {"ld" , DC_RT_OFS_BASE }, + {"sc" , DC_RT_OFS_BASE }, + {"swc1" , DC_FT_OFS_BASE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"scd" , DC_RT_OFS_BASE }, + {"sdc1" , DC_FT_OFS_BASE }, + {"invalid" , DC_BARE }, + {"sd" , DC_RT_OFS_BASE }}; + +static const disasm_t disasm_special[64] DATASEG = +{{"sll" , DC_RD_RT_SA }, + {"$16" , DC_DEREF }, + {"srl" , DC_RD_RT_SA }, + {"sra" , DC_RD_RT_SA }, + {"sllv" , DC_RD_RT_RS }, + {"invalid" , DC_BARE }, + {"srlv" , DC_RD_RT_RS }, + {"srav" , DC_RD_RT_RS }, + {"jr" , DC_RS }, + {"jalr" , DC_RD_RS }, + {"movz" , DC_RD_RS_RT }, + {"movn" , DC_RD_RS_RT }, + {"syscall" , DC_SYSCALL }, + {"break" , DC_BREAK }, + {"invalid" , DC_BARE }, + {"sync" , DC_BARE }, + {"mfhi" , DC_RD }, + {"mthi" , DC_RS }, + {"mflo" , DC_RD }, + {"mtlo" , DC_RS }, + {"dsllv" , DC_RD_RT_RS }, + {"invalid" , DC_BARE }, + {"dsrlv" , DC_RD_RT_RS }, + {"dsrav" , DC_RD_RT_RS }, + {"mult" , DC_RS_RT }, + {"multu" , DC_RS_RT }, + {"div" , DC_RS_RT }, + {"divu" , DC_RS_RT }, + {"dmult" , DC_RS_RT }, + {"dmultu" , DC_RS_RT }, + {"ddiv" , DC_RS_RT }, + {"ddivu" , DC_RS_RT }, + {"add" , DC_RD_RS_RT }, + {"addu" , DC_RD_RS_RT }, + {"sub" , DC_RD_RS_RT }, + {"subu" , DC_RD_RS_RT }, + {"and" , DC_RD_RS_RT }, + {"or" , DC_RD_RS_RT }, + {"xor" , DC_RD_RS_RT }, + {"nor" , DC_RD_RS_RT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"slt" , DC_RD_RS_RT }, + {"sltu" , DC_RD_RS_RT }, + {"dadd" , DC_RD_RS_RT }, + {"daddu" , DC_RD_RS_RT }, + {"dsub" , DC_RD_RS_RT }, + {"dsubu" , DC_RD_RS_RT }, + {"tge" , DC_RS_RT }, + {"tgeu" , DC_RS_RT }, + {"tlt" , DC_RS_RT }, + {"tltu" , DC_RS_RT }, + {"teq" , DC_RS_RT }, + {"invalid" , DC_BARE }, + {"tne" , DC_RS_RT }, + {"invalid" , DC_BARE }, + {"dsll" , DC_RD_RT_SA }, + {"invalid" , DC_BARE }, + {"dsrl" , DC_RD_RT_SA }, + {"dsra" , DC_RD_RT_SA }, + {"dsll32" , DC_RD_RT_SA }, + {"invalid" , DC_BARE }, + {"dsrl32" , DC_RD_RT_SA }, + {"dsra32" , DC_RD_RT_SA }}; + +static const disasm_t disasm_movci[2] DATASEG = +{{"movf" , DC_RD_RS_CC }, + {"movt" , DC_RD_RS_CC }}; + +static const disasm_t disasm_regimm[32] DATASEG = +{{"bltz" , DC_RS_OFS }, + {"bgez" , DC_RS_OFS }, + {"bltzl" , DC_RS_OFS }, + {"bgezl" , DC_RS_OFS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"tgei" , DC_RS_SIMM }, + {"tgeiu" , DC_RS_SIMM }, + {"tlti" , DC_RS_SIMM }, + {"tltiu" , DC_RS_SIMM }, + {"teqi" , DC_RS_SIMM }, + {"invalid" , DC_BARE }, + {"tnei" , DC_RS_SIMM }, + {"invalid" , DC_BARE }, + {"bltzal" , DC_RS_OFS }, + {"bgezal" , DC_RS_OFS }, + {"bltzall" , DC_RS_OFS }, + {"bgezall" , DC_RS_OFS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }}; + +static const disasm_t disasm_spec2[64] DATASEG = +{{"madd" , DC_RS_RT }, + {"maddu" , DC_RS_RT }, + {"mul" , DC_RD_RS_RT }, + {"invalid" , DC_BARE }, + {"msub" , DC_RS_RT }, + {"msubu" , DC_RS_RT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"clz" , DC_RT_RS }, + {"clo" , DC_RT_RS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"dclz" , DC_RT_RS }, + {"dclo" , DC_RT_RS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"sdbbp" , DC_BARE }}; + +static const disasm_t disasm_cop0[32] DATASEG = +{{"mfc0@1" , DC_RT_CR_SEL }, + {"dmfc0@1" , DC_RT_CR_SEL }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"mtc0@1" , DC_RT_CR_SEL }, + {"dmtc0@1" , DC_RT_CR_SEL }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }, + {"$5" , DC_DEREF }}; + +static const disasm_t disasm_cop0_c0[64] DATASEG = +{{"invalid" , DC_BARE }, + {"tlbr" , DC_BARE }, + {"tlbwi" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"tlbwr" , DC_BARE }, + {"invalid" , DC_BARE }, + {"tlbp" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"eret" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"deret" , DC_BARE }, + {"wait" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }}; + +static const disasm_t disasm_cop1[32] DATASEG = +{{"mfc1" , DC_RT_FS }, + {"dmfc1" , DC_RT_FS }, + {"cfc1" , DC_RT_FS }, + {"invalid" , DC_BARE }, + {"mtc1" , DC_RT_FS }, + {"dmtc1" , DC_RT_FS }, + {"ctc1" , DC_RT_FS }, + {"invalid" , DC_BARE }, + {"$17" , DC_DEREF }, + {"$36" , DC_DEREF }, + {"$37" , DC_DEREF }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"$7" , DC_DEREF }, + {"$9" , DC_DEREF }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"$11" , DC_DEREF }, + {"$12" , DC_DEREF }, + {"$13" , DC_DEREF }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }}; + +static const disasm_t disasm_cop1_bc1[4] DATASEG = +{{"bc1f" , DC_CC_OFS }, + {"bc1t" , DC_CC_OFS }, + {"bc1fl" , DC_CC_OFS }, + {"bc1tl" , DC_CC_OFS }, +}; + +static const disasm_t disasm_cop1_bc1any2[2] DATASEG = +{{"bc1any2f" , DC_CC_OFS }, + {"bc1any2t" , DC_CC_OFS }, +}; + +static const disasm_t disasm_cop1_bc1any4[2] DATASEG = +{{"bc1any4f" , DC_CC_OFS }, + {"bc1any4t" , DC_CC_OFS }, +}; + +static const disasm_t disasm_cop1_s[64] DATASEG = +{{"add.s" , DC_FD_FS_FT }, + {"sub.s" , DC_FD_FS_FT }, + {"mul.s" , DC_FD_FS_FT }, + {"div.s" , DC_FD_FS_FT }, + {"sqrt.s" , DC_FD_FS }, + {"abs.s" , DC_FD_FS }, + {"mov.s" , DC_FD_FS }, + {"neg.s" , DC_FD_FS }, + {"round.l.s" , DC_FD_FS }, + {"trunc.l.s" , DC_FD_FS }, + {"ceil.l.s" , DC_FD_FS }, + {"floor.l.s" , DC_FD_FS }, + {"round.w.s" , DC_FD_FS }, + {"trunc.w.s" , DC_FD_FS }, + {"ceil.w.s" , DC_FD_FS }, + {"floor.w.s" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"$8" , DC_DEREF }, + {"movz.s" , DC_FD_FS_RT }, + {"movn.s" , DC_FD_FS_RT }, + {"invalid" , DC_BARE }, + {"recip.s" , DC_FD_FS }, + {"rsqrt.s" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"recip2.s" , DC_FD_FS_FT }, + {"recip1.s" , DC_FD_FS }, + {"rsqrt1.s" , DC_FD_FS }, + {"rsqrt2.s" , DC_FD_FS_FT }, + {"invalid" , DC_BARE }, + {"cvt.d.s" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"cvt.w.s" , DC_FD_FS }, + {"cvt.l.s" , DC_FD_FS }, + {"cvt.ps.s" , DC_FD_FS_FT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"$38" , DC_DEREF }, + {"$39" , DC_DEREF }, + {"$40" , DC_DEREF }, + {"$41" , DC_DEREF }, + {"$42" , DC_DEREF }, + {"$43" , DC_DEREF }, + {"$44" , DC_DEREF }, + {"$45" , DC_DEREF }, + {"$46" , DC_DEREF }, + {"$47" , DC_DEREF }, + {"$48" , DC_DEREF }, + {"$49" , DC_DEREF }, + {"$50" , DC_DEREF }, + {"$51" , DC_DEREF }, + {"$52" , DC_DEREF }, + {"$53" , DC_DEREF }}; + +static const disasm_t disasm_cop1_s_mvcf[2] DATASEG = +{{"movf.s" , DC_FD_FS_CC }, + {"movt.s" , DC_FD_FS_CC }}; + +static const disasm_t disasm_cop1_d[64] DATASEG = +{{"add.d" , DC_FD_FS_FT }, + {"sub.d" , DC_FD_FS_FT }, + {"mul.d" , DC_FD_FS_FT }, + {"div.d" , DC_FD_FS_FT }, + {"sqrt.d" , DC_FD_FS }, + {"abs.d" , DC_FD_FS }, + {"mov.d" , DC_FD_FS }, + {"neg.d" , DC_FD_FS }, + {"round.l.d" , DC_FD_FS }, + {"trunc.l.d" , DC_FD_FS }, + {"ceil.l.d" , DC_FD_FS }, + {"floor.l.d" , DC_FD_FS }, + {"round.w.d" , DC_FD_FS }, + {"trunc.w.d" , DC_FD_FS }, + {"ceil.w.d" , DC_FD_FS }, + {"floor.w.d" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"$10" , DC_DEREF }, + {"movz.d" , DC_FD_FS_RT }, + {"movn.d" , DC_FD_FS_RT }, + {"invalid" , DC_BARE }, + {"recip.d" , DC_FD_FS }, + {"rsqrt.d" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"recip2.d" , DC_FD_FS_FT }, + {"recip1.d" , DC_FD_FS }, + {"rsqrt1.d" , DC_FD_FS }, + {"rsqrt2.d" , DC_FD_FS_FT }, + {"cvt.s.d" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"cvt.w.d" , DC_FD_FS }, + {"cvt.l.d" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"$54" , DC_DEREF }, + {"$55" , DC_DEREF }, + {"$56" , DC_DEREF }, + {"$57" , DC_DEREF }, + {"$58" , DC_DEREF }, + {"$59" , DC_DEREF }, + {"$60" , DC_DEREF }, + {"$61" , DC_DEREF }, + {"$62" , DC_DEREF }, + {"$63" , DC_DEREF }, + {"$64" , DC_DEREF }, + {"$65" , DC_DEREF }, + {"$66" , DC_DEREF }, + {"$67" , DC_DEREF }, + {"$68" , DC_DEREF }, + {"$69" , DC_DEREF }}; + +static const disasm_t disasm_cop1_d_mvcf[2] DATASEG = +{{"movf.d" , DC_FD_FS_CC }, + {"movt.d" , DC_FD_FS_CC }}; + +static const disasm_t disasm_cop1_w[64] DATASEG = +{{"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"cvt.s.w" , DC_FD_FS }, + {"cvt.d.w" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"cvt.ps.pw" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }}; + +static const disasm_t disasm_cop1_l[64] DATASEG = +{{"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"cvt.s.l" , DC_FD_FS }, + {"cvt.d.l" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }}; + +static const disasm_t disasm_cop1_ps[64] DATASEG = +{{"add.ps" , DC_FD_FS_FT }, + {"sub.ps" , DC_FD_FS_FT }, + {"mul.ps" , DC_FD_FS_FT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"abs.ps" , DC_FD_FS }, + {"mov.ps" , DC_FD_FS }, + {"neg.ps" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"$14" , DC_DEREF }, + {"movz.ps" , DC_FD_FS_RT }, + {"movn.ps" , DC_FD_FS_RT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"addr.ps" , DC_FD_FS_FT }, + {"invalid" , DC_BARE }, + {"mulr.ps" , DC_FD_FS_FT }, + {"invalid" , DC_BARE }, + {"recip2.ps" , DC_FD_FS_FT }, + {"recip1.ps" , DC_FD_FS }, + {"rsqrt1.ps" , DC_FD_FS }, + {"rsqrt2.ps" , DC_FD_FS_FT }, + {"cvt.s.pu" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"cvt.pw.ps" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"cvt.s.pl" , DC_FD_FS }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"pll.ps" , DC_FD_FS_FT }, + {"plu.ps" , DC_FD_FS_FT }, + {"pul.ps" , DC_FD_FS_FT }, + {"puu.ps" , DC_FD_FS_FT }, + {"$70" , DC_DEREF }, + {"$71" , DC_DEREF }, + {"$72" , DC_DEREF }, + {"$73" , DC_DEREF }, + {"$74" , DC_DEREF }, + {"$75" , DC_DEREF }, + {"$76" , DC_DEREF }, + {"$77" , DC_DEREF }, + {"$78" , DC_DEREF }, + {"$79" , DC_DEREF }, + {"$80" , DC_DEREF }, + {"$81" , DC_DEREF }, + {"$82" , DC_DEREF }, + {"$83" , DC_DEREF }, + {"$84" , DC_DEREF }, + {"$85" , DC_DEREF }}; + +static const disasm_t disasm_cop1_c_f_s[2] DATASEG = +{{"c.f.s" , DC_CC_FS_FT }, + {"cabs.f.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_un_s[2] DATASEG = +{{"c.un.s" , DC_CC_FS_FT }, + {"cabs.un.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_eq_s[2] DATASEG = +{{"c.eq.s" , DC_CC_FS_FT }, + {"cabs.eq.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ueq_s[2] DATASEG = +{{"c.ueq.s" , DC_CC_FS_FT }, + {"cabs.ueq.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_olt_s[2] DATASEG = +{{"c.olt.s" , DC_CC_FS_FT }, + {"cabs.olt.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ult_s[2] DATASEG = +{{"c.ult.s" , DC_CC_FS_FT }, + {"cabs.ult.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ole_s[2] DATASEG = +{{"c.ole.s" , DC_CC_FS_FT }, + {"cabs.ole.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ule_s[2] DATASEG = +{{"c.ule.s" , DC_CC_FS_FT }, + {"cabs.ule.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_sf_s[2] DATASEG = +{{"c.sf.s" , DC_CC_FS_FT }, + {"cabs.sf.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngle_s[2] DATASEG = +{{"c.ngle.s" , DC_CC_FS_FT }, + {"cabs.ngle.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_seq_s[2] DATASEG = +{{"c.seq.s" , DC_CC_FS_FT }, + {"cabs.seq.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngl_s[2] DATASEG = +{{"c.ngl.s" , DC_CC_FS_FT }, + {"cabs.ngl.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_lt_s[2] DATASEG = +{{"c.lt.s" , DC_CC_FS_FT }, + {"cabs.lt.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_nge_s[2] DATASEG = +{{"c.nge.s" , DC_CC_FS_FT }, + {"cabs.nge.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_le_s[2] DATASEG = +{{"c.le.s" , DC_CC_FS_FT }, + {"cabs.le.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngt_s[2] DATASEG = +{{"c.ngt.s" , DC_CC_FS_FT }, + {"cabs.ngt.s" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_f_d[2] DATASEG = +{{"c.f.d" , DC_CC_FS_FT }, + {"cabs.f.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_un_d[2] DATASEG = +{{"c.un.d" , DC_CC_FS_FT }, + {"cabs.un.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_eq_d[2] DATASEG = +{{"c.eq.d" , DC_CC_FS_FT }, + {"cabs.eq.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ueq_d[2] DATASEG = +{{"c.ueq.d" , DC_CC_FS_FT }, + {"cabs.ueq.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_olt_d[2] DATASEG = +{{"c.olt.d" , DC_CC_FS_FT }, + {"cabs.olt.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ult_d[2] DATASEG = +{{"c.ult.d" , DC_CC_FS_FT }, + {"cabs.ult.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ole_d[2] DATASEG = +{{"c.ole.d" , DC_CC_FS_FT }, + {"cabs.ole.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ule_d[2] DATASEG = +{{"c.ule.d" , DC_CC_FS_FT }, + {"cabs.ule.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_sf_d[2] DATASEG = +{{"c.sf.d" , DC_CC_FS_FT }, + {"cabs.sf.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngle_d[2] DATASEG = +{{"c.ngle.d" , DC_CC_FS_FT }, + {"cabs.ngle.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_seq_d[2] DATASEG = +{{"c.seq.d" , DC_CC_FS_FT }, + {"cabs.seq.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngl_d[2] DATASEG = +{{"c.ngl.d" , DC_CC_FS_FT }, + {"cabs.ngl.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_lt_d[2] DATASEG = +{{"c.lt.d" , DC_CC_FS_FT }, + {"cabs.lt.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_nge_d[2] DATASEG = +{{"c.nge.d" , DC_CC_FS_FT }, + {"cabs.nge.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_le_d[2] DATASEG = +{{"c.le.d" , DC_CC_FS_FT }, + {"cabs.le.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngt_d[2] DATASEG = +{{"c.ngt.d" , DC_CC_FS_FT }, + {"cabs.ngt.d" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_f_ps[2] DATASEG = +{{"c.f.ps" , DC_CC_FS_FT }, + {"cabs.f.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_un_ps[2] DATASEG = +{{"c.un.ps" , DC_CC_FS_FT }, + {"cabs.un.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_eq_ps[2] DATASEG = +{{"c.eq.ps" , DC_CC_FS_FT }, + {"cabs.eq.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ueq_ps[2] DATASEG = +{{"c.ueq.ps" , DC_CC_FS_FT }, + {"cabs.ueq.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_olt_ps[2] DATASEG = +{{"c.olt.ps" , DC_CC_FS_FT }, + {"cabs.olt.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ult_ps[2] DATASEG = +{{"c.ult.ps" , DC_CC_FS_FT }, + {"cabs.ult.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ole_ps[2] DATASEG = +{{"c.ole.ps" , DC_CC_FS_FT }, + {"cabs.ole.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ule_ps[2] DATASEG = +{{"c.ule.ps" , DC_CC_FS_FT }, + {"cabs.ule.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_sf_ps[2] DATASEG = +{{"c.sf.ps" , DC_CC_FS_FT }, + {"cabs.sf.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngle_ps[2] DATASEG = +{{"c.ngle.ps" , DC_CC_FS_FT }, + {"cabs.ngle.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_seq_ps[2] DATASEG = +{{"c.seq.ps" , DC_CC_FS_FT }, + {"cabs.seq.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngl_ps[2] DATASEG = +{{"c.ngl.ps" , DC_CC_FS_FT }, + {"cabs.ngl.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_lt_ps[2] DATASEG = +{{"c.lt.ps" , DC_CC_FS_FT }, + {"cabs.lt.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_nge_ps[2] DATASEG = +{{"c.nge.ps" , DC_CC_FS_FT }, + {"cabs.nge.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_le_ps[2] DATASEG = +{{"c.le.ps" , DC_CC_FS_FT }, + {"cabs.le.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_c_ngt_ps[2] DATASEG = +{{"c.ngt.ps" , DC_CC_FS_FT }, + {"cabs.ngt.ps" , DC_CC_FS_FT }}; + +static const disasm_t disasm_cop1_ps_mvcf[2] DATASEG = +{{"movf.ps" , DC_FD_FS_CC }, + {"movt.ps" , DC_FD_FS_CC }}; + +static const disasm_t disasm_cop1x[64] DATASEG = +{{"lwxc1" , DC_FD_IDX_BASE }, + {"ldxc1" , DC_FD_IDX_BASE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"luxc1" , DC_FD_IDX_BASE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"swxc1" , DC_FS_IDX_BASE }, + {"sdxc1" , DC_FS_IDX_BASE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"suxc1" , DC_FS_IDX_BASE }, + {"invalid" , DC_BARE }, + {"prefx" , DC_PREF_IDX }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"alnv.ps" , DC_FD_FS_FT_RS }, + {"invalid" , DC_BARE }, + {"madd.s" , DC_FD_FR_FS_FT }, + {"madd.d" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"madd.ps" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }, + {"msub.s" , DC_FD_FR_FS_FT }, + {"msub.d" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"msub.ps" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }, + {"nmadd.s" , DC_FD_FR_FS_FT }, + {"nmadd.d" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"nmadd.ps" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }, + {"nmsub.s" , DC_FD_FR_FS_FT }, + {"nmsub.d" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"invalid" , DC_BARE }, + {"nmsub.ps" , DC_FD_FR_FS_FT }, + {"invalid" , DC_BARE }}; + +static const disasm_t disasm_mdmx[8] DATASEG = +{{ "$20" , DC_DEREF }, + { "$19" , DC_DEREF }, + { "$20" , DC_DEREF }, + { "$33" , DC_DEREF }, + { "$20" , DC_DEREF }, + { "$19" , DC_DEREF }, + { "$20" , DC_DEREF }, + { "$33" , DC_DEREF }, +}; + +static const disasm_t disasm_mdmx_qh[64] DATASEG = +{{ "msgn.qh" , DC_VD_VS_VT_VEC}, + { "c.eq.qh" , DC_VS_VT_VEC }, + { "pickf.qh" , DC_VD_VS_VT_VEC}, + { "pickt.qh" , DC_VD_VS_VT_VEC}, + { "c.lt.qh" , DC_VS_VT_VEC }, + { "c.le.qh" , DC_VS_VT_VEC }, + { "min.qh" , DC_VD_VS_VT_VEC}, + { "max.qh" , DC_VD_VS_VT_VEC}, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "sub.qh" , DC_VD_VS_VT_VEC}, + { "add.qh" , DC_VD_VS_VT_VEC}, + { "and.qh" , DC_VD_VS_VT_VEC}, + { "xor.qh" , DC_VD_VS_VT_VEC}, + { "or.qh" , DC_VD_VS_VT_VEC}, + { "nor.qh" , DC_VD_VS_VT_VEC}, + + { "sll.qh" , DC_VD_VS_VT_VEC}, + { "invalid" , DC_BARE }, + { "srl.qh" , DC_VD_VS_VT_VEC}, + { "sra.qh" , DC_VD_VS_VT_VEC}, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "alni.ob" , DC_VD_VS_VT_IMM}, + { "alnv.ob" , DC_VD_VS_VT_RS }, + { "alni.qh" , DC_VD_VS_VT_IMM}, + { "alnv.qh" , DC_VD_VS_VT_RS }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "$34" , DC_DEREF }, + + { "rzu.qh" , DC_VD_VT }, + { "rnau.qh" , DC_VD_VT }, + { "rneu.qh" , DC_VD_VT }, + { "invalid" , DC_BARE }, + { "rzs.qh" , DC_VD_VT }, + { "rnas.qh" , DC_VD_VT }, + { "rnes.qh" , DC_VD_VT }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "mul.qh" , DC_VD_VS_VT_VEC}, + { "invalid" , DC_BARE }, + { "$21" , DC_DEREF }, + { "$22" , DC_DEREF }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "$23" , DC_DEREF }, + { "$24" , DC_DEREF }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "$25" , DC_DEREF }, + { "$26" , DC_DEREF }, +}; + +static const disasm_t disasm_mdmx_ob[64] DATASEG = +{{ "invalid" , DC_BARE }, + { "c.eq.ob" , DC_VS_VT_VEC }, + { "pickf.ob" , DC_VD_VS_VT_VEC}, + { "pickt.ob" , DC_VD_VS_VT_VEC}, + { "c.lt.ob" , DC_VS_VT_VEC }, + { "c.le.ob" , DC_VS_VT_VEC }, + { "min.ob" , DC_VD_VS_VT_VEC}, + { "max.ob" , DC_VD_VS_VT_VEC}, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "sub.ob" , DC_VD_VS_VT_VEC}, + { "add.ob" , DC_VD_VS_VT_VEC}, + { "and.ob" , DC_VD_VS_VT_VEC}, + { "xor.ob" , DC_VD_VS_VT_VEC}, + { "or.ob" , DC_VD_VS_VT_VEC}, + { "nor.ob" , DC_VD_VS_VT_VEC}, + + { "sll.ob" , DC_VD_VS_VT_VEC}, + { "invalid" , DC_BARE }, + { "srl.ob" , DC_VD_VS_VT_VEC}, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "alni.ob" , DC_VD_VS_VT_IMM}, + { "alnv.ob" , DC_VD_VS_VT_RS }, + { "alni.qh" , DC_VD_VS_VT_IMM}, + { "alnv.qh" , DC_VD_VS_VT_RS }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "$35" , DC_DEREF }, + + { "rzu.ob" , DC_VD_VT }, + { "rnau.ob" , DC_VD_VT }, + { "rneu.ob" , DC_VD_VT }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "mul.ob" , DC_VD_VS_VT_VEC}, + { "invalid" , DC_BARE }, + { "$27" , DC_DEREF }, + { "$28" , DC_DEREF }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "$29" , DC_DEREF }, + { "$30" , DC_DEREF }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "$31" , DC_DEREF }, + { "$32" , DC_DEREF }, +}; + +static const disasm_t disasm_mdmx_alni[64] DATASEG = +{{ "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "alni.ob" , DC_VD_VS_VT_IMM}, + { "alnv.ob" , DC_VD_VS_VT_RS }, + { "alni.qh" , DC_VD_VS_VT_IMM}, + { "alnv.qh" , DC_VD_VS_VT_RS }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, +}; + +static const disasm_t disasm_mdmx_muls_qh[2] DATASEG = +{{ "muls.qh" , DC_VS_VT_VEC }, + { "mulsl.qh" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_mul_qh[2] DATASEG = +{{ "mula.qh" , DC_VS_VT_VEC }, + { "mull.qh" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_sub_qh[2] DATASEG = +{{ "suba.qh" , DC_VS_VT_VEC }, + { "subl.qh" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_add_qh[2] DATASEG = +{{ "adda.qh" , DC_VS_VT_VEC }, + { "addl.qh" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_wac_qh[4] DATASEG = +{{ "wacl.qh" , DC_VS_VT }, + { "invalid" , DC_BARE }, + { "wach.qh" , DC_VS }, + { "invalid" , DC_BARE }, +}; + +static const disasm_t disasm_mdmx_rac_qh[4] DATASEG = +{{ "racl.qh" , DC_VD }, + { "racm.qh" , DC_VD }, + { "rach.qh" , DC_VD }, + { "invalid" , DC_BARE }, +}; + +static const disasm_t disasm_mdmx_muls_ob[2] DATASEG = +{{ "muls.ob" , DC_VS_VT_VEC }, + { "mulsl.ob" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_mul_ob[2] DATASEG = +{{ "mula.ob" , DC_VS_VT_VEC }, + { "mull.ob" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_sub_ob[2] DATASEG = +{{ "suba.ob" , DC_VS_VT_VEC }, + { "subl.ob" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_add_ob[2] DATASEG = +{{ "adda.ob" , DC_VS_VT_VEC }, + { "addl.ob" , DC_VS_VT_VEC }, +}; + +static const disasm_t disasm_mdmx_wac_ob[4] DATASEG = +{{ "wacl.ob" , DC_VS_VT }, + { "invalid" , DC_BARE }, + { "wach.ob" , DC_VS }, + { "invalid" , DC_BARE }, +}; + +static const disasm_t disasm_mdmx_rac_ob[4] DATASEG = +{{ "racl.ob" , DC_VD }, + { "racm.ob" , DC_VD }, + { "rach.ob" , DC_VD }, + { "invalid" , DC_BARE }, +}; + +static const disasm_t disasm_mdmx_shfl_ob[16] DATASEG = +{{ "shfl.upsl.ob" , DC_VD_VS_VT }, + { "shfl.pach.ob" , DC_VD_VS_VT }, + { "shfl.mixh.ob" , DC_VD_VS_VT }, + { "shfl.mixl.ob" , DC_VD_VS_VT }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, +}; + +static const disasm_t disasm_mdmx_shfl_qh[8] DATASEG = +{{ "shfl.bfla.qh" , DC_VD_VS_VT }, + { "shfl.pach.qh" , DC_VD_VS_VT }, + { "shfl.mixh.qh" , DC_VD_VS_VT }, + { "shfl.mixl.qh" , DC_VD_VS_VT }, + { "shfl.repa.qh" , DC_VD_VS_VT }, + { "shfl.repb.qh" , DC_VD_VS_VT }, + { "invalid" , DC_BARE }, + { "invalid" , DC_BARE }, +}; + + + +const disasm_deref_t disasm_deref[] = +/* Disasm array shft msk */ +{{ disasm_normal , 26, 0x3f }, /* 0 */ + { disasm_special , 0, 0x3f }, /* 1 */ + { disasm_regimm , 16, 0x1f }, /* 2 */ + { disasm_spec2 , 0, 0x3f }, /* 3 */ + { disasm_cop0 , 21, 0x1f }, /* 4 */ + { disasm_cop0_c0 , 0, 0x3f }, /* 5 */ + { disasm_cop1 , 21, 0x1f }, /* 6 */ + { disasm_cop1_s , 0, 0x3f }, /* 7 */ + { disasm_cop1_s_mvcf , 16, 0x1 }, /* 8 */ + { disasm_cop1_d , 0, 0x3f }, /* 9 */ + { disasm_cop1_d_mvcf , 16, 0x1 }, /* 10 */ + { disasm_cop1_w , 0, 0x3f }, /* 11 */ + { disasm_cop1_l , 0, 0x3f }, /* 12 */ + { disasm_cop1_ps , 0, 0x3f }, /* 13 */ + { disasm_cop1_ps_mvcf, 16, 0x1 }, /* 14 */ + { disasm_cop1x , 0, 0x3f }, /* 15 */ + { disasm_movci , 16, 0x1 }, /* 16 */ + { disasm_cop1_bc1 , 16, 0x3 }, /* 17 */ + { disasm_mdmx , 21, 0x7 }, /* 18 */ + { disasm_mdmx_qh , 0, 0x3f }, /* 19 */ + { disasm_mdmx_ob , 0, 0x3f }, /* 20 */ + { disasm_mdmx_muls_qh, 10, 0x1 }, /* 21 */ + { disasm_mdmx_mul_qh , 10, 0x1 }, /* 22 */ + { disasm_mdmx_sub_qh , 10, 0x1 }, /* 23 */ + { disasm_mdmx_add_qh , 10, 0x1 }, /* 24 */ + { disasm_mdmx_wac_qh , 24, 0x3 }, /* 25 */ + { disasm_mdmx_rac_qh , 24, 0x3 }, /* 26 */ + { disasm_mdmx_muls_ob, 10, 0x1 }, /* 27 */ + { disasm_mdmx_mul_ob , 10, 0x1 }, /* 28 */ + { disasm_mdmx_sub_ob , 10, 0x1 }, /* 29 */ + { disasm_mdmx_add_ob , 10, 0x1 }, /* 30 */ + { disasm_mdmx_wac_ob , 24, 0x3 }, /* 31 */ + { disasm_mdmx_rac_ob , 24, 0x3 }, /* 32 */ + { disasm_mdmx_alni , 0, 0x3f }, /* 33 */ + { disasm_mdmx_shfl_ob, 22, 0xf }, /* 34 */ + { disasm_mdmx_shfl_qh, 23, 0x7 }, /* 35 */ + { disasm_cop1_bc1any2, 16, 0x1 }, /* 36 */ + { disasm_cop1_bc1any4, 16, 0x1 }, /* 37 */ + { disasm_cop1_c_f_s , 6, 0x1 }, /* 38 */ + { disasm_cop1_c_un_s , 6, 0x1 }, /* 39 */ + { disasm_cop1_c_eq_s , 6, 0x1 }, /* 40 */ + { disasm_cop1_c_ueq_s, 6, 0x1 }, /* 41 */ + { disasm_cop1_c_olt_s, 6, 0x1 }, /* 42 */ + { disasm_cop1_c_ult_s, 6, 0x1 }, /* 43 */ + { disasm_cop1_c_ole_s, 6, 0x1 }, /* 44 */ + { disasm_cop1_c_ule_s, 6, 0x1 }, /* 45 */ + { disasm_cop1_c_sf_s , 6, 0x1 }, /* 46 */ + { disasm_cop1_c_ngle_s, 6, 0x1 }, /* 47 */ + { disasm_cop1_c_seq_s, 6, 0x1 }, /* 48 */ + { disasm_cop1_c_ngl_s, 6, 0x1 }, /* 49 */ + { disasm_cop1_c_lt_s , 6, 0x1 }, /* 50 */ + { disasm_cop1_c_nge_s, 6, 0x1 }, /* 51 */ + { disasm_cop1_c_le_s , 6, 0x1 }, /* 52 */ + { disasm_cop1_c_ngt_s, 6, 0x1 }, /* 53 */ + { disasm_cop1_c_f_d , 6, 0x1 }, /* 54 */ + { disasm_cop1_c_un_d , 6, 0x1 }, /* 55 */ + { disasm_cop1_c_eq_d , 6, 0x1 }, /* 56 */ + { disasm_cop1_c_ueq_d, 6, 0x1 }, /* 57 */ + { disasm_cop1_c_olt_d, 6, 0x1 }, /* 58 */ + { disasm_cop1_c_ult_d, 6, 0x1 }, /* 59 */ + { disasm_cop1_c_ole_d, 6, 0x1 }, /* 60 */ + { disasm_cop1_c_ule_d, 6, 0x1 }, /* 61 */ + { disasm_cop1_c_sf_d , 6, 0x1 }, /* 62 */ + { disasm_cop1_c_ngle_d, 6, 0x1 }, /* 63 */ + { disasm_cop1_c_seq_d, 6, 0x1 }, /* 64 */ + { disasm_cop1_c_ngl_d, 6, 0x1 }, /* 65 */ + { disasm_cop1_c_lt_d , 6, 0x1 }, /* 66 */ + { disasm_cop1_c_nge_d, 6, 0x1 }, /* 67 */ + { disasm_cop1_c_le_d , 6, 0x1 }, /* 68 */ + { disasm_cop1_c_ngt_d, 6, 0x1 }, /* 69 */ + { disasm_cop1_c_f_ps , 6, 0x1 }, /* 70 */ + { disasm_cop1_c_un_ps, 6, 0x1 }, /* 71 */ + { disasm_cop1_c_eq_ps, 6, 0x1 }, /* 72 */ + { disasm_cop1_c_ueq_ps, 6, 0x1 }, /* 73 */ + { disasm_cop1_c_olt_ps, 6, 0x1 }, /* 74 */ + { disasm_cop1_c_ult_ps, 6, 0x1 }, /* 75 */ + { disasm_cop1_c_ole_ps, 6, 0x1 }, /* 76 */ + { disasm_cop1_c_ule_ps, 6, 0x1 }, /* 77 */ + { disasm_cop1_c_sf_ps, 6, 0x1 }, /* 78 */ + { disasm_cop1_c_ngle_ps, 6, 0x1 }, /* 79 */ + { disasm_cop1_c_seq_ps, 6, 0x1 }, /* 80 */ + { disasm_cop1_c_ngl_ps, 6, 0x1 }, /* 81 */ + { disasm_cop1_c_lt_ps, 6, 0x1 }, /* 82 */ + { disasm_cop1_c_nge_ps, 6, 0x1 }, /* 83 */ + { disasm_cop1_c_le_ps, 6, 0x1 }, /* 84 */ + { disasm_cop1_c_ngt_ps, 6, 0x1 }, /* 85 */ +}; + +#define PREFHINT(x) (&pref_hints[(x)*9]) +static char *pref_hints = + "load \0" + "store \0" + "reserved\0" + "reserved\0" + + "ld_strm \0" + "st_strm \0" + "ld_retn \0" + "st_retn \0" + + "reserved\0" + "reserved\0" + "reserved\0" + "reserved\0" + + "reserved\0" + "reserved\0" + "reserved\0" + "reserved\0" + + "reserved\0" + "reserved\0" + "reserved\0" + "reserved\0" + + "reserved\0" + "reserved\0" + "reserved\0" + "reserved\0" + + "reserved\0" + "wb_inval\0" + "reserved\0" + "reserved\0" + + "reserved\0" + "reserved\0" + "reserved\0" + "reserved\0"; + + +static int snprintf(char *buf,int len,const char *templat,...) +{ + va_list marker; + int count; + + va_start(marker,templat); + count = xvsprintf(buf,templat,marker); + va_end(marker); + + return count; +} + +static const disasm_t *get_disasm_field(uint32_t inst) +{ + const disasm_deref_t *tmp = &disasm_deref[0]; + const disasm_t *rec; + do { + rec = &(tmp->ptr[(inst>>tmp->shift) & tmp->mask]); + tmp = &disasm_deref[atoi(&(rec->name[1]))]; + } while (rec->type == DC_DEREF); + return rec; +} + +char *disasm_inst_name(uint32_t inst) +{ + return (char *)(get_disasm_field(inst)->name); +} + +void disasm_inst(char *buf, int buf_size, uint32_t inst, uint64_t pc) +{ + const disasm_t *tmp; + char instname[32]; + int commentmode = 0; + char *x; + + tmp = get_disasm_field(inst); + + strcpy(instname,(char *) tmp->name); + + if ((x = strchr(instname,'@'))) { + *x++ = 0; + commentmode = atoi(x); + } + + switch (tmp->type) { + case DC_RD_RS_RT: + snprintf(buf, buf_size, "%-8s %s,%s,%s", + instname, + REGNAME((inst>>11) & 0x1f), + REGNAME((inst>>21) & 0x1f), + REGNAME((inst>>16) & 0x1f)); + break; + case DC_RD_RT_RS: + snprintf(buf, buf_size, "%-8s %s,%s,%s", + instname, + REGNAME((inst>>11) & 0x1f), + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>21) & 0x1f)); + break; + case DC_RT_RS_SIMM: + snprintf(buf, buf_size, "%-8s %s,%s,#%" PF_32 "d", + instname, + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>21) & 0x1f), + SEXT_32(15, inst & 0xffff)); + break; + case DC_RT_RS_XIMM: + snprintf(buf, buf_size, "%-8s %s,%s,#0x%" PF_32 "x", + instname, + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>21) & 0x1f), + inst & 0xffff); + break; + case DC_RS_RT_OFS: + snprintf(buf, buf_size, "%-8s %s,%s,0x%" PF_64 "x", + instname, + REGNAME((inst>>21) & 0x1f), + REGNAME((inst>>16) & 0x1f), + pc + 4 + (SEXT_64(15, inst & 0xffff)<<2)); + break; + case DC_RS_OFS: + snprintf(buf, buf_size, "%-8s %s,0x%" PF_64 "x", + instname, + REGNAME((inst>>21) & 0x1f), + pc + 4 + (SEXT_64(16, inst & 0xffff)<<2)); + break; + case DC_RD_RT_SA: + snprintf(buf, buf_size, "%-8s %s,%s,#%d", + instname, + REGNAME((inst>>11) & 0x1f), + REGNAME((inst>>16) & 0x1f), + (inst>>6) & 0x1f); + break; + case DC_RT_UIMM: + snprintf(buf, buf_size, "%-8s %s,#%d", + instname, + REGNAME((inst>>16) & 0x1f), + inst & 0xffff); + break; + case DC_RD: + snprintf(buf, buf_size, "%-8s %s", + instname, + REGNAME((inst>>11) & 0x1f)); + break; + case DC_J: + snprintf(buf, buf_size, "%-8s 0x%" PF_64 "x", + instname, + (pc & UINT64_T(0xfffffffff0000000)) | ((inst & 0x3ffffff)<<2)); + break; + case DC_RD_RS: + snprintf(buf, buf_size, "%-8s %s,%s", + instname, + REGNAME((inst>>11) & 0x1f), + REGNAME((inst>>21) & 0x1f)); + break; + case DC_RS_RT: + snprintf(buf, buf_size, "%-8s %s,%s", + instname, + REGNAME((inst>>21) & 0x1f), + REGNAME((inst>>16) & 0x1f)); + break; + case DC_RT_RS: + snprintf(buf, buf_size, "%-8s %s,%s", + instname, + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>21) & 0x1f)); + break; + case DC_RT_RD_SEL: + snprintf(buf, buf_size, "%-8s %s,%s,#%d", + instname, + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>11) & 0x1f), + inst & 0x3); + break; + case DC_RT_CR_SEL: + snprintf(buf, buf_size, "%-8s %s,%d,#%d", + instname, + REGNAME((inst>>16) & 0x1f), + (inst>>11) & 0x1f, + inst & 0x3); + break; + case DC_RS: + snprintf(buf, buf_size, "%-8s %s", + instname, + REGNAME((inst>>21) & 0x1f)); + break; + case DC_RS_SIMM: + snprintf(buf, buf_size, "%-8s %s,#%" PF_32 "d", + instname, + REGNAME((inst>>21) & 0x1f), + SEXT_32(15, inst & 0xffff)); + break; + case DC_RT_OFS_BASE: + snprintf(buf, buf_size, "%-8s %s,#%" PF_32 "d(%s)", + instname, + REGNAME((inst>>16) & 0x1f), + SEXT_32(15, inst), + REGNAME((inst>>21) & 0x1f)); + break; + case DC_FT_OFS_BASE: + snprintf(buf, buf_size, "%-8s f%d,#%" PF_32 "d(%s)", + instname, + (inst>>16) & 0x1f, + SEXT_32(15, inst), + REGNAME((inst>>21) & 0x1f)); + break; + case DC_FD_IDX_BASE: + snprintf(buf, buf_size, "%-8s f%d,%s(%s)", + instname, + (inst>>6) & 0x1f, + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>21) & 0x1f)); + break; + case DC_FS_IDX_BASE: + snprintf(buf, buf_size, "%-8s f%d,%s(%s)", + instname, + (inst>>11) & 0x1f, + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>21) & 0x1f)); + break; + case DC_FD_FS_FT: + snprintf(buf, buf_size, "%-8s f%d,f%d,f%d", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + case DC_FD_FS_RT: + snprintf(buf, buf_size, "%-8s f%d,f%d,%s", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + REGNAME((inst>>16) & 0x1f)); + break; + case DC_FD_FS: + snprintf(buf, buf_size, "%-8s f%d,f%d", + instname, + (inst>>6)&0x1f, + (inst>>11)&0x1f); + break; + case DC_PREF_OFS: + snprintf(buf, buf_size, "%-8s #%" PF_32 "d(%s) /* %s */", + instname, + SEXT_32(15, inst & 0xffff), + REGNAME((inst>>21) & 0x1f), + PREFHINT((inst>>16) & 0x1f)); + break; + case DC_PREF_IDX: + snprintf(buf, buf_size, "%-8s %s(%s) /* %s */", + instname, + REGNAME((inst>>16) & 0x1f), + REGNAME((inst>>21) & 0x1f), + PREFHINT((inst>>16) & 0x1f)); + break; + case DC_CC_OFS: + snprintf(buf, buf_size, "%-8s %d,0x%" PF_64 "x", + instname, + (inst>>18) & 0x7, + pc + 4 + (SEXT_64(15, inst & 0xffff)<<2)); + break; + case DC_RD_RS_CC: + snprintf(buf, buf_size, "%-8s %s,%s,%d", + instname, + REGNAME((inst>>11) & 0x1f), + REGNAME((inst>>21) & 0x1f), + (inst>>18) & 0x7); + break; + case DC_FD_FS_CC: + snprintf(buf, buf_size, "%-8s f%d,f%d,%d", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>18) & 0x7); + break; + case DC_FD_FR_FS_FT: + snprintf(buf, buf_size, "%-8s f%d,f%d,f%d,f%d", + instname, + (inst>>6) & 0x1f, + (inst>>21) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + case DC_FD_FS_FT_RS: + snprintf(buf, buf_size, "%-8s f%d,f%d,f%d,%s", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f, + REGNAME((inst>>21) & 0x1f)); + break; + case DC_CC_FS_FT: + snprintf(buf, buf_size, "%-8s %d,f%d,f%d", + instname, + (inst>>8) & 0x7, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + case DC_BARE: + snprintf(buf, buf_size, "%-8s", instname); + break; + case DC_RT_FS: + snprintf(buf, buf_size, "%-8s %s,f%d", + instname, + REGNAME((inst>>16) & 0x1f), + (inst>>11) & 0x1f); + break; + case DC_VS: + snprintf(buf, buf_size, "%-8s $v%d", + instname, + (inst>>11) & 0x1f); + break; + case DC_VD: + snprintf(buf, buf_size, "%-8s $v%d", + instname, + (inst>>6) & 0x1f); + break; + case DC_VD_VT: + snprintf(buf, buf_size, "%-8s $v%d,$v%d", + instname, + (inst>>6) & 0x1f, + (inst>>16) & 0x1f); + break; + case DC_VD_VS_VT_IMM: + snprintf(buf, buf_size, "%-8s $v%d,$v%d,$v%d,#%d", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f, + (inst>>21) & 0x7); + break; + case DC_VD_VS_VT_RS: + snprintf(buf, buf_size, "%-8s $v%d,$v%d,$v%d,%s", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f, + REGNAME((inst>>21) & 0x1f)); + break; + case DC_VD_VS_VT: + snprintf(buf, buf_size, "%-8s $v%d,$v%d,$v%d", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + case DC_VS_VT: + snprintf(buf, buf_size, "%-8s $v%d,$v%d", + instname, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + case DC_VS_VT_VEC: + switch((inst>>24) & 0x3) { + case 0: + case 1: + /* element select */ + if ((inst>>21) & 1) { + /* QH */ + snprintf(buf, buf_size, "%-8s $v%d,$v%d[%d]", + instname, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f, + (inst>>23) & 0x3); + } else { + /* OB */ + snprintf(buf, buf_size, "%-8s $v%d,$v%d[%d]", + instname, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f, + (inst>>22) & 0x7); + + } + break; + case 2: + /* Vector select */ + snprintf(buf, buf_size, "%-8s $v%d,$v%d", + instname, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + case 3: + /* immediate select */ + snprintf(buf, buf_size, "%-8s $v%d,$#%d", + instname, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + } + break; + + case DC_VD_VS_VT_VEC: + switch((inst>>24) & 0x3) { + case 0: + case 1: + /* element select */ + if ((inst>>21) & 1) { + /* QH */ + snprintf(buf, buf_size, "%-8s $v%d,$v%d,$v%d[%d]", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f, + (inst>>23) & 0x3); + } else { + /* OB */ + snprintf(buf, buf_size, "%-8s $v%d,$v%d,$v%d[%d]", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f, + (inst>>22) & 0x7); + + } + break; + case 2: + /* Vector select */ + snprintf(buf, buf_size, "%-8s $v%d,$v%d,$v%d", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + case 3: + /* immediate select */ + snprintf(buf, buf_size, "%-8s $v%d,$v%d,$#%d", + instname, + (inst>>6) & 0x1f, + (inst>>11) & 0x1f, + (inst>>16) & 0x1f); + break; + } + break; + + case DC_SYSCALL: + snprintf(buf, buf_size, "%-8s #%d", + instname, + (inst>>6) & 0xfffff); + break; + case DC_BREAK: + snprintf(buf, buf_size, "%-8s %d", instname, (inst>>6)&0xfffff); + break; + case DC_OOPS: + snprintf(buf, buf_size, "%s OOPS! FIXME!", instname); + break; + default: + /* Hit something we don't know about...Shouldn't happen. */ + break; + } + + /* + * Handle comment field + */ + + + switch (commentmode) { + case 1: /* CP0 ops */ + if ((inst & 3) == 0) { /* select 0 */ + snprintf(buf + strlen(buf),buf_size-strlen(buf)," /* %s */", + CP0REGNAME((inst >> 11) & 0x1f)); + } + break; + default: + break; + } + + buf[buf_size-1] = 0; + +} diff --git a/cfe/cfe/arch/mips/common/src/exception.S b/cfe/cfe/arch/mips/common/src/exception.S new file mode 100644 index 0000000..8036b35 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/exception.S @@ -0,0 +1,546 @@ +/* ********************************************************************* + * SB1250 Board Support Package + * + * Exception Handler File: exception.S + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "exception.h" +#include "mipsmacros.h" +#include "cpu_config.h" /* for definition of HAZARD and ERET */ +#include "bsp_config.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#ifdef _MIPSREGS32_ +#define LREG lw +#define SREG sw +#define SRL srl +#define SLL sll +#else +#define LREG ld +#define SREG sd +#define SRL dsrl +#define SLL dsll +#endif + + +/* ********************************************************************* + * Data + ********************************************************************* */ + + .sdata + + .globl _exc_vectab +_exc_vectab: _LONG_ 0 # XTYPE_RESET + _LONG_ 0 # XTYPE_TLBFILL (not used) + _LONG_ 0 # XTYPE_XTLBFILL + _LONG_ 0 # XTYPE_CACHEERR (not used) + _LONG_ 0 # XTYPE_EXCEPTION + _LONG_ 0 # XTYPE_INTERRUPT + _LONG_ 0 # XTYPE_EJTAG + +/* ********************************************************************* + * Common Data + ********************************************************************* */ + + .bss + + +/* ********************************************************************* + * Code + ********************************************************************* */ + + .text + +#define R_EXC_CERR_TEMPLATE _TBLIDX(0) +#define R_EXC_CERR_TEMPLATE_END _TBLIDX(1) + + .globl _exc_cerr_htable +_exc_cerr_htable: + _LONG_ _exc_cerr_template + _LONG_ _exc_cerr_template_end + + +/* ********************************************************************* + * _exc_cerr_template + * + * This is a template routine for our cache error handler. + * We save a couple of registers in our magic save area, then + * dispatch to code elsewhere in CFE. + * + * This code is copied right to the vector address, so it has + * to be kept tiny! + * + * Input parameters: + * nothing - running uncached, all registers trashed + * + * Return value: + * might return, might not + ********************************************************************* */ + +LEAF(_exc_cerr_template) + + /* + * Magic! When the cache error handler is running, + * we are in a very special state, running uncached + * and with translations turned off. We can use offsets + * from r0(zero) to store registers we need to use + * during the error handler. + */ + + .set push ; .set noreorder + + SR k0,CFE_LOCORE_GLOBAL_K0TMP(zero) + SR k1,CFE_LOCORE_GLOBAL_K1TMP(zero) + SR ra,CFE_LOCORE_GLOBAL_RATMP(zero) + SR gp,CFE_LOCORE_GLOBAL_GPTMP(zero) + + LR k0,CFE_LOCORE_GLOBAL_CERRH(zero) + jal k0 + nop + + LR k0,CFE_LOCORE_GLOBAL_K0TMP(zero) + LR k1,CFE_LOCORE_GLOBAL_K1TMP(zero) + LR ra,CFE_LOCORE_GLOBAL_RATMP(zero) + LR gp,CFE_LOCORE_GLOBAL_GPTMP(zero) + ERET + + .set pop + + /* + * Note: make sure this routine does not exceed 128 bytes + */ + +_exc_cerr_template_end: + +END(_exc_cerr_template) + +/* ********************************************************************* + * _exc_setup_locore(cerrh) + * + * Set global data into the low-memory region. We do this in + * assembly language so it's easier to deal with the 32-bit/64-bit + * issues that arise in the "C" code. + * + * Input parameters: + * a0 - cache error handler + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_exc_setup_locore) + + move t4,ra + + /* + * Save GP for easy re-use, using uncached writes. + */ + + li t0,PHYS_TO_K1(CFE_LOCORE_GLOBAL_GP) + SR gp,0(t0) + + /* + * Initialize cache error handler pointer. Make it + * uncached, since cache error handlers should not + * touch the cache. + */ + + li t1,(K0SIZE-1) + and a0,a0,t1 # keep just physical part + li t1,K1BASE + or a0,a0,t1 # make into an uncached address + + li t0,PHYS_TO_K1(CFE_LOCORE_GLOBAL_CERRH) + SR a0,0(t0) + + /* + * Move the cache error handler into low RAM. + */ + + li t0,PHYS_TO_K1(MIPS_RAM_VEC_CACHEERR) + + LOADREL(t1,_exc_cerr_htable) + LR t2,R_EXC_CERR_TEMPLATE_END(t1) + LR t1,R_EXC_CERR_TEMPLATE(t1) + +1: lw t3,0(t1) # get a word + sw t3,0(t0) # write a word + ADD t0,4 # next word... + ADD t1,4 + blt t1,t2,1b # till done + + /* + * Now do the whole thing again, but with cached writes. + * Writing uncached makes sure the data is actually in memory, + * and writing cached makes sure we write the same + * stuff again when the cache is evicted. + * This way we don't have to bother with cacheops, + * a bonus on the BCM1250 with its funky L2. + */ + + li t0,PHYS_TO_K0(CFE_LOCORE_GLOBAL_GP) + SR gp,0(t0) + + li t0,PHYS_TO_K0(CFE_LOCORE_GLOBAL_CERRH) + SR a0,0(t0) + + li t0,PHYS_TO_K0(MIPS_RAM_VEC_CACHEERR) + + LOADREL(t1,_exc_cerr_htable) + LR t2,R_EXC_CERR_TEMPLATE_END(t1) + LR t1,R_EXC_CERR_TEMPLATE(t1) + +1: lw t3,0(t1) # get a word + sw t3,0(t0) # write a word + ADD t0,4 # next word... + ADD t1,4 + blt t1,t2,1b # till done + + + /* + * done! + */ + + move ra,t4 + j ra + +END(_exc_setup_locore) + + + + +/* ********************************************************************* + * _exc_setvector(xtype,addr) + * + * Set an exception vector address + * + * Input parameters: + * xtype - exception vector type + * addr - routine address + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_exc_setvector) + + la v0,_exc_vectab + srl a0,3 /* convert 8-byte index to array index */ + sll a0,BPWSIZE /* convert back to index appropriate for word size */ + add v0,a0 + SR a1,(v0) + j ra + +END(_exc_setvector) + + +/* ********************************************************************* + * _exc_crash_sim() + * + * Crash the GDB simulator, causing it to exit. + * + * Input parameters: + * nothing + * + * Return value: + * nothing - does not return + ********************************************************************* */ + + +LEAF(_exc_crash_sim) + + li $2,1 + li $3,0xdead + li $4,0 + syscall 0xca +1: b 1b + +END(_exc_crash_sim) + + +/* ********************************************************************* + * _exc_cache_crash_sim() + * + * As _exc_crash_sim, but distinguish cache error exception. + * + * Input parameters: + * nothing + * + * Return value: + * nothing - does not return + ********************************************************************* */ + + +LEAF(_exc_cache_crash_sim) + + li $2,1 + li $3,0xbadc + li $4,0 + syscall 0xca +1: b 1b + +END(_exc_cache_crash_sim) + + +/* ********************************************************************* + * _exc_restart() + * + * Restart the firmware at the boot address + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_exc_restart) + + li t0,0xBFC00000 # ROM restart vector + jr t0 + +END(_exc_restart) + +/* ********************************************************************* + * _exc_entry(k0) + * + * Main exception entry point. + * + * Input parameters: + * k0 - exception type + * + * Return value: + * ... + ********************************************************************* */ + +LEAF(_exc_entry) + + .set noreorder + .set noat + + subu k1,sp,EXCEPTION_SIZE + SRL k1,3 + SLL k1,3 + + SREG zero,XGR_ZERO(k1) + SREG AT,XGR_AT(k1) + + SREG v0,XGR_V0(k1) + SREG v1,XGR_V1(k1) + + SREG a0,XGR_A0(k1) + SREG a1,XGR_A1(k1) + SREG a2,XGR_A2(k1) + SREG a3,XGR_A3(k1) + + SREG t0,XGR_T0(k1) + SREG t1,XGR_T1(k1) + SREG t2,XGR_T2(k1) + SREG t3,XGR_T3(k1) + SREG t4,XGR_T4(k1) + SREG t5,XGR_T5(k1) + SREG t6,XGR_T6(k1) + SREG t7,XGR_T7(k1) + + SREG s0,XGR_S0(k1) + SREG s1,XGR_S1(k1) + SREG s2,XGR_S2(k1) + SREG s3,XGR_S3(k1) + SREG s4,XGR_S4(k1) + SREG s5,XGR_S5(k1) + SREG s6,XGR_S6(k1) + SREG s7,XGR_S7(k1) + + SREG t8,XGR_T8(k1) + SREG t9,XGR_T9(k1) + + SREG gp,XGR_GP(k1) + SREG sp,XGR_SP(k1) + SREG fp,XGR_FP(k1) + SREG ra,XGR_RA(k1) + + mfc0 t0,C0_CAUSE + mfc0 t1,C0_SR + MFC0 t2,C0_BADVADDR + MFC0 t3,C0_EPC + mfc0 t4,C0_PRID + mflo t5 + mfhi t6 + SREG t0,XCP0_CAUSE(k1) + SREG t1,XCP0_SR(k1) + SREG t2,XCP0_VADDR(k1) + SREG t3,XCP0_EPC(k1) + SREG t4,XCP0_PRID(k1) + SREG t5,XGR_LO(k1) + SREG t6,XGR_HI(k1) + +#if CFG_EMBEDDED_PIC + la gp,PHYS_TO_K0(CFE_LOCORE_GLOBAL_GP) + LR gp,0(gp) # get our GP handle from low memory vector +#else + la gp,_gp # Load up GP, not relocated so it's easy +#endif + + move a0,k0 # Pass exception type + move a1,k1 # Pass frame to exception handler + la t0,_exc_vectab # get base of exception vectors + srl k0,3 # convert 8-byte index to array index + sll k0,BPWSIZE # convert back to index appropriate for word size + addu t0,k0 # get vector address + LR t0,(t0) # to call handler + + move sp,k1 # "C" gets fresh stack area + + jalr t0 # Call exception handler + nop + + move k1, sp + LREG AT,XGR_AT(k1) + + LREG t0,XGR_LO(k1) + LREG t1,XGR_HI(k1) + mtlo t0 + mthi t1 + + LREG a0,XGR_A0(k1) + LREG a1,XGR_A1(k1) + LREG a2,XGR_A2(k1) + LREG a3,XGR_A3(k1) + + LREG t0,XGR_T0(k1) + LREG t1,XGR_T1(k1) + LREG t2,XGR_T2(k1) + LREG t3,XGR_T3(k1) + LREG t4,XGR_T4(k1) + LREG t5,XGR_T5(k1) + LREG t6,XGR_T6(k1) + LREG t7,XGR_T7(k1) + + LREG s0,XGR_S0(k1) + LREG s1,XGR_S1(k1) + LREG s2,XGR_S2(k1) + LREG s3,XGR_S3(k1) + LREG s4,XGR_S4(k1) + LREG s5,XGR_S5(k1) + LREG s6,XGR_S6(k1) + LREG s7,XGR_S7(k1) + + LREG t8,XGR_T8(k1) + LREG t9,XGR_T9(k1) + + LREG gp,XGR_GP(k1) + LREG sp,XGR_SP(k1) + LREG fp,XGR_FP(k1) + LREG ra,XGR_RA(k1) + +/* do any CP0 cleanup here */ + + LREG v0,XGR_V0(k1) + LREG v1,XGR_V1(k1) + + ERET + + .set at + .set reorder + + +END(_exc_entry) + + +/* ********************************************************************* + * _exc_clear_sr_exl() + * + * Clear SR(EXL) and return to caller. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_exc_clear_sr_exl) + + mfc0 t0,C0_SR + and t0,t0,~(0x02) # clear SR(EXL). Bit 1 + mtc0 t0,C0_SR + + HAZARD + + j ra + +END(_exc_clear_sr_exl) + +/* ********************************************************************* + * _exc_clear_sr_erl() + * + * Clear SR(ERL) and return to caller. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_exc_clear_sr_erl) + + mfc0 t0,C0_SR + and t0,t0,~(0x04) # clear SR(ERL). Bit 2 + mtc0 t0,C0_SR + + HAZARD + + j ra + +END(_exc_clear_sr_erl) + + +/* ********************************************************************* + * End + ********************************************************************* */ + + diff --git a/cfe/cfe/arch/mips/common/src/exchandler.c b/cfe/cfe/arch/mips/common/src/exchandler.c new file mode 100644 index 0000000..d69b980 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/exchandler.c @@ -0,0 +1,580 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Exception Handler File: exchandler.c + * + * This is the "C" part of the exception handler and the + * associated setup routines. We call these routines from + * the assembly-language exception handler. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "exception.h" +#include "cfe.h" +#include "cfe_error.h" +#include "cfe_iocb.h" +#include "exchandler.h" +#include "cpu_config.h" +#include "bsp_config.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* + * Temporary until all our CPU packages support a cache error handler + */ + +#ifndef CPUCFG_CERRHANDLER +#define CPUCFG_CERRHANDLER 0xBFC00000 +#else +extern void CPUCFG_CERRHANDLER(void); +#endif + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +exc_handler_t exc_handler; +extern void _exc_entry(void); +extern void _exc_setup_locore(long); +extern void CPUCFG_TLBHANDLER(void); +extern void cfe_flushcache(uint32_t,long,long); +extern uint32_t _getstatus(void); +extern void _setstatus(uint32_t); + +static const char *regnames = "0 ATv0v1a0a1a2a3t0t1t2t3t4t5t6t7" + "s0s1s2s3s4s5s6s7t8t9k0k1gpspfpra"; +static const char *excnames = + "Interrupt" /* 0 */ + "TLBMod " /* 1 */ + "TLBMissRd" /* 2 */ + "TLBMissWr" /* 3 */ + "AddrErrRd" /* 4 */ + "AddrErrWr" /* 5 */ + "BusErrRd " /* 6 */ + "BusErrWr " /* 7 */ + "Syscall " /* 8 */ + "Breakpt " /* 9 */ + "InvOpcode" /* 10 */ + "CoProcUnu" /* 11 */ + "ArithOvfl" /* 12 */ + "TrapExc " /* 13 */ + "VCEI " /* 14 */ + "FPUExc " /* 15 */ + "CP2Exc " /* 16 */ + "Exc17 " /* 17 */ + "Exc18 " /* 18 */ + "Exc19 " /* 19 */ + "Exc20 " /* 20 */ + "Exc21 " /* 21 */ + "Exc22 " /* 22 */ + "Watchpt " /* 23 */ + "Exc24 " /* 24 */ + "Exc25 " /* 25 */ + "Exc26 " /* 26 */ + "Exc27 " /* 27 */ + "Exc28 " /* 28 */ + "Exc29 " /* 29 */ + "Exc30 " /* 30 */ + "VCED "; /* 31 */ + + + +/* ********************************************************************* + * cfe_exception(code,info) + * + * Exception handler. This routine is called when any CPU + * exception that is handled by the assembly-language + * vectors is reached. The usual thing to do here is just to + * reboot. + * + * Input parameters: + * code - exception type + * info - exception stack frame + * + * Return value: + * usually reboots + ********************************************************************* */ + +void cfe_exception(int code,uint64_t *info) +{ + int idx; + + SETLEDS("EXC!"); + + if(exc_handler.catch_exc == 1) { + /*Deal with exception without restarting CFE.*/ + + /*Clear relevant SR bits*/ + _exc_clear_sr_exl(); + _exc_clear_sr_erl(); + + /*Reset flag*/ + exc_handler.catch_exc = 0; + + exc_longjmp_handler(); + } + + +#ifdef _MIPSREGS32_ + xprintf("**Exception %d: EPC=%08X, Cause=%08X (%9s)\n", + code,(uint32_t)info[XCP0_EPC], + (uint32_t)info[XCP0_CAUSE], + excnames + G_CAUSE_EXC((uint32_t)info[XCP0_CAUSE])*9); + xprintf(" RA=%08X, VAddr=%08X\n", + (uint32_t)info[XGR_RA],(uint32_t)info[XCP0_VADDR]); + xprintf("\n"); + for (idx = 0;idx < 32; idx+= 2) { + xprintf(" %2s ($%2d) = %08X %2s ($%2d) = %08X\n", + regnames+(idx*2), + idx,(uint32_t)info[XGR_ZERO+idx], + regnames+((idx+1)*2), + idx+1,(uint32_t)info[XGR_ZERO+idx+1]); + } +#else + xprintf("**Exception %d: EPC=%016llX, Cause=%08X (%9s)\n", + code,info[XCP0_EPC],info[XCP0_CAUSE], + excnames + G_CAUSE_EXC((uint32_t)info[XCP0_CAUSE])*9); + xprintf(" RA=%016llX, VAddr=%016llX\n", + info[XGR_RA],info[XCP0_VADDR]); + xprintf("\n"); + for (idx = 0;idx < 32; idx+= 2) { + xprintf(" %2s ($%2d) = %016llX %2s ($%2d) = %016llX\n", + regnames+(idx*2), + idx,info[XGR_ZERO+idx], + regnames+((idx+1)*2), + idx+1,info[XGR_ZERO+idx+1]); + } +#endif + + xprintf("\n"); + _exc_restart(); +} + +#if (!CFG_BOOTRAM) && (CFG_RUNFROMKSEG0) +/* ********************************************************************* + * exc_setup_hw_vector(vecoffset,target,k0code) + * + * Install a patch of code at the specified offset in low + * KSEG0 memory that will jump to 'target' and load k0 + * with the specified code value. This is used when we + * run with RAM vectors. + * + * Input parameters: + * vecoffset - offset into KSEG0 + * target - location where we should branch when vector is called + * k0code - value to load into K0 before branching + * + * Return value: + * nothing + ********************************************************************* */ + +static void exc_setup_hw_vector(uint32_t vecoffset, + void *target, + uint32_t k0code) +{ + uint32_t *vec; + uint32_t new; + uint32_t lower,upper; + + new = (uint32_t) (intptr_t) target; /* warning: assumes compatibility addresses! */ + + lower = new & 0xffff; + upper = (new >> 16) & 0xffff; + if ((lower & 0x8000) != 0) { + upper++; + } + + /* + * Get a KSEG0 version of the vector offset. + */ + vec = (uint32_t *) PHYS_TO_K0(vecoffset); + + /* + * Patch in the vector. Note that we have to flush + * the L1 Dcache and invalidate the L1 Icache before + * we can use this. + */ + + vec[0] = 0x3c1b0000 | upper; /* lui k1, HIGH(new) */ + vec[1] = 0x277b0000 | lower; /* addiu k1, k1, LOW(new) */ + vec[2] = 0x03600008; /* jr k1 */ + vec[3] = 0x241a0000 | k0code; /* li k0, code */ + +} + + +/* ********************************************************************* + * exc_install_ram_vectors() + * + * Install all of the hardware vectors into low memory, + * flush the cache, and clear the BEV bit so we can start + * using them. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void exc_install_ram_vectors(void) +{ + uint32_t *ptr; + int idx; + + /* Debug: blow away the vector area so we can see what we did */ + ptr = (uint32_t *) PHYS_TO_K0(0); + for (idx = 0; idx < 0x1000/sizeof(uint32_t); idx++) *ptr++ = 0; + + /* + * Set up the vectors. The cache error handler is set up + * specially. + */ + + exc_setup_hw_vector(MIPS_RAM_VEC_TLBFILL, CPUCFG_TLBHANDLER,XTYPE_TLBFILL); + exc_setup_hw_vector(MIPS_RAM_VEC_XTLBFILL, _exc_entry,XTYPE_XTLBFILL); + exc_setup_hw_vector(MIPS_RAM_VEC_CACHEERR, _exc_entry,XTYPE_CACHEERR); + exc_setup_hw_vector(MIPS_RAM_VEC_EXCEPTION,_exc_entry,XTYPE_EXCEPTION); + exc_setup_hw_vector(MIPS_RAM_VEC_INTERRUPT,_exc_entry,XTYPE_INTERRUPT); + + /* + * Flush the D-cache and invalidate the I-cache so we can start + * using these vectors. + */ + + cfe_flushcache(CFE_CACHE_FLUSH_D | CFE_CACHE_INVAL_I,0,0); + + /* + * Write the handle into our low memory space. If we need to save + * other stuff down there, this is a good place to do it. + * This call uses uncached writes - we have not touched the + * memory in the handlers just yet, so they should not be + * in our caches. + */ + + _exc_setup_locore((intptr_t) CPUCFG_CERRHANDLER); + + /* + * Finally, clear BEV so we'll use the vectors in RAM. + */ + + _setstatus(_getstatus() & ~M_SR_BEV); + + /* + * XXX There's a hazard here, but we're not going to worry about + * XXX it. It is unlikely we'll use the vectors any time soon. + */ +} +#endif + +/* ********************************************************************* + * cfe_setup_exceptions() + * + * Set up the exception handlers. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +void cfe_setup_exceptions(void) +{ + _exc_setvector(XTYPE_TLBFILL, (void *) cfe_exception); + _exc_setvector(XTYPE_XTLBFILL, (void *) cfe_exception); + _exc_setvector(XTYPE_CACHEERR, (void *) _exc_cache_crash_sim); + _exc_setvector(XTYPE_EXCEPTION,(void *) cfe_exception); + _exc_setvector(XTYPE_INTERRUPT,(void *) cfe_exception); + _exc_setvector(XTYPE_EJTAG, (void *) cfe_exception); + + exc_handler.catch_exc = 0; + q_init( &(exc_handler.jmpbuf_stack)); + +#if (!CFG_BOOTRAM) && (CFG_RUNFROMKSEG0) + /* + * Install RAM vectors, and clear the BEV bit in the status + * register. Don't do this if we're running from PromICE RAM + */ + exc_install_ram_vectors(); +#endif +} + + + +/* ********************************************************************* + * exc_initialize_block() + * + * Set up the exception handler. Allow exceptions to be caught. + * Allocate memory for jmpbuf and store it away. + * + * Returns NULL if error in memory allocation. + * + * Input parameters: + * nothing + * + * Return value: + * jmpbuf_t structure, or NULL if no memory + ********************************************************************* */ +jmpbuf_t *exc_initialize_block(void) +{ + jmpbuf_t *jmpbuf_local; + + exc_handler.catch_exc = 1; + + /* Create the jmpbuf_t object */ + jmpbuf_local = (jmpbuf_t *) KMALLOC((sizeof(jmpbuf_t)),0); + + if (jmpbuf_local == NULL) { + return NULL; + } + + q_enqueue( &(exc_handler.jmpbuf_stack), &((*jmpbuf_local).stack)); + + return jmpbuf_local; +} + +/* ********************************************************************* + * exc_cleanup_block(dq_jmpbuf) + * + * Remove dq_jmpbuf from the exception handler stack and free + * the memory. + * + * Input parameters: + * dq_jmpbuf - block to deallocate + * + * Return value: + * nothing + ********************************************************************* */ + +void exc_cleanup_block(jmpbuf_t *dq_jmpbuf) +{ + int count; + + if (dq_jmpbuf == NULL) { + return; + } + + count = q_count( &(exc_handler.jmpbuf_stack)); + + if( count > 0 ) { + q_dequeue( &(*dq_jmpbuf).stack ); + KFREE(dq_jmpbuf); + } +} + +/* ********************************************************************* + * exc_cleanup_handler(dq_jmpbuf,chain_exc) + * + * Clean a block, then chain to the next exception if required. + * + * Input parameters: + * dq_jmpbuf - current exception + * chain_exc - true if we should chain to the next handler + * + * Return value: + * nothing + ********************************************************************* */ + +void exc_cleanup_handler(jmpbuf_t *dq_jmpbuf, int chain_exc) +{ + exc_cleanup_block(dq_jmpbuf); + + if( chain_exc == EXC_CHAIN_EXC ) { + /*Go to next exception on stack */ + exc_longjmp_handler(); + } +} + + + +/* ********************************************************************* + * exc_longjmp_handler() + * + * This routine long jumps to the exception handler on the top + * of the exception stack. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +void exc_longjmp_handler(void) +{ + int count; + jmpbuf_t *jmpbuf_local; + + count = q_count( &(exc_handler.jmpbuf_stack)); + + if( count > 0 ) { + jmpbuf_local = (jmpbuf_t *) q_getlast(&(exc_handler.jmpbuf_stack)); + + SETLEDS("CFE "); + + lib_longjmp( (*jmpbuf_local).jmpbuf, -1); + } +} + + +/* ********************************************************************* + * mem_peek(d,addr,type) + * + * Read memory of the specified type at the specified address. + * Exceptions are caught in the case of a bad memory reference. + * + * Input parameters: + * d - pointer to where data should be placed + * addr - address to read + * type - type of read to do (MEM_BYTE, etc.) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int mem_peek(void *d, long addr, int type) +{ + + jmpbuf_t *jb; + + jb = exc_initialize_block(); + if( jb == NULL ) { + return CFE_ERR_NOMEM; + } + + if (exc_try(jb) == 0) { + + switch (type) { + case MEM_BYTE: + *(uint8_t *)d = *((volatile uint8_t *) addr); + break; + case MEM_HALFWORD: + *(uint16_t *)d = *((volatile uint16_t *) addr); + break; + case MEM_WORD: + *(uint32_t *)d = *((volatile uint32_t *) addr); + break; + case MEM_QUADWORD: + *(uint64_t *)d = *((volatile uint64_t *) addr); + break; + default: + return CFE_ERR_INV_PARAM; + } + + exc_cleanup_block(jb); + } + else { + /*Exception handler*/ + + exc_cleanup_handler(jb, EXC_NORMAL_RETURN); + return CFE_ERR_GETMEM; + } + + return 0; +} + +/* ********************************************************************* + * Write memory of type at address addr with value val. + * Exceptions are caught, handled (error message) and function + * returns with 0. + * + * 1 success + * 0 failure + ********************************************************************* */ + +int mem_poke(long addr, uint64_t val, int type) +{ + + jmpbuf_t *jb; + + jb = exc_initialize_block(); + if( jb == NULL ) { + return CFE_ERR_NOMEM; + } + + if (exc_try(jb) == 0) { + + switch (type) { + case MEM_BYTE: + *((volatile uint8_t *) addr) = (uint8_t) val; + break; + case MEM_HALFWORD: + *((volatile uint16_t *) addr) = (uint16_t) val; + break; + case MEM_WORD: + *((volatile uint32_t *) addr) = (uint32_t) val; + break; + case MEM_QUADWORD: + *((volatile uint64_t *) addr) = (uint64_t) val; + break; + default: + return CFE_ERR_INV_PARAM; + } + + exc_cleanup_block(jb); + } + else { + /*Exception handler*/ + + exc_cleanup_handler(jb, EXC_NORMAL_RETURN); + return CFE_ERR_SETMEM; + } + + return 0; +} + + + + + + + + + + diff --git a/cfe/cfe/arch/mips/common/src/init_mips.S b/cfe/cfe/arch/mips/common/src/init_mips.S new file mode 100755 index 0000000..3f59539 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/init_mips.S @@ -0,0 +1,683 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * CPU init module File: init_mips.S + * + * This module contains the vectors and lowest-level CPU startup + * functions for CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "exception.h" + +#include "bsp_config.h" +#include "cpu_config.h" + +#ifdef _CFE_ +#include "cfe_devfuncs.h" +#else + +#define cfe_command_restart 0 +#endif + +/* BCM63XX specific change. */ +#include "bcm_hwdefs.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#include "mipsmacros.h" + + +/* ********************************************************************* + * SETLEDS(a,b,c,d) + * SETLEDS1(a,b,c,d) + * + * Sets the on-board LED display (if present). Two variants + * of this routine are provided. If you're running KSEG1, + * call the SETLEDS1 variant, else call SETLEDS. + * + * Input parameters: + * a,b,c,d - four ASCII characters (literal constants) + * + * Return value: + * a0,k1,ra trashed + ********************************************************************* */ + +#define SETLEDS(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + CALLINIT_KSEG0(init_table,R_INIT_SETLEDS) + +#define SETLEDS1(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + CALLINIT_KSEG1(init_table,R_INIT_SETLEDS) + + +/* ********************************************************************* + * Other constants + ********************************************************************* */ + +/* + * This is the size of the stack, rounded to KByte boundaries. + */ + +#ifndef CFG_STACK_SIZE +#error "CFG_STACK_SIZE not defined" +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +#ifdef __MIPSEB +#define TEXTSECTION 0x2e746578 # ".tex", big-endian +#else +#define TEXTSECTION 0x7865742e # ".tex", little-endian +#endif + +/* + * Duplicates from cfe_iocb.h -- warning! + */ + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 +#define CFE_CACHE_FLUSH_L2 16 +#define CFE_CACHE_INVAL_RANGE 32 +#define CFE_CACHE_FLUSH_RANGE 64 + + +/* + * To make life easier reading this code, define "KSEGBASE" + * to either K0BASE or K1BASE depending on whether we're running + * uncached. + */ + +#if CFG_RUNFROMKSEG0 +#define KSEGBASE K0BASE +#else +#define KSEGBASE K1BASE +#endif + + +/* ********************************************************************* + * Names of registers used in this module + ********************************************************************* */ + +#define RELOCOFFSET s8 /* $30 (fp) */ +#define TEXTOFFSET t9 /* $25 (t9) */ +#define MEMTOP t8 /* $24 (t8) */ +#define TEXTBASE s7 /* $23 (s7) */ +#undef BOOT_OFFSET +#define BOOT_OFFSET s6 /* $22 (s6) */ + + .sdata + +#include "initdata.h" /* declare variables we use here */ + +#if CFG_MULTI_CPUS + .globl cfe_spinlock +cfe_spinlock: .word 0 +#endif + + .extern _fdata + .extern _edata + .extern _etext + +/* ********************************************************************* + * uninitialized data + ********************************************************************* */ + + .bss + + .comm __junk,4 + +/* ********************************************************************* + * Exception Vectors + ********************************************************************* */ + + .text + + .set noreorder + +/* + * Declare the actual vectors. This expands to code that + * must be at the very beginning of the text segment. + */ + +DECLARE_VECTOR(0x0000,vec_reset,cpu_reset) + + .set reorder + +/* ********************************************************************* + * Some offsets depend on our current configuration + ********************************************************************* */ + +#define RUNTIME_RELOC_START 0 +#define RUNTIME_RELOC_STOP 0 + +/* ********************************************************************* + * Segment Table. + * + * Addresses of data segments and of certain routines we're going + * to call from KSEG1. These are here mostly for the embedded + * PIC case, since we can't count on the 'la' instruction to + * do the expected thing (the assembler expands it into a macro + * for doing GP-relative stuff, and the code is NOT GP-relative. + * So, we (relocatably) get the offset of this table and then + * index within it. + * + * Pointer values in this segment will be relative to KSEG0 for + * cached versions of CFE, so we need to OR in K1BASE in the + * case of calling to a uncached address. + * + * The LOADREL macro handles most of the nastiness here. + ********************************************************************* */ + +#include "segtable.h" +#include "cfe.h" + + .org 0x570 + .byte 'c','f','e','-','v',CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD,BCM63XX_MAJOR,BCM63XX_MINOR # CFE version info for applications + .org 0x580 # move past exception vectors + + /* + * BCM963XX NVRAM Data Storage + */ + + .globl nvram_data_storage +nvram_data_storage: + .word NVRAM_DATA_ID + .space 0x400 + + .globl segment_table +segment_table: + _LONG_ _etext # [ 0] End of text (R_SEG_ETEXT) + _LONG_ _fdata # [ 1] Beginning of data (R_SEG_FDATA) + _LONG_ _edata # [ 2] End of data (R_SEG_EDATA) + _LONG_ _end # [ 3] End of BSS (R_SEG_END) + _LONG_ _ftext # [ 4] Beginning of text (R_SEG_FTEXT) + _LONG_ _fbss # [ 5] Beginning of BSS (R_SEG_FBSS) + _LONG_ _gp # [ 6] Global Pointer (R_SEG_GP) + _LONG_ 0 # [ 7] Beginning of reloc entries + _LONG_ 0 # [ 8] End of reloc entries + _LONG_ 0 # [ 9] R_SEG_APIENTRY + +/* ********************************************************************* + * Init Table. + * + * This is like segment_table except it contains pointers to + * routines used during initialization. It serves both as a + * table for doing PIC stuff and also to separate out + * machine-specific init routines. + * + * The CALLINIT_xxx macros are used to call routines in this table. + ********************************************************************* */ + + + .globl init_table +init_table: + _LONG_ board_earlyinit # [ 0] R_INIT_EARLYINIT + _LONG_ board_setleds # [ 1] R_INIT_SETLEDS + _LONG_ board_draminfo # [ 2] R_INIT_DRAMINFO + _LONG_ CPUCFG_CPUINIT # [ 3] R_INIT_CPUINIT + _LONG_ CPUCFG_ALTCPU_START1 # [ 4] R_INIT_ALTCPU_START1 + _LONG_ CPUCFG_ALTCPU_START2 # [ 5] R_INIT_ALTCPU_START2 + _LONG_ CPUCFG_ALTCPU_RESET # [ 6] R_INIT_ALTCPU_RESET + _LONG_ CPUCFG_CPURESTART # [ 7] R_INIT_CPURESTART + _LONG_ CPUCFG_DRAMINIT # [ 8] R_INIT_DRAMINIT + _LONG_ CPUCFG_CACHEOPS # [ 9] R_INIT_CACHEOPS + _LONG_ CPUCFG_TLBHANDLER # [ 10] R_INIT_TLBHANDLER + _LONG_ cfe_main # [ 11] R_INIT_CMDSTART + _LONG_ cfe_command_restart # [ 12] R_INIT_CMDRESTART + _LONG_ cfe_doxreq # [ 13] R_INIT_DOXREQ + _LONG_ CPUCFG_TP1_SWITCH # [ 14] R_INIT_TP1_SWITCH + _LONG_ cfe_size_ram # [ 15] R_INIT_SIZERAM + +/* ********************************************************************* + * CPU Startup Code + ********************************************************************* */ + +cpu_reset: + + /* + * Start with GP as zero. Nobody should touch + * this or set it to any other value until we're ready + * to use it. This is used to tell when we should start + * using relocated references in the init table, + * so beware! (see CALLINIT_RELOC in mipsmacros.h) + */ + + move gp,zero # start with no GP. + + .set noreorder + bal 1f + nop +1: nop + .set reorder + li BOOT_OFFSET, 0x1fff0000 + and BOOT_OFFSET, ra + +#------------------------------------------------------------------------------ + + /* + * Do low-level board initialization. This is our first + * chance to customize the startup sequence. + */ + move a0, BOOT_OFFSET + + CALLINIT_KSEG1(init_table,R_INIT_EARLYINIT) + + SETLEDS1('H','E','L','O') + + CALLINIT_KSEG1(init_table,R_INIT_CPUINIT) + +#------------------------------------------------------------------------------ + + /* + * Now, switch from KSEG1 to KSEG0 + */ + +#if CFG_RUNFROMKSEG0 + bal cpu_kseg0_switch +#endif + +#------------------------------------------------------------------------------ + /* + * Now running on cpu0 in K0SEG. + */ + +#if CFG_CMT + /* + * Check if the thread switch is required. If we are already + * running on thread 1 this function will do nothing and just return + * If we are running on thread 0 this function will take thread 1 + * out of reset and put thread 0 to sleep waiting for singnal from + * thread 1. + */ + CALLINIT_KSEG0(init_table,R_INIT_TP1_SWITCH) +#endif + +#if CFG_INIT_DRAM + SETLEDS('D','R','A','M') + + CALLINIT_KSEG0(init_table,R_INIT_DRAMINFO) + + move a0,v0 # pass these params + CALLINIT_KSEG0(init_table,R_INIT_DRAMINIT) + CALLINIT_KSEG0(init_table,R_INIT_SIZERAM) + move k0,v0 # Save in k0 for now +#else + li k0,(CFG_DRAM_SIZE * 1024) +#endif + +#------------------------------------------------------------------------------ + +#if CFG_BOOTRAM + b have_ram # No RAM is ok if using emulator RAM +#endif + + bne k0,zero,have_ram + + SETLEDS('R','A','M','X') # die here if no ram + +die1: b die1 + +have_ram: + + /* + * If this is the 64-bit version, turn on the KX bit + * to allow 64-bit accesses. + */ + +#ifdef __long64 + mfc0 t0,C0_SR + or t0,t0,M_SR_KX + mtc0 t0,C0_SR +#endif + +#------------------------------------------------------------------------------ + /* + * K0 contains the RAM size (and therefore the top of RAM + * offset). Start there, and subtract the amount of memory + * we expect to use. If we have more than 256MB of + * physical memory, work backwards from the 256MB + * boundary. + */ + +__CalcMemTop: li MEMTOP,256 # 256MB boundary + bgt k0,MEMTOP,1f # use 256MB if k0 is greater + move MEMTOP,k0 # otherwise keep top +1: sll MEMTOP,20 # make into byte amount + + li RELOCOFFSET,0 # not relocating, no offset + li TEXTOFFSET,0 + + /* + * DRAM is now running, and we're alive in cacheable memory + * on cpu0 in K0SEG. Set up GP. + */ + + LOADREL(a0,segment_table) + LR gp,R_SEG_GP(a0) + add gp,RELOCOFFSET + +#------------------------------------------------------------------------------ + /* + * Zero BSS + */ + + SETLEDS('Z','B','S','S') + + LOADREL(a0,segment_table) +__ZeroBss: + + LR v0,R_SEG_FBSS(a0) + LR v1,R_SEG_END(a0) + ADD v0,RELOCOFFSET # Relocate to actual data segment + ADD v1,RELOCOFFSET + +1: SR zero,0(v0) # Zero one cacheline at a time + SR zero,(REGSIZE*1)(v0) + SR zero,(REGSIZE*2)(v0) + SR zero,(REGSIZE*3)(v0) + add v0,REGSIZE*4 + blt v0,v1,1b + +#------------------------------------------------------------------------------ + /* + * Copy code + */ + + SETLEDS('C','O','D','E') + + LOADREL(a0,segment_table) +__CopyCode: + + LR t1,R_SEG_FTEXT(a0) # destination address + move TEXTBASE,t1 + + LR t2,R_SEG_FTEXT(a0) # Source address + FIXUP (t2); + LR t3,R_SEG_ETEXT(a0) + FIXUP (t3); + +1: LR t4,0(t2) # read one cache line + LR t5,(REGSIZE*1)(t2) + LR t6,(REGSIZE*2)(t2) + LR t7,(REGSIZE*3)(t2) + SR t4,0(t1) # write one cache line + SR t5,(REGSIZE*1)(t1) + SR t6,(REGSIZE*2)(t1) + SR t7,(REGSIZE*3)(t1) + add t1,REGSIZE*4 + add t2,REGSIZE*4 + bltu t2,t3,1b + +#------------------------------------------------------------------------------ + /* + * Copy initialized data + */ + +#if (CFG_BOOTRAM == 0) + + SETLEDS('D','A','T','A') + + LOADREL(a0,segment_table) + +__CopyData: + LR t1,R_SEG_FDATA(a0) + FIXUP (t1); + li t0,15 + add t1,t0 + not t0 + and t1,t0 # t1 = _etext rounded up to 16-byte boundary + + LR t2,R_SEG_FDATA(a0) + LR t3,R_SEG_EDATA(a0) + ADD t2,RELOCOFFSET # Relocate to actual data segment + ADD t3,RELOCOFFSET + +1: LR t4,0(t1) # read one cache line + LR t5,(REGSIZE*1)(t1) + LR t6,(REGSIZE*2)(t1) + LR t7,(REGSIZE*3)(t1) + SR t4,0(t2) # write one cache line + SR t5,(REGSIZE*1)(t2) + SR t6,(REGSIZE*2)(t2) + SR t7,(REGSIZE*3)(t2) + add t1,(REGSIZE*4) + add t2,(REGSIZE*4) + bltu t2,t3,1b + +#endif + +#------------------------------------------------------------------------------ + + /* + * Flush the cache, then switch to relocated code + * We need to flush the cache since we just moved the code and + * it may still live in our L1 DCache. We also need to + * flush L2, since there are some rare times we run + * uncached from DRAM, like when we start/stop a CPU. + * + * In the case of running completely uncached, don't flush the + * cache. It should not have any dirty lines in it, but you + * never know... + */ + +__GoRelo: + +#if CFG_RUNFROMKSEG0 + SETLEDS('L','1','2','F') + + li a0,CFE_CACHE_FLUSH_D | CFE_CACHE_FLUSH_L2 + CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) + li a0,CFE_CACHE_INVAL_I + CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) +#endif /* CFG_RUNFROMKSEG0 */ + + la t0,gorelo # Now jump to an address code was compiled for + j t0 # and go there +gorelo: nop + li BOOT_OFFSET, 0 # no longer running at offset + + /* + * Remember total amount of memory. This is *still* in k0 + * after all this time. Hopefully. + */ + +__MemVars: + SR k0,mem_totalsize + SR RELOCOFFSET,mem_datareloc + + move v0,zero + + LOADREL(a0,segment_table) # trashed by l2 cache flush + LR v0,R_SEG_FDATA(a0) + ADD v0,RELOCOFFSET + LR v1,R_SEG_END(a0) + ADD v1,RELOCOFFSET + + SR v0,mem_bottomofmem + SR v1,mem_heapstart + + add v1,(CFG_HEAP_SIZE*1024) # Otherwise + add v1,STACK_SIZE + SR v1,mem_topofmem + + SR TEXTOFFSET,mem_textreloc + + /* At this point it's safe to use the CALLINIT_RELOC macro */ + + LR t1,R_SEG_FTEXT(a0) + FIXUP (t1); + LR t0,R_SEG_ETEXT(a0) + FIXUP (t0); + sub t0,t0,t1 + SR t0,mem_textsize + add t1,TEXTOFFSET + SR t1,mem_textbase + + +#------------------------------------------------------------------------------ + + /* + * Stash away some config register stuff + */ + + mfc0 v0,C0_PRID + SR v0,cpu_prid + + +#------------------------------------------------------------------------------ + + /* + * Set up the "C" stack and jump to the main routine. + */ + + SETLEDS('M','A','I','N') + + LR sp,mem_heapstart + ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) + li a0,0 # call as "cfe_main(0,0)" + li a1,0 + + CALLINIT_RELOC(init_table,R_INIT_CMDSTART) # should not return + +/* ********************************************************************* + * CFE_LAUNCH + * + * Start the user program. The program is passed a handle + * that must be passed back when calling the firmware. + * + * Parameters passed to the called program are as follows: + * + * a0 - CFE handle + * a1 - entry vector + * a2 - reserved, will be 0 + * a3 - entrypoint signature. + * + * Input parameters: + * a0 - entry vector + * + * Return value: + * does not return + ********************************************************************* */ + +LEAF(cfe_launch) + + sub sp,8 + SR a0,0(sp) + + /* + * This function runs in RAM so BOOT_OFFSET is 0. It is called from + * C which could have modified the BOOT_OFFSET register, s6. + */ + li BOOT_OFFSET, 0 + + + /* + * Mask all interrupts. + */ + mfc0 v0,C0_SR # Get current interrupt flag + li v1,M_SR_IE # master interrupt control + not v1 # disable interrupts + and v0,v1 # SR now has IE=0 + mtc0 v0,C0_SR # put back into CP0 + + + /* + * Flush the D-Cache, since the program we loaded is "data". + * Invalidate the I-Cache, so that addresses in the program + * region will miss and need to be filled from the data we + * just flushed above. + */ + + li a0,CFE_CACHE_FLUSH_D|CFE_CACHE_INVAL_I + CALLINIT_RELOC(init_table,R_INIT_CACHEOPS) + + + /* + * Set things up for launching the program. Pass the + * handle in A0 - apps need to remember that and pass it + * back. + */ + + j RunProgram + +END(cfe_launch) + + /* + * This is a nice place to set a breakpoint. + */ +LEAF(RunProgram) + LR t0,0(sp) # entry point + + j t0 # go for it. +END(RunProgram) + +/* ********************************************************************* + * CPU_KSEG0_SWITCH + * + * Hack the return address so we will come back in KSEG0 + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(cpu_kseg0_switch) + + and ra,(K0SIZE-1) + or ra,K0BASE + jr ra + +END(cpu_kseg0_switch) + +/* ********************************************************************* + * End + ********************************************************************* */ + + diff --git a/cfe/cfe/arch/mips/common/src/init_ram.S b/cfe/cfe/arch/mips/common/src/init_ram.S new file mode 100755 index 0000000..2531700 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/init_ram.S @@ -0,0 +1,889 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * CPU init module File: init_ram.S + * + * This module contains the vectors and lowest-level CPU startup + * functions for CFE. + * + * This is very similar to "init_mips.S" but is used when + * you want to locate CFE in DRAM, loading it like an + * application program. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "exception.h" + +#include "bsp_config.h" +#include "cpu_config.h" + +#include "cfe_devfuncs.h" + +/* ********************************************************************* + * Check some stuff + ********************************************************************* */ + +#if CFG_RELOC +#error "RAM version is not compatible with relocation." +#endif +#if !(CFG_RUNFROMKSEG0) +#error "RAM version should be run cached" +#endif + +#if CFG_MULTI_CPUS +#error "Multiple CPUs not compatible with RAM version" +#endif + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#include "mipsmacros.h" + + +/* ********************************************************************* + * SETLEDS(a,b,c,d) + * + * Sets the on-board LED display (if present). + * + * Input parameters: + * a,b,c,d - four ASCII characters (literal constants) + * + * Return value: + * a0,k1,ra trashed + ********************************************************************* */ + + +#define SETLEDS(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + jal board_setleds ; + + +/* ********************************************************************* + * Other constants + ********************************************************************* */ + +/* + * This is the size of the stack, rounded to KByte boundaries. + */ + +#ifndef CFG_STACK_SIZE +#error "CFG_STACK_SIZE not defined" +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +/* + * Duplicates from cfe_iocb.h -- warning! + */ + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 +#define CFE_CACHE_FLUSH_L2 16 +#define CFE_CACHE_INVAL_RANGE 32 +#define CFE_CACHE_FLUSH_RANGE 64 + + +/* + * To make life easier reading this code, define "KSEGBASE" + * to either K0BASE or K1BASE depending on whether we're running + * uncached. + */ + +#define KSEGBASE K0BASE /* RAM version always cached */ + + +/* ********************************************************************* + * Names of registers used in this module + ********************************************************************* */ + + .sdata + +#include "initdata.h" /* declare variables we use here */ + +#if CFG_MULTI_CPUS + .globl cfe_spinlock +cfe_spinlock: .word 0 +#endif + + .extern _fdata + .extern _edata + .extern _etext + +/* ********************************************************************* + * uninitialized data + ********************************************************************* */ + + .bss + + .comm __junk,4 + + .text + + .set noreorder + + +/* ********************************************************************* + * CFE Entry Point (used by OS boot loaders and such) + ********************************************************************* */ + + .set noreorder + + .globl vec_reset + +vec_reset: b cpu_reset + nop + + +vec_apientry: b cpu_apientry + nop + .word CFE_EPTSEAL + .word CFE_EPTSEAL + + .set reorder + + +/* ********************************************************************* + * Segment Table. + * + * Addresses of data segments and of certain routines we're going + * to call from KSEG1. These are here mostly for the embedded + * PIC case, since we can't count on the 'la' instruction to + * do the expected thing (the assembler expands it into a macro + * for doing GP-relative stuff, and the code is NOT GP-relative. + * So, we (relocatably) get the offset of this table and then + * index within it. + * + * Pointer values in this segment will be relative to KSEG0 for + * cached versions of CFE, so we need to OR in K1BASE in the + * case of calling to a uncached address. + * + * The LOADREL macro handles most of the nastiness here. + ********************************************************************* */ + + +#include "segtable.h" + + .globl segment_table +segment_table: + _LONG_ _etext # [ 0] End of text (R_SEG_ETEXT) + _LONG_ _fdata # [ 1] Beginning of data (R_SEG_FDATA) + _LONG_ _edata # [ 2] End of data (R_SEG_EDATA) + _LONG_ _end # [ 3] End of BSS (R_SEG_END) + _LONG_ _ftext # [ 4] Beginning of text (R_SEG_FTEXT) + _LONG_ _fbss # [ 5] Beginning of BSS (R_SEG_FBSS) + _LONG_ _gp # [ 6] Global Pointer (R_SEG_GP) + _LONG_ 0 # [ 7] Beginning of reloc entries + _LONG_ 0 # [ 8] End of reloc entries + _LONG_ cpu_apientry # [ 9] R_SEG_APIENTRY + + +/* ********************************************************************* + * Init Table. + * + * This is like segment_table except it contains pointers to + * routines used during initialization. It serves both as a + * table for doing PIC stuff and also to separate out + * machine-specific init routines. + * + * The CALLINIT_xxx macros are used to call routines in this table. + ********************************************************************* */ + + + .globl init_table +init_table: + _LONG_ board_earlyinit # [ 0] R_INIT_EARLYINIT + _LONG_ board_setleds # [ 1] R_INIT_SETLEDS + _LONG_ board_draminfo # [ 2] R_INIT_DRAMINFO + _LONG_ CPUCFG_CPUINIT # [ 3] R_INIT_CPUINIT + _LONG_ CPUCFG_ALTCPU_START1 # [ 4] R_INIT_ALTCPU_START1 + _LONG_ CPUCFG_ALTCPU_START2 # [ 5] R_INIT_ALTCPU_START2 + _LONG_ CPUCFG_ALTCPU_RESET # [ 6] R_INIT_ALTCPU_RESET + _LONG_ CPUCFG_CPURESTART # [ 7] R_INIT_CPURESTART + _LONG_ CPUCFG_DRAMINIT # [ 8] R_INIT_DRAMINIT + _LONG_ CPUCFG_CACHEOPS # [ 9] R_INIT_CACHEOPS + _LONG_ CPUCFG_TLBHANDLER # [ 10] R_INIT_TLBHANDLER + _LONG_ cfe_main # [ 11] R_INIT_CMDSTART + _LONG_ cfe_command_restart # [ 12] R_INIT_CMDRESTART + _LONG_ cfe_doxreq # [ 13] R_INIT_DOXREQ + _LONG_ CPUCFG_TP1_SWITCH # [ 14] R_INIT_TP1_SWITCH + _LONG_ bcmcore_null # [ 15] R_INIT_SIZERAM + +/* ********************************************************************* + * CPU Startup Code + ********************************************************************* */ + + +cpu_reset: + +#------------------------------------------------------------------------------ + + /* + * Do low-level board initialization. This is our first + * chance to customize the startup sequence. + */ + + CALLINIT_KSEG0(init_table,R_INIT_EARLYINIT) + + SETLEDS('H','E','L','O') + +#------------------------------------------------------------------------------ + + /* + * DRAM is now running, and we're alive in cacheable memory + * on cpu0 in K0SEG. Set up GP. + */ + + LOADREL(a0,segment_table) + LR gp,R_SEG_GP(a0) + +#------------------------------------------------------------------------------ + /* + * Zero BSS + */ + + SETLEDS('Z','B','S','S') + + LOADREL(a0,segment_table) +__ZeroBss: + + LR v0,R_SEG_FBSS(a0) + LR v1,R_SEG_END(a0) + +1: SR zero,0(v0) # Zero one cacheline at a time + SR zero,(REGSIZE*1)(v0) + SR zero,(REGSIZE*2)(v0) + SR zero,(REGSIZE*3)(v0) + add v0,REGSIZE*4 + blt v0,v1,1b + + +#------------------------------------------------------------------------------ + + li k0,256 # memory size in megabytes + + +#ifdef __long64 + mfc0 t0,C0_SR + or t0,t0,M_SR_KX + mtc0 t0,C0_SR +#endif + +#------------------------------------------------------------------------------ + + /* + * Remember total amount of memory. This is *still* in k0 + * after all this time. Hopefully. + */ + +__MemVars: + SR k0,mem_totalsize + SR zero,mem_datareloc + + move v0,zero + + LOADREL(a0,segment_table) # trashed by l2 cache flush + LR v0,R_SEG_FTEXT(a0) # bottom = beginning of text + LR v1,R_SEG_END(a0) + + SR v0,mem_bottomofmem + SR v1,mem_heapstart + + add v1,(CFG_HEAP_SIZE*1024) # Otherwise + add v1,STACK_SIZE + SR v1,mem_topofmem + + SR zero,mem_textreloc + + + LR t1,R_SEG_FTEXT(a0) + LR t0,R_SEG_ETEXT(a0) + sub t0,t0,t1 + SR t0,mem_textsize + SR t1,mem_textbase + + +#------------------------------------------------------------------------------ + +#if CFG_MULTI_CPUS + /* + * Let secondary CPU(s) run their idle loops. Set the + * mailbox register to our relocation factor so we can read + * it out of the mailbox register and relocate GP properly. + */ + + move a0,zero + CALLINIT_KSEG0(init_table,R_INIT_ALTCPU_START2) +#endif + + /* + * Stash away some config register stuff + */ + + mfc0 v0,C0_PRID + SR v0,cpu_prid + + +#------------------------------------------------------------------------------ + + /* + * Set up the "C" stack and jump to the main routine. + */ + + SETLEDS('M','A','I','N') + + LR sp,mem_heapstart + ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) + li a0,0 # call as "cfe_main(0,0)" + li a1,0 + + CALLINIT_KSEG0(init_table,R_INIT_CMDSTART) # should not return + + + /* + * Terminate the simulator. + */ + +crash_sim: li $2,1 + li $4,0 + syscall 0xCA + b cpu_reset + + + +/* ********************************************************************* + * CFE_WARMSTART + * + * Restart the command interpreter + * + * Input parameters: + * A0 - command status + * nothing (GP has already been set up for us) + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(cfe_warmstart) + + SR a0,0(sp) # store on old stack + LOADREL(v0,init_table) + LR v0,R_INIT_CPURESTART(v0) + jal v0 # had better not trash GP or K1 + LR a0,0(sp) + + LR sp,mem_heapstart + ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) + + /* + * If someone called the API to do a warm start, clear the + * spin lock, since the call will never return. + */ + +#if CFG_MULTI_CPUS + SPIN_UNLOCK(cfe_spinlock,t0) +#endif + + CALLINIT_KSEG0(init_table,R_INIT_CMDRESTART) # should not return + +END(cfe_warmstart) + +/* ********************************************************************* + * CFE_FLUSHCACHE + * + * Perform certain cache operations + * + * Input parameters: + * a0 - flags (CFE_CACHE_xxx flags, or zero for a default) + * a1,a2 - start/end of range for "range invalidate" operations + * (not used otherwise) + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_cfe_flushcache) + + sub sp,32 + SR ra,0(sp) + SR a0,8(sp) + SR s0,16(sp) + SR v1,24(sp) + + + CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) + + LR v1,24(sp) + LR s0,16(sp) + LR a0,8(sp) + LR ra,0(sp) + add sp,32 + j ra + +END(_cfe_flushcache) + + +/* ********************************************************************* + * CFE_LAUNCH + * + * Start the user program. The program is passed a handle + * that must be passed back when calling the firmware. + * + * Parameters passed to the called program are as follows: + * + * a0 - CFE handle + * a1 - entry vector + * a2 - reserved, will be 0 + * a3 - entrypoint signature. + * + * Input parameters: + * a0 - entry vector + * + * Return value: + * does not return + ********************************************************************* */ + +LEAF(cfe_launch) + + sub sp,8 + SR a0,0(sp) + + /* + * Mask all interrupts. + */ + mfc0 v0,C0_SR # Get current interrupt flag + li v1,M_SR_IE # master interrupt control + not v1 # disable interrupts + and v0,v1 # SR now has IE=0 + mtc0 v0,C0_SR # put back into CP0 + + /* + * Flush the D-Cache, since the program we loaded is "data". + * Invalidate the I-Cache, so that addresses in the program + * region will miss and need to be filled from the data we + * just flushed above. + */ + + li a0,CFE_CACHE_FLUSH_D|CFE_CACHE_INVAL_I + CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) + + /* + * Set things up for launching the program. Pass the + * handle in A0 - apps need to remember that and pass it + * back. + */ + + j RunProgram + +END(cfe_launch) + + /* + * This is a nice place to set a breakpoint. + */ +LEAF(RunProgram) + + LOADREL(a2,segment_table) + LR a2,R_SEG_APIENTRY(a2) # A2 = code entry + move t0,a0 # + move a1,zero # A1 = 0 + move a0,gp # A0 = handle + li a3,CFE_EPTSEAL # A3 = entrypoint signature + LR t0,0(sp) # entry point + j t0 # go for it. +END(RunProgram) + + + + +/* ********************************************************************* + * CFE_LEDS + * + * Set the on-board LEDs. + * + * Input parameters: + * a0 - LEDs + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(cfe_leds) + + j board_setleds # jump to BSP routine + +END(cfe_leds) + +/* ********************************************************************* + * TLB Fill Exeption Handler + ********************************************************************* */ + +cpu_tlbfill: + move k0,ra # Save, we're about to trash + LOADREL(k1,init_table) # Load offset of init table + LR k1,R_INIT_TLBHANDLER(k1) # Get entry from table + move ra,k0 # restore trashed ra + j k1 # Dispatch to handler + +/* ********************************************************************* + * XTLB Fill Exception Handler + ********************************************************************* */ + +cpu_xtlbfill: + j _exc_entry + +/* ********************************************************************* + * Cache Error Exception Handler + ********************************************************************* */ + +cpu_cacheerr: + j _exc_entry + + +/* ********************************************************************* + * General Exception Handler + ********************************************************************* */ + +cpu_exception: + j _exc_entry + + +/* ********************************************************************* + * General Interrupt Handler + ********************************************************************* */ + +cpu_interrupt: + j _exc_entry + + +/* ********************************************************************* + * EJTAG Debug Exception Handler + ********************************************************************* */ + +cpu_ejtag: + j cpu_reset + +/* ********************************************************************* + * cpu_apientry(handle,iocb) + * + * API entry point for external apps. + * + * Input parameters: + * a0 - firmware handle (used to determine the location of + * our relocated data) + * a1 - pointer to IOCB to execute + * + * Return value: + * v0 - return code, 0 if ok + ********************************************************************* */ + +#define _regidx(x) ((x)*8) + +#define CAE_SRSAVE _regidx(0) +#define CAE_GPSAVE _regidx(1) +#define CAE_RASAVE _regidx(2) +#define CAE_S0SAVE _regidx(3) +#define CAE_S1SAVE _regidx(4) +#define CAE_S2SAVE _regidx(5) +#define CAE_S3SAVE _regidx(6) +#define CAE_S4SAVE _regidx(7) +#define CAE_S5SAVE _regidx(8) +#define CAE_S6SAVE _regidx(9) +#define CAE_S7SAVE _regidx(10) + +#define CAE_STKSIZE _regidx(11) + +LEAF(cpu_apientry) + + sub sp,CAE_STKSIZE # Make room for our stuff + + mfc0 v0,C0_SR # Get current interrupt flag + SR v0,CAE_SRSAVE(sp) # save on stack + li t0,M_SR_IE # master interrupt control + not t0 # disable interrupts + and v0,t0 # SR now has IE=0 + mtc0 v0,C0_SR # put back into CP0 + + SR gp,CAE_GPSAVE(sp) # save GP + SR ra,CAE_RASAVE(sp) # and old RA + + SR s0,CAE_S0SAVE(sp) + SR s1,CAE_S1SAVE(sp) + SR s2,CAE_S2SAVE(sp) + SR s3,CAE_S3SAVE(sp) + SR s4,CAE_S4SAVE(sp) + SR s5,CAE_S5SAVE(sp) + SR s6,CAE_S6SAVE(sp) + SR s7,CAE_S7SAVE(sp) + + move gp,a0 # set up new GP + move a0,a1 # A0 points at IOCB + + +#if CFG_MULTI_CPUS + SPIN_LOCK(cfe_spinlock,t0,t1) +#endif + + CALLINIT_KSEG0(init_table,R_INIT_DOXREQ) # should not return + +#if CFG_MULTI_CPUS + SPIN_UNLOCK(cfe_spinlock,t0) +#endif + + # + # Restore the saved registers. + # + + LR s7,CAE_S7SAVE(sp) + LR s6,CAE_S6SAVE(sp) + LR s5,CAE_S5SAVE(sp) + LR s4,CAE_S4SAVE(sp) + LR s3,CAE_S3SAVE(sp) + LR s2,CAE_S2SAVE(sp) + LR s1,CAE_S1SAVE(sp) + LR s0,CAE_S0SAVE(sp) + + LR ra,CAE_RASAVE(sp) # unwind the stack + LR gp,CAE_GPSAVE(sp) + + LR t0,CAE_SRSAVE(sp) # old interrupt mask + + add sp,CAE_STKSIZE # restore old stack pointer + + mtc0 t0,C0_SR # restore interrupts + j ra + nop + +END(cpu_apientry) + + +/* ********************************************************************* + * CPU_KSEG0_SWITCH + * + * Hack the return address so we will come back in KSEG0 + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(cpu_kseg0_switch) + + and ra,(K0SIZE-1) + or ra,K0BASE + jr ra + +END(cpu_kseg0_switch) + + + + +/* ********************************************************************* + * _GETSTATUS() + * + * Read the STATUS register into v0 + * + * Input parameters: + * nothing + * + * Return value: + * v0 - Status register + ********************************************************************* */ + +LEAF(_getstatus) + + mfc0 v0,C0_SR + j ra +END(_getstatus) + + +/* ********************************************************************* + * _SETSTATUS() + * + * Set the STATUS register to the value in a0 + * + * Input parameters: + * nothing + * + * Return value: + * v0 - Status register + ********************************************************************* */ + +LEAF(_setstatus) + + mtc0 a0,C0_SR + j ra +END(_setstatus) + +/* ********************************************************************* + * _GETCAUSE() + * + * Read the CAUSE register into v0 + * + * Input parameters: + * nothing + * + * Return value: + * v0 - Cause register + ********************************************************************* */ + +LEAF(_getcause) + + mfc0 v0,C0_CAUSE + j ra +END(_getcause) + + +/* ********************************************************************* + * _GETTICKS() + * + * Read the COUNT register into v0 + * + * Input parameters: + * nothing + * + * Return value: + * v0 - count register + ********************************************************************* */ + +LEAF(_getticks) + + mfc0 v0,C0_COUNT + j ra +END(_getticks) + + +/* ********************************************************************* + * _SETALARM(ticks) + * + * Set the C0_Compare register from a0 + * + * Input parameters: + * a0 - compare register + * + * Return value: + * none + ********************************************************************* */ + +LEAF(_setalarm) + + mtc0 a0,C0_COMPARE + j ra +END(_setalarm) + + +/* ********************************************************************* + * _SETCONTEXT() + * + * Set the CONTEXT register. + * + * Input parameters: + * a0 - context + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_setcontext) + + mtc0 a0,C0_CTEXT + j ra +END(_setcontext) + +/* ********************************************************************* + * _GETSEGTBL() + * + * Return the address of the segment table. We use this + * to display the startup messages. + * + * You can't just address the table from C because it lives + * in the text segment. + * + * Input parameters: + * nothing + * + * Return value: + * address of table + ********************************************************************* */ + + +LEAF(_getsegtbl) + move t0,ra + LOADREL(v0,segment_table) + move ra,t0 + j ra +END(_getsegtbl) + + +/* ********************************************************************* + * _wbflush() + * + * Flush the write buffer. This is probably not necessary + * on SiByte CPUs, but we have it for completeness. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(_wbflush) + + sync /* drain the buffers */ + la t0,__junk /* do an uncached read to force it out */ + or t0,K1BASE + lw zero,0(t0) + j ra + +END(_wbflush) + + +/* ********************************************************************* + * End + ********************************************************************* */ + + diff --git a/cfe/cfe/arch/mips/common/src/lib_hssubr.S b/cfe/cfe/arch/mips/common/src/lib_hssubr.S new file mode 100644 index 0000000..07085e3 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/lib_hssubr.S @@ -0,0 +1,194 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Hyperspace Subroutines File: lib_hssubr.S + * + * Little stub routines to allow access to KXSEG from 32-bit progs. + * + * Author: Mitch Lichtenberg (mitch@sibyte.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "mipsmacros.h" +#include "cpu_config.h" /* for definition of HAZARD */ + + +/* ********************************************************************* + * hs_read8 - read 8-bit bytes + ********************************************************************* */ + + +LEAF(hs_read8) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + lbu v0,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_read8) + +/* ********************************************************************* + * hs_read16 - read 16-bit shorts + ********************************************************************* */ + +LEAF(hs_read16) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + lhu v0,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_read16) + +/* ********************************************************************* + * hs_read32 - read 32-bit ints + ********************************************************************* */ + +LEAF(hs_read32) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + lw v0,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_read32) + +/* ********************************************************************* + * hs_read64 - read 64-bit longs + ********************************************************************* */ + +LEAF(hs_read64) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + ld v0,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_read64) + +/* ********************************************************************* + * hs_write8 - write 8-bit bytes + ********************************************************************* */ + +LEAF(hs_write8) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + sb a1,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_write8) + +/* ********************************************************************* + * hs_write16 - write 16-bit shorts + ********************************************************************* */ + +LEAF(hs_write16) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + sh a1,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_write16) + +/* ********************************************************************* + * hs_write32 - write 32-bit longs + ********************************************************************* */ + +LEAF(hs_write32) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + sw a1,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_write32) + +/* ********************************************************************* + * hs_write64 - write 64-bit longs + ********************************************************************* */ + +LEAF(hs_write64) + mfc0 t2,C0_SR + or t1,t2,M_SR_KX + mtc0 t1,C0_SR + HAZARD + + sd a1,(a0) + + mtc0 t2,C0_SR + HAZARD + j ra +END(hs_write64) + + +/* ********************************************************************* + * End + ********************************************************************* */ + diff --git a/cfe/cfe/arch/mips/common/src/lib_physio.S b/cfe/cfe/arch/mips/common/src/lib_physio.S new file mode 100644 index 0000000..7f57fea --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/lib_physio.S @@ -0,0 +1,173 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Physical memory peek/poke routines File: lib_physio.S + * + * Little stub routines to allow access to arbitrary physical + * addresses. In most cases this should not be needed, as + * many physical addresses are within kseg1, but this handles + * the cases that are not automagically, so we don't need + * to mess up the code with icky macros and such. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "mipsmacros.h" +#include "cpu_config.h" /* for definition of HAZARD */ + + +/* ********************************************************************* + * PHYSOP(inst,a) + * + * Macro to construct code for doing the physical I/O + * We try to avoid messing with KX or doing 64-bit stuff + * unless necessary. + * + * Input parameters: + * INST - instruction name to run + * A - register containing arg or return value + * + * Return value: + * nothing + ********************************************************************* */ + + + +#ifdef _MIPSREGS32_ +#define PHYSOP(INST,A) \ + or a0,a0,K1BASE ; \ + INST A,0(a0) ; \ + j ra ; +#else +#define PHYSOP(INST,A) \ + lui t0,0x2000 ; \ + bgeu a0,t0,1f ; \ + or a0,a0,K1BASE ; \ + INST A,0(a0) ; \ + j ra ; \ +1: lui t0,0x9000 ; \ + dsll t0,t0,32 ; \ + or a0,a0,t0 ; \ + mfc0 t1,C0_SR ; \ + and t0,t1,M_SR_KX ; \ + beq t0,zero,1f ; \ + INST A,0(a0) ; \ + j ra ; \ +1: or t0,t1,M_SR_KX ; \ + mtc0 t0,C0_SR ; \ + HAZARD ; \ + INST A,0(a0) ; \ + mtc0 t1,C0_SR ; \ + HAZARD ; \ + j ra ; +#endif + + +/* ********************************************************************* + * phys_read8 - read 8-bit bytes + ********************************************************************* */ + + +LEAF(phys_read8) +PHYSOP(lbu,v0) +END(phys_read8) + +/* ********************************************************************* + * phys_read16 - read 16-bit shorts + ********************************************************************* */ + +LEAF(phys_read16) +PHYSOP(lh,v0) +END(phys_read16) + +/* ********************************************************************* + * phys_read32 - read 32-bit ints + ********************************************************************* */ + +LEAF(phys_read32) +PHYSOP(lw,v0) +END(phys_read32) + +/* ********************************************************************* + * phys_read64 - read 64-bit longs + ********************************************************************* */ + +LEAF(phys_read64) +PHYSOP(ld,v0) +END(phys_read64) + +/* ********************************************************************* + * phys_write8 - write 8-bit bytes + ********************************************************************* */ + +LEAF(phys_write8) +PHYSOP(sb,a1) +END(phys_write8) + +/* ********************************************************************* + * phys_write16 - write 16-bit shorts + ********************************************************************* */ + +LEAF(phys_write16) +PHYSOP(sh,a1) +END(phys_write16) + +/* ********************************************************************* + * phys_write32 - write 32-bit longs + ********************************************************************* */ + +LEAF(phys_write32) +PHYSOP(sw,a1) +END(phys_write32) + +/* ********************************************************************* + * phys_write64 - write 64-bit longs + ********************************************************************* */ + +LEAF(phys_write64) +PHYSOP(sd,a1) +END(phys_write64) + + +/* ********************************************************************* + * End + ********************************************************************* */ + diff --git a/cfe/cfe/arch/mips/common/src/lib_setjmp.S b/cfe/cfe/arch/mips/common/src/lib_setjmp.S new file mode 100644 index 0000000..b8c82b3 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/lib_setjmp.S @@ -0,0 +1,94 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Simple setjmp/longjmp File: lib_setjmp.S + * + * A very simple SETJMP and LONGJMP + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + + +#include "sbmips.h" +#include "lib_setjmp.h" + +#ifdef _MIPSREGS32_ +#define SREG sw +#define LREG lw +#else +#define SREG sd +#define LREG ld +#endif + +LEAF(lib_setjmp) + + SREG s0,JMPB_S0(a0) + SREG s1,JMPB_S1(a0) + SREG s2,JMPB_S2(a0) + SREG s3,JMPB_S3(a0) + SREG s4,JMPB_S4(a0) + SREG s5,JMPB_S5(a0) + SREG s6,JMPB_S6(a0) + SREG s7,JMPB_S7(a0) + SREG fp,JMPB_FP(a0) + SREG sp,JMPB_SP(a0) + SREG ra,JMPB_RA(a0) + move v0,zero + j ra + +END(lib_setjmp) + +LEAF(lib_longjmp) + LREG s0,JMPB_S0(a0) + LREG s1,JMPB_S1(a0) + LREG s2,JMPB_S2(a0) + LREG s3,JMPB_S3(a0) + LREG s4,JMPB_S4(a0) + LREG s5,JMPB_S5(a0) + LREG s6,JMPB_S6(a0) + LREG s7,JMPB_S7(a0) + LREG fp,JMPB_FP(a0) + LREG sp,JMPB_SP(a0) + LREG ra,JMPB_RA(a0) + move v0,a1 + jr ra +END(lib_longjmp) + diff --git a/cfe/cfe/arch/mips/common/src/mips_arena.c b/cfe/cfe/arch/mips/common/src/mips_arena.c new file mode 100644 index 0000000..d96fee6 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/mips_arena.c @@ -0,0 +1,186 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Physical Memory (arena) manager File: sb1250_arena.c + * + * This module describes the physical memory available to the + * firmware. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_arena.h" + +#include "cfe_error.h" + +#include "cfe.h" +#include "cfe_mem.h" + +#include "initdata.h" + +#define _NOPROTOS_ +#include "cfe_boot.h" +#undef _NOPROTOS_ + +#include "cpu_config.h" + +#include "addrspace.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + + +#define MEG (1024*1024) +#define KB 1024 +#define PAGESIZE 4096 +#define CFE_BOOTAREA_SIZE (256*KB) +#define CFE_BOOTAREA_ADDR 0x20000000 + + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +extern arena_t cfe_arena; +uint64_t *cfe_pagetable = NULL; + +extern void CPUCFG_PAGETBLINIT(uint64_t *ptaddr,unsigned int ptstart); + +void cfe_bootarea_init(void); +extern void _setcontext(int64_t); + + +/* ********************************************************************* + * CFE_BOOTAREA_INIT() + * + * Initialize the page table and map our boot program area. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_bootarea_init(void) +{ + unsigned char *pte; + int64_t pte_int; + unsigned int addr = 16*MEG; + unsigned int topmem; + unsigned int topcfe; + unsigned int botcfe; + unsigned int beforecfe; + unsigned int aftercfe; + + /* + * Calculate the location where the boot area will + * live. It lives either above or below the + * firmware, depending on where there's more space. + */ + + /* + * The firmware will always be loaded in the first + * 256M. Calculate the top of that region. The bottom + * of that region is always the beginning of our + * data segment. + */ + if (mem_totalsize > (uint64_t)256) { + topmem = 256*MEG; + } + else { + topmem = (unsigned int) (mem_totalsize << 20); + } + botcfe = (unsigned int) K1_TO_PHYS(mem_bottomofmem); + topcfe = (unsigned int) K1_TO_PHYS(mem_topofmem); + + beforecfe = botcfe; + aftercfe = topmem-topcfe; + + if (beforecfe > aftercfe) { + botcfe -= (PAGESIZE-1); + botcfe &= ~(PAGESIZE-1); /* round down to page boundary */ + addr = botcfe - CFE_BOOTAREA_SIZE; /* this is the address */ + } + else { + topcfe += (PAGESIZE-1); /* round *up* to a page address */ + topcfe &= ~(PAGESIZE-1); + addr = topcfe; + } + + mem_bootarea_start = addr; + mem_bootarea_size = CFE_BOOTAREA_SIZE; + + /* + * Allocate the page table + */ + + pte = KMALLOC(1024,1024); + +#ifdef __long64 + pte_int = (int64_t) pte; +#else + pte_int = (int64_t) ((int) pte); +#endif + + /* + * Set the CP0 CONTEXT register to point at the page table + */ + + pte_int <<= 13; + cfe_pagetable = (uint64_t *) pte; + + _setcontext(pte_int); + + + /* + * Initialize page table entries + */ + + CPUCFG_PAGETBLINIT(cfe_pagetable,addr); + + +} + diff --git a/cfe/cfe/arch/mips/common/src/tools.mk b/cfe/cfe/arch/mips/common/src/tools.mk new file mode 100755 index 0000000..d195de9 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/tools.mk @@ -0,0 +1,83 @@ +# +# Basic compiler options and preprocessor flags +# + +CFLAGS += -g -c -ffreestanding +CFLAGS += -O1 -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes + +# +# Tools locations +# + +ifndef TOOLS +TOOLS=/opt/toolchains/uclibc-crosstools-gcc-4.4.2-1/usr/bin/mips-linux- +endif + +GCC ?= $(TOOLS)gcc +GLD ?= $(TOOLS)ld +AR ?= $(TOOLS)ar +OBJDUMP ?= $(TOOLS)objdump +OBJCOPY ?= $(TOOLS)objcopy +RANLIB ?= $(TOOLS)ranlib + +# +# Check for 64-bit mode +# + +ifeq ($(strip ${CFG_MLONG64}),1) + CFLAGS += -mlong64 -D__long64 +endif + +# +# Figure out which linker script to use +# + +ifeq ($(strip ${CFG_RAMAPP}),1) + CFLAGS += -DCFG_RAMAPP=1 + LDFLAGS = -g --script ${ARCH_SRC}/cfe_ramapp.lds + CFLAGS += -DCFG_RUNFROMKSEG0=1 +else + ifeq ($(strip ${CFG_RELOC}),0) + ifeq ($(strip ${CFG_BOOTRAM}),1) + CFLAGS += -DCFG_BOOTRAM=1 + ROMRAM = ram + else + CFLAGS += -DCFG_BOOTRAM=0 + ROMRAM = rom + endif + ifeq ($(strip ${CFG_UNCACHED}),1) + CFLAGS += -DCFG_RUNFROMKSEG0=0 + LDFLAGS = -g --script ${ARCH_SRC}/cfe_${ROMRAM}_uncached.lds + else + CFLAGS += -DCFG_RUNFROMKSEG0=1 + LDFLAGS = -g --script ${ARCH_SRC}/cfe_${ROMRAM}_cached.lds + endif + else + CFLAGS += -membedded-pic -mlong-calls -DCFG_EMBEDDED_PIC=1 + ifeq ($(strip ${CFG_UNCACHED}),1) + CFLAGS += -DCFG_RUNFROMKSEG0=0 + LDFLAGS = -g --script ${ARCH_SRC}/cfe_rom_reloc_uncached.lds --embedded-relocs + else + CFLAGS += -DCFG_RUNFROMKSEG0=1 + ifeq ($(strip ${CFG_TEXTAT1MB}),1) + LDFLAGS = -g --script ${ARCH_SRC}/cfe_rom_reloc_cached_biendian.lds --embedded-relocs + else + LDFLAGS = -g --script ${ARCH_SRC}/cfe_rom_reloc_cached.lds --embedded-relocs + endif + endif + endif +endif +# +# Determine target endianness +# + +ifeq ($(strip ${CFG_LITTLE}),1) + ENDIAN = -EL + CFLAGS += -EL + LDFLAGS += -EL +else + ENDIAN = -EB + CFLAGS += -EB + LDFLAGS += -EB +endif + diff --git a/cfe/cfe/arch/mips/common/src/ui_memtest.c b/cfe/cfe/arch/mips/common/src/ui_memtest.c new file mode 100644 index 0000000..5388fd8 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/ui_memtest.c @@ -0,0 +1,282 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Test commands File: ui_memtest.c + * + * A simple memory test + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" + +#include "cfe_error.h" + +#include "ui_command.h" +#include "cfe.h" + +#include "bsp_config.h" + +#include "cfe_mem.h" + + +#ifdef __long64 +static int ui_cmd_memorytest(ui_cmdline_t *cmd,int argc,char *argv[]); +#endif + +#ifndef _SB_MAKE64 +#define _SB_MAKE64(x) ((uint64_t)(x)) +#endif +#ifndef _SB_MAKEMASK +#define _SB_MAKEMASK(v,n) (_SB_MAKE64((_SB_MAKE64(1)<<(v))-1) << _SB_MAKE64(n)) +#endif +#ifndef _SB_MAKEMASK1 +#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n)) +#endif + + +int ui_init_memtestcmds(void); + +int ui_init_memtestcmds(void) +{ +#ifdef __long64 + cmd_addcmd("memorytest", + ui_cmd_memorytest, + NULL, + "Tests all available memory", + "", + "-loop;Loop forever or until keypress|" + "-stoponerror;Stop if error occurs while looping|" + "-cca=*;Use specified cacheability attribute|" + "-arena=*;Test only specified arena index"); +#endif + return 0; +} + + +#ifdef __long64 +/* extensive memory tests */ + +static void inline uacwrite(volatile long *srcadr,long *dstadr) +{ +__asm __volatile ("ld $8, 0(%0) ; " + "ld $9, 8(%0) ; " + "ld $10, 16(%0) ; " + "ld $11, 24(%0) ; " + "sync ; " + "sd $8, 0(%1) ; " + "sd $9, 8(%1) ; " + "sd $10, 16(%1) ; " + "sd $11, 24(%1) ; " + "sync" :: "r"(srcadr),"r"(dstadr) : "$8","$9","$10","$11"); +} + + +#define TEST_DATA_LEN 4 +#define CACHE_LINE_LEN 32 + +static int ui_cmd_memorytest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + + static volatile long test_data[TEST_DATA_LEN] = { + 0xaaaaaaaaaaaaaaaa, 0x5555555555555555, 0xcccccccccccccccc, 0x3333333333333333, /* one cache line */ + }; + int arena, exitLoop; + int error; + int arena_type; + uint64_t arena_start, arena_size; + long phys_addr, offset, mem_base, cache_mem_base, i; + long *dst_adr, *cache_dst_adr; + long cda,tda; + int forever; + int passcnt; + int stoponerr = 0; + int cca = K_CALG_UNCACHED_ACCEL; + int arenanum = -1; + char *x; + + arena = 0; + exitLoop = 0; + offset = 0; + mem_base = 0; + passcnt = 0; + error = 0; + + forever = cmd_sw_isset(cmd,"-loop"); + stoponerr = cmd_sw_isset(cmd,"-stoponerror"); + if (cmd_sw_value(cmd,"-cca",&x)) cca = atoi(x); + if (cmd_sw_value(cmd,"-arena",&x)) arenanum = atoi(x); + + printf("Available memory arenas:\n"); + while (cfe_arena_enum(arena, &arena_type, &arena_start, &arena_size, FALSE) == 0) { + phys_addr = (long) arena_start; /* actual physical address */ + mem_base = PHYS_TO_XKPHYS(cca, phys_addr); /* virtual address */ + xprintf("phys = %016llX, virt = %016llX, size = %016llX\n", phys_addr, mem_base, arena_size); + arena++; + } + + printf("\nTesting memory.\n"); + do { + + passcnt++; + if (forever) { + if (console_status()) break; + printf("***** Iteration %d *****\n",passcnt); + } + + arena = 0; + exitLoop = 0; + error = 0; + + while (cfe_arena_enum(arena, &arena_type, &arena_start, &arena_size, FALSE) == 0) { + + if ((arenanum >= 0) && (arena != arenanum)) { + arena++; + continue; + } + + test_data[0] = 0xAAAAAAAAAAAAAAAA; + test_data[1] = 0x5555555555555555; + test_data[2] = 0xCCCCCCCCCCCCCCCC; + test_data[3] = 0x3333333333333333; + + phys_addr = (long) arena_start; /* actual physical address */ + mem_base = PHYS_TO_XKPHYS(cca, phys_addr); /* virtual address */ + cache_mem_base = PHYS_TO_K0(phys_addr); + + xprintf("\n"); + xprintf("Testing: phys = %016llX, virt = %016llX, size = %016llX\n", phys_addr, mem_base, arena_size); + + xprintf("Writing: a/5/c/3\n"); + + for (offset = 0; (offset < arena_size); offset += CACHE_LINE_LEN) { + dst_adr = (long*)(mem_base+offset); + uacwrite(test_data, dst_adr); + } + + xprintf("Reading: a/5/c/3\n"); + + for (offset = 0; (offset < arena_size); offset += CACHE_LINE_LEN) { + dst_adr = (long*)(mem_base+offset); + cache_dst_adr = (long*)(mem_base+offset); + for (i = 0; i < TEST_DATA_LEN; i++) { + cda = cache_dst_adr[i]; + tda = test_data[i]; + if (cda != tda) { + xprintf("mem[%016llX] %016llX != %016llX\n", + mem_base+offset+(i*8), cda, tda); + exitLoop = 1; + } + } + if (exitLoop) break; + } + + + if (exitLoop) { + exitLoop = 0; + error++; + arena++; + continue; + } + + xprintf("Writing: address|5555/inv/aaaa|address\n"); + exitLoop = 0; + + for (offset = 0; (offset < arena_size); offset += CACHE_LINE_LEN) { + dst_adr = (long*)(mem_base+offset); + test_data[0] = ((long)dst_adr<<32)|0x55555555; + test_data[1] = ~test_data[0]; + test_data[2] = 0xaaaaaaaa00000000|((long)dst_adr & 0xffffffff); + test_data[3] = ~test_data[2]; + uacwrite(test_data, dst_adr); + } + + xprintf("Reading: address|5555/inv/aaaa|address\n"); + + for (offset = 0; (offset < arena_size); offset += CACHE_LINE_LEN) { + dst_adr = (long*)(mem_base+offset); + test_data[0] = ((long)dst_adr<<32)|0x55555555; + test_data[1] = ~test_data[0]; + test_data[2] = 0xaaaaaaaa00000000|((long)dst_adr & 0xffffffff); + test_data[3] = ~test_data[2]; + cache_dst_adr = (long*)(mem_base+offset); + for (i = 0; i < TEST_DATA_LEN; i++) { + cda = cache_dst_adr[i]; + tda = test_data[i]; + if (cda != tda) { + xprintf("mem[%016llX] %016llX != %016llX\n", + mem_base+offset+(i*8),cda,tda); + exitLoop = 1; + } + } + if (exitLoop) break; + } + + if (exitLoop) { + error++; + exitLoop = 0; + if (stoponerr) forever = 0; + } + + arena++; + } + } while (forever); + + if (error) printf("Failing address: %016llX\n",mem_base+offset); + + return error ? -1 : 0; +} + +#endif + + + + diff --git a/cfe/cfe/arch/mips/cpu/SIBYTE_PRIVATE_FILES b/cfe/cfe/arch/mips/cpu/SIBYTE_PRIVATE_FILES new file mode 100644 index 0000000..1e7d4b6 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/SIBYTE_PRIVATE_FILES @@ -0,0 +1,2 @@ +bcmcore +bcm1400 diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/include/bcm4710.h b/cfe/cfe/arch/mips/cpu/bcmcore/include/bcm4710.h new file mode 100644 index 0000000..f499bc9 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/include/bcm4710.h @@ -0,0 +1,58 @@ +/* + Copyright 2001, Broadcom Corporation + All Rights Reserved. + + This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + the contents of this file may not be disclosed to third parties, copied or + duplicated in any form, in whole or in part, without the prior written + permission of Broadcom Corporation. +*/ +/* + * BCM4710 address space map and definitions + * + * Think twice before adding to this file, this is not the kitchen sink + * These definitions are not guaranteed for all 47xx chips, only the 4710 + * + * Copyright (C) 2000 Broadcom Corporation + * $Id: bcm4710.h,v 1.1 2001/10/31 18:49:25 mpl Exp $ + */ + +#ifndef _bcm4710_h_ +#define _bcm4710_h_ + +/* Address map */ +#define BCM4710_SDRAM 0x00000000 /* Physical SDRAM */ +#define BCM4710_PCI_MEM 0x08000000 /* Host Mode PCI memory access space (64 MB) */ +#define BCM4710_PCI_CFG 0x0c000000 /* Host Mode PCI configuration space (64 MB) */ +#define BCM4710_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */ +#define BCM4710_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ +#define BCM4710_ENUM 0x18000000 /* Beginning of core enumeration space */ + +/* Core register space */ +#define BCM4710_REG_SDRAM 0x18000000 /* SDRAM core registers */ +#define BCM4710_REG_ILINE20 0x18001000 /* InsideLine20 core registers */ +#define BCM4710_REG_EMAC0 0x18002000 /* Ethernet MAC 0 core registers */ +#define BCM4710_REG_CODEC 0x18003000 /* Codec core registers */ +#define BCM4710_REG_USB 0x18004000 /* USB core registers */ +#define BCM4710_REG_PCI 0x18005000 /* PCI core registers */ +#define BCM4710_REG_MIPS 0x18006000 /* MIPS core registers */ +#define BCM4710_REG_EXTIF 0x18007000 /* External Interface core registers */ +#define BCM4710_REG_EMAC1 0x18008000 /* Ethernet MAC 1 core registers */ + +#define BCM4710_EXTIF 0x1f000000 /* External Interface base address */ +#define BCM4710_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */ + +#define BCM4710_UART (BCM4710_REG_EXTIF + 0x00000300) + +#define BCM4710_EUART (BCM4710_EXTIF + 0x00800000) +#define BCM4710_LED (BCM4710_EXTIF + 0x00900000) + +#ifdef CONFIG_VSIM +#define BCM4710_TRACE(trval) do { *((int *)0xa0002ff8) = (trval); } while (0) +#else +#define BCM4710_TRACE(trval) do { *((unsigned char *)KSEG1ADDR(BCM4710_LED)) = (trval); \ + *((int *)0xa0002ff8) = (trval); } while (0) +#endif + + +#endif /* _bcm4710_h_ */ diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/include/bcm47xx.h b/cfe/cfe/arch/mips/cpu/bcmcore/include/bcm47xx.h new file mode 100644 index 0000000..eb752e5 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/include/bcm47xx.h @@ -0,0 +1,8 @@ +#ifndef _BCM47XX_H +#define _BCM47XX_H + +/* uart defaults */ +#define DIV_LO 0x36 +#define DIV_HI 0 + +#endif diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/include/bcmnvram.h b/cfe/cfe/arch/mips/cpu/bcmcore/include/bcmnvram.h new file mode 100644 index 0000000..b9d37e6 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/include/bcmnvram.h @@ -0,0 +1,123 @@ +/* + Copyright 2001, Broadcom Corporation + All Rights Reserved. + + This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + the contents of this file may not be disclosed to third parties, copied or + duplicated in any form, in whole or in part, without the prior written + permission of Broadcom Corporation. +*/ +/* + * NVRAM variable manipulation + * + * Copyright (C) 2001 Broadcom Corporation + * + * $Id: bcmnvram.h,v 1.1 2001/10/31 18:49:25 mpl Exp $ + */ + +#ifndef _bcmnvram_h_ +#define _bcmnvram_h_ + +#ifndef _LANGUAGE_ASSEMBLY + +struct nvram_header { + unsigned long magic; + unsigned long len; + unsigned long crc_ver_init; /* 0:7 crc, 8:15 ver, 16:27 init, mem. test 28, 29-31 reserved */ + unsigned long config_refresh; /* 0:15 config, 16:31 refresh */ + unsigned long reserved; +}; + +struct nvram_tuple { + char *name; + char *value; + struct nvram_tuple *next; +}; + +/* Compatibility */ +typedef struct nvram_tuple EnvRec; + +/* + * Get the value of an NVRAM variable + * @param name name of variable to get + * @return value of variable or NULL if undefined + */ +extern char * nvram_get(const char *name); + +/* + * Get the value of an NVRAM variable + * @param name name of variable to get + * @return value of variable or NUL if undefined + */ +#define nvram_safe_get(name) (nvram_get(name) ? : "") + +/* + * Match an NVRAM variable + * @param name name of variable to match + * @param match value to compare against value of variable + * @return TRUE if variable is defined and its value is string equal to match or FALSE otherwise + */ +#define nvram_match(name, match) ({ \ + const char *value = nvram_get(name); \ + (value && !strcmp(value, match)); \ +}) + +/* + * Match an NVRAM variable + * @param name name of variable to match + * @param match value to compare against value of variable + * @return TRUE if variable is defined and its value is not string equal to invmatch or FALSE otherwise + */ +#define nvram_invmatch(name, invmatch) ({ \ + const char *value = nvram_get(name); \ + (value && strcmp(value, invmatch)); \ +}) + +/* + * Set the value of an NVRAM variable + * @param name name of variable to set + * @param value value of variable + * @return 0 on success and errno on failure + * NOTE: use nvram_commit to commit this change to flash. + */ +extern int nvram_set(const char *name, const char *value); + +/* + * Unset an NVRAM variable + * @param name name of variable to unset + * @return 0 on success and errno on failure + * NOTE: use nvram_commit to commit this change to flash. + */ +extern int nvram_unset(const char *name); + +/* + * Permanently commit NVRAM variables + * @return 0 on success and errno on failure + */ +extern int nvram_commit(void); + +/* + * Get all NVRAM variables (format name=value\0 ... \0\0) + * @param buf buffer to store variables + * @param count size of buffer in bytes + * @return 0 on success and errno on failure + */ +extern int nvram_getall(char *buf, int count); + +/* + * Invalidate the current NVRAM header + * @return 0 on success and errno on failure + */ +extern int nvram_invalidate(void); + +#endif /* _LANGUAGE_ASSEMBLY */ + +#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ +#define NVRAM_VERSION 1 +#define NVRAM_HEADER_SIZE 20 +#define NVRAM_FIRST_LOC 0xbfcf8000 +#define NVRAM_LAST_LOC 0xbfff8000 +#define NVRAM_LOC_GAP 0x100000 +#define NVRAM_SPACE 0x8000 + +#endif /* _bcmnvram_h_ */ diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/include/cpu_config.h b/cfe/cfe/arch/mips/cpu/bcmcore/include/cpu_config.h new file mode 100755 index 0000000..51cf4e1 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/include/cpu_config.h @@ -0,0 +1,62 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * CPU Configuration file File: cpu_config.h + * + * This file contains the names of the routines to be used + * in the dispatch table in init_mips.S + * + * It lives here in the CPU directory so we can direct + * the init calls to routines named in this directory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * XX Copyright 2000,2001 + * Broadcom Corporation. All rights reserved. + * + * BROADCOM PROPRIETARY AND CONFIDENTIAL + * + * This software is furnished under license and may be used and + * copied only in accordance with the license. + ********************************************************************* */ + +/* + */ + +#define CPUCFG_CPUINIT bcmcore_cpuinit +#define CPUCFG_ALTCPU_START1 bcmcore_null +#define CPUCFG_ALTCPU_START2 bcmcore_null +#define CPUCFG_ALTCPU_RESET bcmcore_null +#define CPUCFG_CPURESTART bcmcore_cpurestart +#define CPUCFG_DRAMINIT board_draminit /* no dram on CPU */ +#define CPUCFG_CACHEOPS bcmcore_cacheops +#define CPUCFG_ARENAINIT bcmcore_arena_init +#define CPUCFG_PAGETBLINIT bcmcore_pagetable_init +#define CPUCFG_TLBHANDLER bcmcore_tlbhandler +#define CPUCFG_DIAG_TEST1 bcmcore_null +#define CPUCFG_DIAG_TEST2 bcmcore_null +#if CFG_CMT +#define CPUCFG_TP1_SWITCH bcmcore_tp1_switch +#else +#define CPUCFG_TP1_SWITCH bcmcore_null +#endif +/* + * The BCMCORE ticks CP0 every other cycle. + */ + +#define CPUCFG_CYCLESPERCPUTICK 2 + +/* + * Hazard macro + */ + +#define HAZARD nop ; nop ; nop ; nop ; nop ; nop ; nop +#define ERET \ + .set push ; \ + .set mips4 ; \ + eret ; \ + .set pop + + diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/include/sbmips.h b/cfe/cfe/arch/mips/cpu/bcmcore/include/sbmips.h new file mode 100644 index 0000000..0f4e055 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/include/sbmips.h @@ -0,0 +1,670 @@ +/* ********************************************************************* + * SB1250 Board Support Package + * + * MIPS64 CPU definitions File: sbmips.h + * + * This module contains constants and macros specific to the + * SB1 MIPS64 core. + * + * Author: Mitch Lichtenberg (mitch@sibyte.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _SB_MIPS_H +#define _SB_MIPS_H + +/* ********************************************************************* + * Configure language + ********************************************************************* */ + +#if defined(__ASSEMBLER__) +#define _ATYPE_ +#define _ATYPE32_ +#define _ATYPE64_ +#else +#define _ATYPE_ (__SIZE_TYPE__) +#define _ATYPE32_ (int) +#define _ATYPE64_ (long long) +#endif + + +/* ********************************************************************* + * Bitfield macros + ********************************************************************* */ + +/* + * Make a mask for 1 bit at position 'n' + */ + +#define _MM_MAKEMASK1(n) (1 << (n)) + +/* + * Make a mask for 'v' bits at position 'n' + */ + +#define _MM_MAKEMASK(v,n) (((1<<(v))-1) << (n)) + +/* + * Make a value at 'v' at bit position 'n' + */ + +#define _MM_MAKEVALUE(v,n) ((v) << (n)) + +/* + * Retrieve a value from 'v' at bit position 'n' with 'm' mask bits + */ + +#define _MM_GETVALUE(v,n,m) (((v) & (m)) >> (n)) + + + +/* ********************************************************************* + * 32-bit MIPS Address Spaces + ********************************************************************* */ + +#ifdef __ASSEMBLER__ +#define _ACAST32_ +#define _ACAST64_ +#else +#define _ACAST32_ _ATYPE_ _ATYPE32_ /* widen if necessary */ +#define _ACAST64_ _ATYPE64_ /* do _not_ narrow */ +#endif + +/* 32-bit address map */ +#define UBASE 0x00000000 /* user+ mapped */ +#define USIZE 0x80000000 +#define K0BASE (_ACAST32_ 0x80000000) /* kernel unmapped cached */ +#define K0SIZE 0x20000000 +#define K1BASE (_ACAST32_ 0xa0000000) /* kernel unmapped uncached */ +#define K1SIZE 0x20000000 +#define KSBASE (_ACAST32_ 0xc0000000) /* supervisor+ mapped */ +#define KSSIZE 0x20000000 +#define K3BASE (_ACAST32_ 0xe0000000) /* kernel mapped */ +#define K3SIZE 0x20000000 + +/* 64-bit address map additions to the above (sign-extended) ranges */ +#define XUBASE (_ACAST64_ 0x0000000080000000) /* user+ mapped */ +#define XUSIZE (_ACAST64_ 0x00000FFF80000000) +#define XSSEGBASE (_ACAST64_ 0x4000000000000000) /* supervisor+ mapped */ +#define XSSEGSIZE (_ACAST64_ 0x0000100000000000) +#define XKPHYSBASE (_ACAST64_ 0x8000000000000000) /* kernel unmapped */ +#define XKPHYSSIZE (_ACAST64_ 0x0000100000000000) +#define XKSEGBASE (_ACAST64_ 0xC000000000000000) /* kernel mapped */ +#define XKSEGSIZE (_ACAST64_ 0x00000FFF80000000) + +#define GEN_VECT (_ACAST32_ 0x80000080) +#define UTLB_VECT (_ACAST32_ 0x80000000) + +/* ********************************************************************* + * Address space coercion macros + ********************************************************************* */ + +#define PHYS_TO_K0(pa) (K0BASE | (pa)) +#define PHYS_TO_K1(pa) (K1BASE | (pa)) +#define K0_TO_PHYS(va) ((va) & (K0SIZE-1)) +#define K1_TO_PHYS(va) ((va) & (K1SIZE-1)) +#define K0_TO_K1(va) ((va) | K1SIZE) +#define K1_TO_K0(va) ((va) & ~K1SIZE) + +#define PHYS_TO_XK1(p) (_ACAST64_ (0xffffffffa0000000 | (p))) +#define XK1_TO_PHYS(p) ((p) & (K1SIZE-1)) +#define PHYS_TO_XKPHYS(cca,p) (_SB_MAKEMASK1(63) | (_SB_MAKE64(cca) << 59) | (p)) +#define PHYS_TO_XKSEG_UNCACHED(p) PHYS_TO_XKPHYS(K_CALG_UNCACHED,(p)) +#define PHYS_TO_XKSEG_CACHED(p) PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE,(p)) +#define XKPHYS_TO_PHYS(p) ((p) & _SB_MAKEMASK(0,59)) + + +#if !defined(__ASSEMBLER__) +#define mips_wbflush() __asm__ __volatile__ ("sync" : : : "memory") +#define ISK0SEG(va) ((va) >= K0BASE && (va) <= (K0BASE + K0SIZE - 1)) +#define ISK1SEG(va) ((va) >= K1BASE && (va) <= (K1BASE + K1SIZE - 1)) +#endif + +/* ********************************************************************* + * Register aliases + ********************************************************************* */ + +#if defined(__ASSEMBLER__) +#define zero $0 +#define AT $1 /* assembler temporaries */ +#define v0 $2 /* value holders */ +#define v1 $3 +#define a0 $4 /* arguments */ +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 /* temporaries */ +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define ta0 $12 +#define ta1 $13 +#define ta2 $14 +#define ta3 $15 +#define s0 $16 /* saved registers */ +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 /* temporaries */ +#define t9 $25 +#define k0 $26 /* kernel registers */ +#define k1 $27 +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define s8 $30 /* saved register */ +#define fp $30 /* frame pointer */ +#define ra $31 /* return address */ +#endif + +/* ********************************************************************* + * CP0 Registers + ********************************************************************* */ + +#if defined(__ASSEMBLER__) +#define C0_INX $0 /* CP0: TLB Index */ +#define C0_RAND $1 /* CP0: TLB Random */ +#define C0_TLBLO0 $2 /* CP0: TLB EntryLo0 */ +#define C0_TLBLO C0_TLBLO0 /* CP0: TLB EntryLo0 */ +#define C0_TLBLO1 $3 /* CP0: TLB EntryLo1 */ +#define C0_CTEXT $4 /* CP0: Context */ +#define C0_PGMASK $5 /* CP0: TLB PageMask */ +#define C0_WIRED $6 /* CP0: TLB Wired */ +#define C0_BADVADDR $8 /* CP0: Bad Virtual Address */ +#define C0_COUNT $9 /* CP0: Count */ +#define C0_TLBHI $10 /* CP0: TLB EntryHi */ +#define C0_COMPARE $11 /* CP0: Compare */ +#define C0_SR $12 /* CP0: Processor Status */ +#define C0_STATUS C0_SR /* CP0: Processor Status */ +#define C0_CAUSE $13 /* CP0: Exception Cause */ +#define C0_EPC $14 /* CP0: Exception PC */ +#define C0_PRID $15 /* CP0: Processor Revision Indentifier */ +#define C0_CONFIG $16 /* CP0: Config */ +#define C0_LLADDR $17 /* CP0: LLAddr */ +#define C0_WATCHLO $18 /* CP0: WatchpointLo */ +#define C0_WATCHHI $19 /* CP0: WatchpointHi */ +#define C0_XCTEXT $20 /* CP0: XContext */ +#define C0_ECC $26 /* CP0: ECC */ +#define C0_CACHEERR $27 /* CP0: CacheErr */ +#define C0_TAGLO $28 /* CP0: TagLo */ +#define C0_TAGHI $29 /* CP0: TagHi */ +#define C0_ERREPC $30 /* CP0: ErrorEPC */ +#else +#define C0_INX 0 /* CP0: TLB Index */ +#define C0_RAND 1 /* CP0: TLB Random */ +#define C0_TLBLO0 2 /* CP0: TLB EntryLo0 */ +#define C0_TLBLO C0_TLBLO0 /* CP0: TLB EntryLo0 */ +#define C0_TLBLO1 3 /* CP0: TLB EntryLo1 */ +#define C0_CTEXT 4 /* CP0: Context */ +#define C0_PGMASK 5 /* CP0: TLB PageMask */ +#define C0_WIRED 6 /* CP0: TLB Wired */ +#define C0_BADVADDR 8 /* CP0: Bad Virtual Address */ +#define C0_COUNT 9 /* CP0: Count */ +#define C0_TLBHI 10 /* CP0: TLB EntryHi */ +#define C0_COMPARE 11 /* CP0: Compare */ +#define C0_SR 12 /* CP0: Processor Status */ +#define C0_STATUS C0_SR /* CP0: Processor Status */ +#define C0_CAUSE 13 /* CP0: Exception Cause */ +#define C0_EPC 14 /* CP0: Exception PC */ +#define C0_PRID 15 /* CP0: Processor Revision Indentifier */ +#define C0_CONFIG 16 /* CP0: Config */ +#define C0_LLADDR 17 /* CP0: LLAddr */ +#define C0_WATCHLO 18 /* CP0: WatchpointLo */ +#define C0_WATCHHI 19 /* CP0: WatchpointHi */ +#define C0_XCTEXT 20 /* CP0: XContext */ +#define C0_ECC 26 /* CP0: ECC */ +#define C0_CACHEERR 27 /* CP0: CacheErr */ +#define C0_TAGLO 28 /* CP0: TagLo */ +#define C0_TAGHI 29 /* CP0: TagHi */ +#define C0_ERREPC 30 /* CP0: ErrorEPC */ +#endif + +/* ********************************************************************* + * CP1 (floating point) control registers + ********************************************************************* */ + +#define FPA_IRR 0 /* CP1: Implementation/Revision */ +#define FPA_CSR 31 /* CP1: Control/Status */ + +/* ********************************************************************* + * Macros for generating assembly language routines + ********************************************************************* */ + +#if defined(__ASSEMBLER__) + +/* global leaf function (does not call other functions) */ +#define LEAF(name) \ + .globl name; \ + .ent name; \ +name: + +/* global alternate entry to (local or global) leaf function */ +#define XLEAF(name) \ + .globl name; \ + .aent name; \ +name: + +/* end of a global function */ +#define END(name) \ + .size name,.-name; \ + .end name + +/* local leaf function (does not call other functions) */ +#define SLEAF(name) \ + .ent name; \ +name: + +/* local alternate entry to (local or global) leaf function */ +#define SXLEAF(name) \ + .aent name; \ +name: + +/* end of a local function */ +#define SEND(name) \ + END(name) + +/* define & export a symbol */ +#define EXPORT(name) \ + .globl name; \ +name: + +/* import a symbol */ +#define IMPORT(name, size) \ + .extern name,size + +/* define a zero-fill common block (BSS if not overridden) with a global name */ +#define COMM(name,size) \ + .comm name,size + +/* define a zero-fill common block (BSS if not overridden) with a local name */ +#define LCOMM(name,size) \ + .lcomm name,size + +#endif + + +/* Floating-Point Control register bits */ +#define CSR_C 0x00800000 +#define CSR_EXC 0x0003f000 +#define CSR_EE 0x00020000 +#define CSR_EV 0x00010000 +#define CSR_EZ 0x00008000 +#define CSR_EO 0x00004000 +#define CSR_EU 0x00002000 +#define CSR_EI 0x00001000 +#define CSR_TV 0x00000800 +#define CSR_TZ 0x00000400 +#define CSR_TO 0x00000200 +#define CSR_TU 0x00000100 +#define CSR_TI 0x00000080 +#define CSR_SV 0x00000040 +#define CSR_SZ 0x00000020 +#define CSR_SO 0x00000010 +#define CSR_SU 0x00000008 +#define CSR_SI 0x00000004 +#define CSR_RM 0x00000003 + +/* Status Register */ +#define M_SR_CUMASK _MM_MAKEMASK(4,28) /* coprocessor usable bits */ +#define M_SR_CU3 _MM_MAKEMASK1(31) /* coprocessor 3 usable */ +#define M_SR_CU2 _MM_MAKEMASK1(30) /* coprocessor 2 usable */ +#define M_SR_CU1 _MM_MAKEMASK1(29) /* coprocessor 1 usable */ +#define M_SR_CU0 _MM_MAKEMASK1(28) /* coprocessor 0 usable */ + +#define M_SR_RP _MM_MAKEMASK1(27) /* reduced power mode */ +#define M_SR_FR _MM_MAKEMASK1(26) /* fpu regs any data */ +#define M_SR_RE _MM_MAKEMASK1(25) /* reverse endian */ +#define M_SR_MX _MM_MAKEMASK1(24) /* MDMX */ +#define M_SR_PX _MM_MAKEMASK1(23) /* 64-bit ops in user mode */ +#define M_SR_BEV _MM_MAKEMASK1(22) /* boot exception vectors */ +#define M_SR_TS _MM_MAKEMASK1(21) /* TLB is shut down */ +#define M_SR_SR _MM_MAKEMASK1(20) /* soft reset */ +#define M_SR_NMI _MM_MAKEMASK1(19) /* nonmaskable interrupt */ + +#define M_SR_IMASK _MM_MAKEMASK(8,8) /* all interrupt mask bits */ + +#define M_SR_IBIT8 _MM_MAKEMASK1(15) /* individual bits */ +#define M_SR_IBIT7 _MM_MAKEMASK1(14) +#define M_SR_IBIT6 _MM_MAKEMASK1(13) +#define M_SR_IBIT5 _MM_MAKEMASK1(12) +#define M_SR_IBIT4 _MM_MAKEMASK1(11) +#define M_SR_IBIT3 _MM_MAKEMASK1(10) +#define M_SR_IBIT2 _MM_MAKEMASK1(9) +#define M_SR_IBIT1 _MM_MAKEMASK1(8) + +#define M_SR_IMASK8 0 /* masks for nested int levels */ +#define M_SR_IMASK7 _MM_MAKEMASK(1,15) +#define M_SR_IMASK6 _MM_MAKEMASK(2,14) +#define M_SR_IMASK5 _MM_MAKEMASK(3,13) +#define M_SR_IMASK4 _MM_MAKEMASK(4,12) +#define M_SR_IMASK3 _MM_MAKEMASK(5,11) +#define M_SR_IMASK2 _MM_MAKEMASK(6,10) +#define M_SR_IMASK1 _MM_MAKEMASK(7,9) +#define M_SR_IMASK0 _MM_MAKEMASK(8,8) + +#define M_SR_KX _MM_MAKEMASK1(7) /* 64-bit access for kernel */ +#define M_SR_SX _MM_MAKEMASK1(6) /* .. for supervisor */ +#define M_SR_UX _MM_MAKEMASK1(5) /* .. for user */ + +#define S_SR_KSU 3 /* base operating mode mode */ +#define M_SR_KSU _MM_MAKEMASK(2,S_SR_KSU) +#define V_SR_KSU(x) _MM_MAKEVALUE(x,S_SR_KSU) +#define G_SR_KSU(x) _MM_GETVALUE(x,S_SR_KSU,M_SR_KSU) +#define K_SR_KSU_KERNEL 0 +#define K_SR_KSU_SUPR 1 +#define K_SR_KSU_USER 2 + +#define M_SR_UM _MM_MAKEMASK1(4) +#define M_SR_ERL _MM_MAKEMASK1(2) +#define M_SR_EXL _MM_MAKEMASK1(1) +#define M_SR_IE _MM_MAKEMASK1(0) + +/* + * Cause Register + */ +#define M_CAUSE_BD _MM_MAKEMASK1(31) /* exception in BD slot */ + +#define S_CAUSE_CE 28 /* coprocessor error */ +#define M_CAUSE_CE _MM_MAKEMASK(2,S_CAUSE_CE) +#define V_CAUSE_CE(x) _MM_MAKEVALUE(x,S_CAUSE_CE) +#define G_CAUSE_CE(x) _MM_GETVALUE(x,S_CAUSE_CE,M_CAUSE_CE) + +#define M_CAUSE_IV _MM_MAKEMASK1(23) /* special interrupt */ +#define M_CAUSE_WP _MM_MAKEMASK1(22) /* watch interrupt deferred */ + +#define S_CAUSE_IPMASK 8 +#define M_CAUSE_IPMASK _MM_MAKEMASK(8,S_CAUSE_IPMASK) +#define M_CAUSE_IP8 _MM_MAKEMASK1(15) /* hardware interrupts */ +#define M_CAUSE_IP7 _MM_MAKEMASK1(14) +#define M_CAUSE_IP6 _MM_MAKEMASK1(13) +#define M_CAUSE_IP5 _MM_MAKEMASK1(12) +#define M_CAUSE_IP4 _MM_MAKEMASK1(11) +#define M_CAUSE_IP3 _MM_MAKEMASK1(10) +#define M_CAUSE_SW2 _MM_MAKEMASK1(9) /* software interrupts */ +#define M_CAUSE_SW1 _MM_MAKEMASK1(8) + +#define S_CAUSE_EXC 2 +#define M_CAUSE_EXC _MM_MAKEMASK(5,S_CAUSE_EXC) +#define V_CAUSE_EXC(x) _MM_MAKEVALUE(x,S_CAUSE_EXC) +#define G_CAUSE_EXC(x) _MM_GETVALUE(x,S_CAUSE_EXC,M_CAUSE_EXC) + +/* Exception Code */ +#define K_CAUSE_EXC_INT 0 /* External interrupt */ +#define K_CAUSE_EXC_MOD 1 /* TLB modification */ +#define K_CAUSE_EXC_TLBL 2 /* TLB miss (Load or Ifetch) */ +#define K_CAUSE_EXC_TLBS 3 /* TLB miss (Save) */ +#define K_CAUSE_EXC_ADEL 4 /* Address error (Load or Ifetch) */ +#define K_CAUSE_EXC_ADES 5 /* Address error (Save) */ +#define K_CAUSE_EXC_IBE 6 /* Bus error (Ifetch) */ +#define K_CAUSE_EXC_DBE 7 /* Bus error (data load or store) */ +#define K_CAUSE_EXC_SYS 8 /* System call */ +#define K_CAUSE_EXC_BP 9 /* Break point */ +#define K_CAUSE_EXC_RI 10 /* Reserved instruction */ +#define K_CAUSE_EXC_CPU 11 /* Coprocessor unusable */ +#define K_CAUSE_EXC_OVF 12 /* Arithmetic overflow */ +#define K_CAUSE_EXC_TRAP 13 /* Trap exception */ +#define K_CAUSE_EXC_VCEI 14 /* Virtual Coherency Exception (I) */ +#define K_CAUSE_EXC_FPE 15 /* Floating Point Exception */ +#define K_CAUSE_EXC_CP2 16 /* Cp2 Exception */ +#define K_CAUSE_EXC_WATCH 23 /* Watchpoint exception */ +#define K_CAUSE_EXC_VCED 31 /* Virtual Coherency Exception (D) */ + +#define K_NTLBENTRIES 64 + +#define HI_HALF(x) ((x) >> 16) +#define LO_HALF(x) ((x) & 0xffff) + +/* FPU stuff */ + +#if defined(__ASSEMBLER__) +#define C1_CSR $31 +#define C1_FRID $0 +#else +#define C1_CSR 31 +#define C1_FRID 0 +#endif + +#define S_FCSR_CAUSE 12 +#define M_FCSR_CAUSE _MM_MAKEMASK(5,S_FCSR_CAUSE) +#define V_FCSR_CAUSE(x) _MM_MAKEVALUE(x,S_FCSR_CAUSE) +#define G_FCSR_CAUSE(x) _MM_GETVALUE(x,S_FCSR_CAUSE,M_FCSR_CAUSE) + +#define S_FCSR_ENABLES 7 +#define M_FCSR_ENABLES _MM_MAKEMASK(5,S_FCSR_ENABLES) +#define V_FCSR_ENABLES(x) _MM_MAKEVALUE(x,S_FCSR_ENABLES) +#define G_FCSR_ENABLES(x) _MM_GETVALUE(x,S_FCSR_ENABLES,M_FCSR_ENABLES) + +#define S_FCSR_FLAGS 2 +#define M_FCSR_FLAGS _MM_MAKEMASK(5,S_FCSR_FLAGS) +#define V_FCSR_FLAGS(x) _MM_MAKEVALUE(x,S_FCSR_FLAGS) +#define G_FCSR_FLAGS(x) _MM_GETVALUE(x,S_FCSR_FLAGS,M_FCSR_FLAGS) + + +/* + * MIPS64 Config Register (select 0) + */ +#define M_CFG_CFG1 _MM_MAKEMASK1(31) /* config1 select1 is impl */ +#define M_CFG_BE _MM_MAKEMASK1(15) /* big-endian mode */ + +#define S_CFG_AT 13 /* Architecture Type */ +#define M_CFG_AT _MM_MAKEMASK(2,S_CFG_AT) +#define V_CFG_AT(x) _MM_MAKEVALUE(x,S_CFG_AT) +#define G_CFG_AT(x) _MM_GETVALUE(x,S_CFG_AT,M_CFG_AT) +#define K_CFG_AT_MIPS32 0 +#define K_CFG_AT_MIPS64_32 1 +#define K_CFG_AT_MIPS64 2 + +#define S_CFG_AR 10 /* Architecture Revision */ +#define M_CFG_AR _MM_MAKEMASK(3,S_CFG_AR) +#define V_CFG_AR(x) _MM_MAKEVALUE(x,S_CFG_AR) +#define G_CFG_AR(x) _MM_GETVALUE(x,S_CFG_AR,M_CFG_AR) +#define K_CFG_AR_REV1 0 + +#define S_CFG_MMU 7 /* MMU Type */ +#define M_CFG_MMU _MM_MAKEMASK(3,S_CFG_MMU) +#define V_CFG_MMU(x) _MM_MAKEVALUE(x,S_CFG_MMU) +#define G_CFG_MMU(x) _MM_GETVALUE(x,S_CFG_MMU,M_CFG_MMU) +#define K_CFG_MMU_NONE 0 +#define K_CFG_MMU_TLB 1 +#define K_CFG_MMU_BAT 2 +#define K_CFG_MMU_FIXED 3 + +#define S_CFG_K0COH 0 /* K0seg coherency */ +#define M_CFG_K0COH _MM_MAKEMASK(3,S_CFG_K0COH) +#define V_CFG_K0COH(x) _MM_MAKEVALUE(x,S_CFG_K0COH) +#define G_CFG_K0COH(x) _MM_GETVALUE(x,S_CFG_K0COH,M_CFG_K0COH) +#define K_CFG_K0COH_UNCACHED 2 +#define K_CFG_K0COH_CACHEABLE 3 +#define K_CFG_K0COH_COHERENT 5 + +/* + * MIPS64 Config Register (select 1) + */ + +#define M_CFG_CFG2 _MM_MAKEMASK1(31) /* config2 select2 is impl */ + +#define S_CFG_MMUSIZE 25 +#define M_CFG_MMUSIZE _MM_MAKEMASK(6,S_CFG_MMUSIZE) + +#define S_CFG_IS 22 +#define M_CFG_IS _MM_MAKEMASK(3,S_CFG_IS) +#define V_CFG_IS(x) _MM_MAKEVALUE(x,S_CFG_IS) +#define G_CFG_IS(x) _MM_GETVALUE(x,S_CFG_IS,M_CFG_IS) + +#define S_CFG_IL 19 +#define M_CFG_IL _MM_MAKEMASK(S_CFG_IL,3) +#define V_CFG_IL(x) _MM_MAKEVALUE(x,S_CFG_IL) +#define G_CFG_IL(x) _MM_GETVALUE(x,S_CFG_IL,M_CFG_IL) + +#define S_CFG_IA 16 +#define M_CFG_IA _MM_MAKEMASK(3,S_CFG_IA) +#define V_CFG_IA(x) _MM_MAKEVALUE(x,S_CFG_IA) +#define G_CFG_IA(x) _MM_GETVALUE(x,S_CFG_IA,M_CFG_IA) + +#define S_CFG_DS 13 +#define M_CFG_DS _MM_MAKEMASK(3,S_CFG_DS) +#define V_CFG_DS(x) _MM_MAKEVALUE(x,S_CFG_DS) +#define G_CFG_DS(x) _MM_GETVALUE(x,S_CFG_DS,M_CFG_DS) + +#define S_CFG_DL 10 +#define M_CFG_DL _MM_MAKEMASK(3,S_CFG_DL) +#define V_CFG_DL(x) _MM_MAKEVALUE(x,S_CFG_DL) +#define G_CFG_DL(x) _MM_GETVALUE(x,S_CFG_DL,M_CFG_DL) + +#define S_CFG_DA 7 +#define M_CFG_DA _MM_MAKEMASK(3,S_CFG_DA) +#define V_CFG_DA(x) _MM_MAKEVALUE(x,S_CFG_DA) +#define G_CFG_DA(x) _MM_GETVALUE(x,S_CFG_DA,M_CFG_DA) + +#define M_CFG_PC _MM_MAKEMASK1(4) /* perf ctrs present */ +#define M_CFG_WR _MM_MAKEMASK1(3) /* watch regs present */ +#define M_CFG_CA _MM_MAKEMASK1(2) /* MIPS16 present */ +#define M_CFG_EP _MM_MAKEMASK1(1) /* EJTAG present */ +#define M_CFG_FP _MM_MAKEMASK1(0) /* FPU present */ + + + +/* + * Primary Cache TagLo + */ + +#define S_TAGLO_PTAG 8 +#define M_TAGLO_PTAG _MM_MAKEMASK(56,S_TAGLO_PTAG) + +#define S_TAGLO_PSTATE 6 +#define M_TAGLO_PSTATE _MM_MAKEMASK(2,S_TAGLO_PSTATE) +#define V_TAGLO_PSTATE(x) _MM_MAKEVALUE(x,S_TAGLO_PSTATE) +#define G_TAGLO_PSTATE(x) _MM_GETVALUE(x,S_TAGLO_PSTATE,M_TAGLO_PSTATE) +#define K_TAGLO_PSTATE_INVAL 0 +#define K_TAGLO_PSTATE_SHARED 1 +#define K_TAGLO_PSTATE_CLEAN_EXCL 2 +#define K_TAGLO_PSTATE_DIRTY_EXCL 3 + +#define M_TAGLO_LOCK _MM_MAKEMASK1(5) +#define M_TAGLO_PARITY _MM_MAKEMASK1(0) + + +/* + * CP0 CacheErr register + */ +#define M_CERR_DATA _MM_MAKEMASK1(31) /* err in D space */ +#define M_CERR_SCACHE _MM_MAKEMASK1(30) /* err in l2, not l1 */ +#define M_CERR_DERR _MM_MAKEMASK1(29) /* data error */ +#define M_CERR_TERR _MM_MAKEMASK1(28) /* tag error */ +#define M_CERR_EXTRQ _MM_MAKEMASK1(27) /* external req caused err */ +#define M_CERR_BPAR _MM_MAKEMASK1(26) /* bus parity err */ +#define M_CERR_ADATA _MM_MAKEMASK1(25) /* additional data */ +#define M_CERR_IDX _MM_MAKEMASK(22,0) + + + +/* + * Primary Cache operations + */ +#define Index_Invalidate_I 0x0 /* 0 0 */ +#define Index_Writeback_Inv_D 0x1 /* 0 1 */ +#define Index_Invalidate_SI 0x2 /* 0 2 */ +#define Index_Writeback_Inv_SD 0x3 /* 0 3 */ +#define Index_Load_Tag_I 0x4 /* 1 0 */ +#define Index_Load_Tag_D 0x5 /* 1 1 */ +#define Index_Load_Tag_SI 0x6 /* 1 2 */ +#define Index_Load_Tag_SD 0x7 /* 1 3 */ +#define Index_Store_Tag_I 0x8 /* 2 0 */ +#define Index_Store_Tag_D 0x9 /* 2 1 */ +#define Index_Store_Tag_SI 0xA /* 2 2 */ +#define Index_Store_Tag_SD 0xB /* 2 3 */ +#define Create_Dirty_Exc_D 0xD /* 3 1 */ +#define Create_Dirty_Exc_SD 0xF /* 3 3 */ +#define Hit_Invalidate_I 0x10 /* 4 0 */ +#define Hit_Invalidate_D 0x11 /* 4 1 */ +#define Hit_Invalidate_SI 0x12 /* 4 2 */ +#define Hit_Invalidate_SD 0x13 /* 4 3 */ +#define Fill_I 0x14 /* 5 0 */ +#define Hit_Writeback_Inv_D 0x15 /* 5 1 */ +#define Hit_Writeback_Inv_SD 0x17 /* 5 3 */ +#define Hit_Writeback_I 0x18 /* 6 0 */ +#define Hit_Writeback_D 0x19 /* 6 1 */ +#define Hit_Writeback_SD 0x1B /* 6 3 */ +#define Hit_Set_Virtual_SI 0x1E /* 7 2 */ +#define Hit_Set_Virtual_SD 0x1F /* 7 3 */ + +/* Watchpoint Register */ +#define M_WATCH_PA 0xfffffff8 +#define M_WATCH_R 0x00000002 +#define M_WATCH_W 0x00000001 + + +/* TLB entries */ +#define M_TLBHI_ASID _MM_MAKEMASK(0,8) +#define M_TLBHI_VPN2 _MM_MAKEMASK(27,13) + +#define M_TLBLO_G _MM_MAKEMASK1(0) +#define M_TLBLO_V _MM_MAKEMASK1(1) +#define M_TLBLO_D _MM_MAKEMASK1(2) + +#define S_TLBLO_CALG 3 +#define M_TLBLO_CALG _MM_MAKEMASK(3,S_TLBLO_CALG) +#define V_TLBLO_CALG(x) _MM_MAKEVALUE(x,S_TLBLO_CALG) +#define G_TLBLO_CALG(x) _MM_GETVALUE(x,S_TLBLO_CALG,M_TLBLO_CALG) + +#define K_CALG_COH_EXCL1_NOL2 0 +#define K_CALG_COH_SHRL1_NOL2 1 +#define K_CALG_UNCACHED 2 +#define K_CALG_NONCOHERENT 3 +#define K_CALG_COH_EXCL 4 +#define K_CALG_COH_SHAREABLE 5 +#define K_CALG_NOTUSED 6 +#define K_CALG_UNCACHED_ACCEL 7 + +#define S_TLBLO_PFNMASK 6 +#define M_TLBLO_PFNMASK _MM_MAKEMASK(24,S_TLBLO_PFNMASK) +#define V_TLBLO_PFNMASK(x) _MM_MAKEVALUE(x,S_TLBLO_PFNMASK) +#define G_TLBLO_PFNMASK(x) _MM_GETVALUE(x,S_TLBLO_PFNMASK,M_TLBLO_PFNMASK) + + + +#endif /* _SB_MIPS_H */ + + diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/include/sbsdram.h b/cfe/cfe/arch/mips/cpu/bcmcore/include/sbsdram.h new file mode 100644 index 0000000..80e93e3 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/include/sbsdram.h @@ -0,0 +1,92 @@ +/* + Copyright 2001, Broadcom Corporation + All Rights Reserved. + + This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + the contents of this file may not be disclosed to third parties, copied or + duplicated in any form, in whole or in part, without the prior written + permission of Broadcom Corporation. +*/ +/* + * BCM47XX Sonics SiliconBackplane SDRAM controller core hardware definitions. + * + * $Id: sbsdram.h,v 1.1 2001/10/31 18:49:26 mpl Exp $ + */ + +#ifndef _SBSDRAM_H +#define _SBSDRAM_H + +#ifndef _LANGUAGE_ASSEMBLY + +/* Sonics side: SDRAM core registers */ +typedef volatile struct sbsdramregs { + uint32 initcontrol; /* Generates external SDRAM initialization sequence */ + uint32 config; /* Initializes external SDRAM mode register */ + uint32 refresh; /* Controls external SDRAM refresh rate */ + uint32 pad1; + uint32 pad2; +} sbsdramregs_t; + +#endif + +/* SDRAM initialization control (initcontrol) register bits */ +#define SDRAM_CBR 0x0001 /* Writing 1 generates refresh cycle and toggles bit */ +#define SDRAM_PRE 0x0002 /* Writing 1 generates precharge cycle and toggles bit */ +#define SDRAM_MRS 0x0004 /* Writing 1 generates mode register select cycle and toggles bit */ +#define SDRAM_EN 0x0008 /* When set, enables access to SDRAM */ +#define SDRAM_16Mb 0x0000 /* Use 16 Megabit SDRAM */ +#define SDRAM_64Mb 0x0010 /* Use 64 Megabit SDRAM */ +#define SDRAM_128Mb 0x0020 /* Use 128 Megabit SDRAM */ +#define SDRAM_RSVMb 0x0030 /* Use special SDRAM */ +#define SDRAM_RST 0x0080 /* Writing 1 causes soft reset of controller */ +#define SDRAM_SELFREF 0x0100 /* Writing 1 enables self refresh mode */ +#define SDRAM_PWRDOWN 0x0200 /* Writing 1 causes controller to power down */ +#define SDRAM_32BIT 0x0400 /* When set, indicates 32 bit SDRAM interface */ +#define SDRAM_9BITCOL 0x0800 /* When set, indicates 9 bit column */ + +/* SDRAM configuration (config) register bits */ +#define SDRAM_BURSTFULL 0x0000 /* Use full page bursts */ +#define SDRAM_BURST8 0x0001 /* Use burst of 8 */ +#define SDRAM_BURST4 0x0002 /* Use burst of 4 */ +#define SDRAM_BURST2 0x0003 /* Use burst of 2 */ +#define SDRAM_CAS3 0x0000 /* Use CAS latency of 3 */ +#define SDRAM_CAS2 0x0004 /* Use CAS latency of 2 */ + +/* SDRAM refresh control (refresh) register bits */ +#define SDRAM_REF(p) (((p)&0xff) | SDRAM_REF_EN) /* Refresh period */ +#define SDRAM_REF_EN 0x8000 /* Writing 1 enables periodic refresh */ + +/* SDRAM Core Init values (OCP ID 0x803) */ + +#define SDRAM_CONFIG SDRAM_BURSTFULL +#define SDRAM_REFRESH SDRAM_REF(0x40) + +#if defined(MEM1MX16_KM) +#define SDRAM_INIT 0x009 +#elif defined(MEM1MX16X2_KM) +#define SDRAM_INIT 0x409 +#elif defined(MEM2MX8X2_KM) +#define SDRAM_INIT 0x809 +#elif defined(MEM2MX8X4_KM) +#define SDRAM_INIT 0xc09 +#elif defined(MEM2MX32_KM) +#define SDRAM_INIT 0x439 +#elif defined(MEM4MX16_KM) +#define SDRAM_INIT 0x019 +#elif defined(MEM4MX16X2_KM) +#define SDRAM_INIT 0x419 +#elif defined(MEM8MX8X2_KM) +#define SDRAM_INIT 0x819 +#elif defined(MEM8MX8X4_KM) +#define SDRAM_INIT 0xc19 +#elif defined(MEM8MX16_KM) +#define SDRAM_INIT 0x829 +#elif defined(MEM8MX16X2_KM) +#define SDRAM_INIT 0xc29 +#elif defined(MEM4MX32_KM) +#define SDRAM_INIT 0x429 +#else /* DEFAULT MEM */ +#define SDRAM_INIT 0x419 +#endif + +#endif /* _SBSDRAM_H */ diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/src/Makefile b/cfe/cfe/arch/mips/cpu/bcmcore/src/Makefile new file mode 100755 index 0000000..76662a0 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/src/Makefile @@ -0,0 +1,8 @@ + +ALLOBJS += bcmcore_cpuinit.o bcmcore_l1cache.o +ifeq ($(strip ${CFG_RAMAPP}),1) +ALLOBJS += bcmcore_arena.o +endif +CFLAGS += -mips32 -D_MIPSREGS32_ -mno-abicalls -fPIC +# CFLAGS += -mips2 -D_MIPSREGS32_ + diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_arena.c b/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_arena.c new file mode 100755 index 0000000..b368158 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_arena.c @@ -0,0 +1,170 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Physical Memory (arena) manager File: bcmcore_arena.c + * + * This module describes the physical memory available to the + * firmware. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_arena.h" + +#include "cfe_error.h" + +#include "cfe.h" +#include "cfe_mem.h" + +#include "initdata.h" + +#define _NOPROTOS_ +#include "cfe_boot.h" +#undef _NOPROTOS_ + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define ARENA_RANGE(bottom,top,type) arena_markrange(&cfe_arena,(uint64_t)(bottom), \ + (uint64_t)(top)-(uint64_t)bottom+1,(type),NULL) + +#define MEG (1024*1024) +#define KB 1024 +#define PAGESIZE 4096 +#define CFE_BOOTAREA_SIZE (256*KB) +#define CFE_BOOTAREA_ADDR 0x20000000 + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +extern arena_t cfe_arena; + +unsigned int mem_bootarea_start; +unsigned int mem_bootarea_size; + +void bcmcore_arena_init(void); +void bcmcore_pagetable_init(uint64_t *ptaddr,unsigned int physaddr); + + +/* ********************************************************************* + * bcmcore_arena_init() + * + * Create the initial map of physical memory + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void bcmcore_arena_init(void) +{ + int64_t memleft; + +#if 1 /* defined(CONFIG_MIPS_BRCM) */ + arena_init(&cfe_arena,0x0,0x0); /* 2^32 physical bytes */ +#else + arena_init(&cfe_arena,0x0,0x100000000); /* 2^32 physical bytes */ +#endif + + /* + * Mark the ranges from the SB1250's memory map + */ + + ARENA_RANGE(0x0000000000,0x000FFFFFFF,MEMTYPE_DRAM_NOTINSTALLED); + + /* + * Now, fix up the map with what is known about *this* system. + * + * Do each 256MB chunk. + */ + + memleft = ((int64_t) mem_totalsize) << 20; + + arena_markrange(&cfe_arena,0x00000000,memleft,MEMTYPE_DRAM_AVAILABLE,NULL); + + /* + * Do the boot ROM + */ + + arena_markrange(&cfe_arena,0x1FC00000,2*1024*1024,MEMTYPE_BOOTROM,NULL); + +} + + +/* ********************************************************************* + * BCMCORE_PAGETABLE_INIT(ptaddr,physaddr) + * + * This routine constructs the page table. 256KB is mapped + * starting at physical address 'physaddr' - the resulting + * table entries are placed at 'ptaddr' + * + * Input parameters: + * ptaddr - base of page table + * physaddr - starting physical addr of area to map + * + * Return value: + * nothing + ********************************************************************* */ + +void bcmcore_pagetable_init(uint64_t *ptaddr,unsigned int physaddr) +{ + int idx; + + for (idx = 0; idx < (CFE_BOOTAREA_SIZE/PAGESIZE); idx++) { + ptaddr[idx] = (physaddr >> 6) | + V_TLBLO_CALG(K_CALG_NONCOHERENT) | + M_TLBLO_V | + M_TLBLO_D; + physaddr += PAGESIZE; + } + +} + diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_cpuinit.S b/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_cpuinit.S new file mode 100755 index 0000000..7c04b51 --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_cpuinit.S @@ -0,0 +1,490 @@ +/* ********************************************************************* + * SB1250 Board Support Package + * + * CPU initialization File: bcmcore_cpuinit.S + * + * This module contains code to initialize the CPU cores. + * + * Note: all the routines in this module rely on registers only, + * since DRAM may not be active yet. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * XX Copyright 2000,2001 + * Broadcom Corporation. All rights reserved. + * + * BROADCOM PROPRIETARY AND CONFIDENTIAL + * + * This software is furnished under license and may be used and + * copied only in accordance with the license. + ********************************************************************* */ + +#include "sbmips.h" +#include "exception.h" +#include "bsp_config.h" +#include "mipsmacros.h" +#include "cpu_config.h" /* for ERET and HAZARD */ + + + .text + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define LINESIZE 16 + +#define CACHEOP(cachename,op) ((cachename) | ((op) << 2)) + +#define CACHE_OP_IDXINVAL 0 +#define CACHE_OP_IDXLOADTAG 1 +#define CACHE_OP_IDXSTORETAG 2 +#define CACHE_OP_IMPLRSVD 3 +#define CACHE_OP_HITINVAL 4 +#define CACHE_OP_FILL 5 +#define CACHE_OP_HITWRITEBACK_INVAL 5 +#define CACHE_OP_HITWRITEBACK 6 +#define CACHE_OP_FETCHLOCK 7 + +#define L2C 3 +#define L1C_I 0 +#define L1C_D 1 + + +/* + * Duplicates from cfe_iocb.h -- warning! + */ + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 +#define CFE_CACHE_FLUSH_L2 16 +#define CFE_CACHE_INVAL_RANGE 32 +#define CFE_CACHE_FLUSH_RANGE 64 + +#define BCMCORE_NTLBENTRIES 32 + + + +#define SENDCHAR(c) \ + li t0,0xBF800000 ; \ + li t1,c ; \ + sb t1,0(t0) + + +#define R_CPU_CP0INIT _TBLIDX(0) +#define R_CPU_L1CINIT _TBLIDX(1) +#define R_CPU_SETLEDS _TBLIDX(2) +#define R_CPU_L1CFLASHD _TBLIDX(3) +#define R_CPU_L1CINVALI _TBLIDX(4) + +#define SETLEDS1(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + CALLINIT_KSEG1(cpuinit_table,R_CPU_SETLEDS) +#define SETLEDS(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + CALLINIT_KSEG0(cpuinit_table,R_CPU_SETLEDS) + +cpuinit_table: + _LONG_ bcmcore_cp0_init # [ 0 ] R_CPU_CP0INIT + _LONG_ bcmcore_l1cache_init # [ 1 ] R_CPU_L1CINIT + _LONG_ board_setleds # [ 2 ] R_CPU_SETLEDS + _LONG_ bcmcore_l1cache_flush_d # [ 3 ] R_CPU_L1CFLASHD + _LONG_ bcmcore_l1cache_inval_i # [ 4 ] R_CPU_L1CINVALI + + +/* ********************************************************************* + * BCMCORE_CP0_INIT() + * + * Initialize an BCMCORE CPU's CP0 registers + * + * Input parameters: + * nothing + * + * Return value: + * nothing + * + * Registers used: + * all + ********************************************************************* */ + + +LEAF(bcmcore_cp0_init) + + .set noreorder + + mtc0 zero,C0_WATCHLO # Watch registers. + mtc0 zero,C0_WATCHHI + mtc0 zero,C0_CAUSE # must clear before writing SR + + mfc0 v0,C0_SR # Get status register + and v0,M_SR_SR # preserve soft reset +#ifdef DEBUG_ENV_ICE + and v0,~M_SR_BEV +#else + or v0,M_SR_BEV # exceptions to boot vector +#endif + mtc0 v0,C0_SR # set up the status register + + + mfc0 v0,C0_CONFIG # get current CONFIG register + srl v0,v0,3 # strip out K0 bits + sll v0,v0,3 # k0 bits now zero + or v0,v0,K_CFG_K0COH_CACHEABLE # K0 is cacheable. + mtc0 v0,C0_CONFIG + nop + + mtc0 zero,C0_WATCHLO # Watch registers. + mtc0 zero,C0_WATCHHI + + mtc0 zero,C0_TLBHI # TLB entry (high half) + nop + + + # + # This is probably not the right init value for C0_COMPARE, + # but it seems to be necessary for the sim model right now. + # + + li v0,-1 + mtc0 v0,C0_COMPARE + nop + + # + # Initialize all the TLB entries to some invalid value + # + + mtc0 zero,C0_TLBLO0 /* tlblo0 = invalid */ + nop + mtc0 zero,C0_TLBLO1 /* tlblo1 = invalid */ + nop + mtc0 zero,C0_PGMASK /* 4K pages */ + nop + + li t0,K1BASE /* tlbhi = impossible vpn */ + li t1,(BCMCORE_NTLBENTRIES-1) /* index */ + + + nop +1: mtc0 t0,C0_TLBHI + nop + mtc0 t1,C0_INX + nop + addu t0,0x2000 /* inc vpn */ + tlbwi + bnez t1,1b + subu t1,1 # BDSLOT + .set reorder + + +/* + * XXX What other CP0 initialization do I need? + */ + + jr ra + + +END(bcmcore_cp0_init) + + +/* ********************************************************************* + * BCMCORE_CPUINIT + * + * Do initialization of the Broadcom core + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + + +LEAF(bcmcore_cpuinit) + + move fp,ra + + SETLEDS1('C','P','U','I') + CALLINIT_KSEG1(cpuinit_table,R_CPU_CP0INIT) + + SETLEDS1('L','1','C','I') + CALLINIT_KSEG1(cpuinit_table,R_CPU_L1CINIT) + + move ra,fp + j ra + +END(bcmcore_cpuinit) + + +/* ********************************************************************* + * BCMCORE_KSEG0_SWITCH + * + * Return to the address of the routine that called us, except + * in K0seg instead of K1seg + * + * Input parameters: + * nothing - ra is return address + * + * Return value: + * ra = same return address in K0 + ********************************************************************* */ + +LEAF(bcmcore_kseg0_switch) + + and ra,(K0SIZE-1) + or ra,K0BASE + jr ra + +END(bcmcore_kseg0_switch) + +/* ********************************************************************* + * BCMCORE_NULL + * + * Dummy handler for routines we don't need to implement, like + * the multiprocessor stuff + * + * Input parameters: + * nothing + * + * Return value: + * nothing + * + * Registers used: + * none + ********************************************************************* */ + +LEAF(bcmcore_null) + + j ra + +END(bcmcore_null) + + +/* ********************************************************************* + * BCMCORE_CPURESTART + * + * This routine is called when someone soft-exits to CFE. We + * reinitialize any CP0 stuff here. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(bcmcore_cpurestart) + + j ra + +END(bcmcore_cpurestart) + + +/* ********************************************************************* + * BCMCORE_CACHEOPS + * + * Perform various cache operations on a BCM Core + * + * Input parameters: + * a0 - flag bits (CFE_CACHE_xxx) + * + * Return value: + * nothing + * + * Registers used: + * t0,t1,t2,t3,v1,s0 + ********************************************************************* */ + +LEAF(bcmcore_cacheops) + + move s0,ra + + move v1,a0 + + /* + * With no flags, we flush L1D and invalid L1I + */ + + bne v1,zero,1f + li v1,CFE_CACHE_FLUSH_D | CFE_CACHE_INVAL_I +1: + + /* + * Flush the D-Cache, since the program we loaded is "data". + */ + + and a0,v1,CFE_CACHE_FLUSH_D + beq a0,zero,1f + CALLINIT_KSEG1(cpuinit_table,R_CPU_L1CFLASHD) +1: + + /* + * Invalidate the I-Cache, so that addresses in the program + * region will miss and need to be filled from the data we + * just flushed above. + */ + + and a0,v1,CFE_CACHE_INVAL_I + beq a0,zero,1f + CALLINIT_KSEG1(cpuinit_table,R_CPU_L1CINVALI) +1: + + + .set push + .set mips32 + + /* + * Invalidate cache range + */ + + and a0,v1,CFE_CACHE_INVAL_RANGE + beq a0,zero,2f + + move t0,a1 +1: cache CACHEOP(L1C_D,CACHE_OP_HITINVAL),0(t0) + add t0,LINESIZE + blt t0,a2,1b + + /* + * Flush cache range + */ + + +2: + and a0,v1,CFE_CACHE_FLUSH_RANGE + beq a0,zero,2f + + move t0,a1 +1: cache CACHEOP(L1C_D,CACHE_OP_HITWRITEBACK_INVAL),0(t0) + add t0,LINESIZE + blt t0,a2,1b + +2: + + .set pop + + + move ra,s0 + j ra + +END(bcmcore_cacheops) + + + +/* ********************************************************************* + * BCMCORE_TLBHANDLER + * + * This is the TLB exception handler for the bcmcore + * + * Note: only K0 and K1 are available to us at this time. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + + +LEAF(bcmcore_tlbhandler) + .set noreorder + .set noat + +/* + * XXX XXX XXX XXX XXX + * + * This won't work as-is on the BCMCORE. The CONTEXT register is not + * wide enough! In fact, it's broken on all pre-mips4 CPUs. + * + * XXX XXX XXX XXX XXX + */ + +/* + * This requires a bit of explanation: We only support 256KB + * of mapped space for the boot program. This space will be + * mapped from 0x2000_0000 to 0x2004_0000 to some physical + * memory allocated by the firmware. This is 64 pages + * of 4KB each. + * + * We know our BadVPN2 will be in the range + * 0x100000 to 0x1001F0, since the memory is mapped from + * 0x2000_0000 to 0x2004_0000. BadVPN2 plus the four bits + * of zeroes at the end are bits 31..9 + * + * We also want to place the PTEbase on something other than + * a 16MB boundary. Each entry is 16 bytes, and there + * are 64 entries, so we need only 10 bits to address + * the entire table (it can therefore be aligned on a + * 1KB boundary). + * + * To make this work, we'll shift PTEbase to the right, leaving + * the bottom ten bits for the page number, as: + * + * Bits 31..10: PTEbase + * Bits 9..4: BadVPN + * Bits 3..0: 16 bytes for table entry + * + * Therefore: + * PTEbase gets shifted right 13 bits. + * BadVPN gets masked at 6 bits (mask is 0x3F0) + * The bottom 4 bits are zero. + * + * To range check the address, we can shift the Bad VPN + * right by 9 bits, and check for values of 0x1000 and + * 0x1001. + */ + + + /* + * This part range checks the VPN2 field in the + * context register. We only handle + * VPN2s in the range 0x100000 to 0x1001F0 + */ + mfc0 k0,C0_TLBHI + + mfc0 k0,C0_CTEXT # Get context + sra k0,8 # keep hi part + and k0,0x1FFF # of VPN2 + li k1,0x1000 # 0x1000 is ok + beq k0,k1,1f # + nop # BDSLOT + li k1,0x1001 # 0x1001 is ok + beq k0,k1,1f # + nop # BDSLOT + + li k0,XTYPE_TLBFILL # all other bits are not + b _exc_entry + nop # BDSLOT + +1: mfc0 k0,C0_CTEXT # Get context + sra k0,13 # Shift PTEbase + li k1,0x3FF # Generate mask to kill + not k1 # BadVPN2 bits + and k0,k1 # keep only PTEBase part. + + mfc0 k1,C0_CTEXT # Get Context + and k1,0x3F0 # Keep only BadVPN2 bits + or k1,k0 # Replace PTEBase + + ld k0,0(k1) # Load entrylo0 + ld k1,8(k1) # Load entrylo1 + mtc0 k0,C0_TLBLO0 # and write to CP0 + mtc0 k1,C0_TLBLO1 + tlbwr # put it in the TLB + ERET + nop + + .set reorder + .set at + +END(bcmcore_tlbhandler) + + +/* ********************************************************************* + * End + ********************************************************************* */ + diff --git a/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_l1cache.S b/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_l1cache.S new file mode 100755 index 0000000..fa39bfd --- /dev/null +++ b/cfe/cfe/arch/mips/cpu/bcmcore/src/bcmcore_l1cache.S @@ -0,0 +1,219 @@ +/* ********************************************************************* + * SB1250 Board Support Package + * + * L1C initialization File: bcmcore_l1cache.S + * + * This module contains code to initialize the CPU's caches + * + * Note: all the routines in this module rely on registers only, + * since DRAM may not be active yet. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * XX Copyright 2000,2001 + * Broadcom Corporation. All rights reserved. + * + * BROADCOM PROPRIETARY AND CONFIDENTIAL + * + * This software is furnished under license and may be used and + * copied only in accordance with the license. + ********************************************************************* */ + +#include "sbmips.h" +#include "bsp_config.h" + + .text + + .set push + .set mips32 + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define CP0_CFG_ISMSK (0x7 << 22) +#define CP0_CFG_ISSHF 22 +#define CP0_CFG_ILMSK (0x7 << 19) +#define CP0_CFG_ILSHF 19 +#define CP0_CFG_IAMSK (0x7 << 16) +#define CP0_CFG_IASHF 16 +#define CP0_CFG_DSMSK (0x7 << 13) +#define CP0_CFG_DSSHF 13 +#define CP0_CFG_DLMSK (0x7 << 10) +#define CP0_CFG_DLSHF 10 +#define CP0_CFG_DAMSK (0x7 << 7) +#define CP0_CFG_DASHF 7 + +#define cacheop(kva, size, linesize, op) \ + .set noreorder; \ + addu t1, kva, size; \ + subu t2, linesize, 1; \ + not t2; \ + and t0, kva, t2; \ + addu t1, -1; \ + and t1, t2; \ +10: cache op, 0(t0); \ + bne t0, t1, 10b; \ + addu t0, linesize; \ +11: \ + .set reorder + +#define size_icache(size, linesize) \ + mfc0 t7, C0_CONFIG, 1; \ + and t0, t7, CP0_CFG_ILMSK; \ + srl t0, t0, CP0_CFG_ILSHF; \ + move linesize, zero; \ + beq t0, zero,1f; \ + add t0, 1; \ + li linesize, 1; \ + sll linesize, t0; \ +1: and t0, t7, CP0_CFG_ISMSK; \ + srl t0, t0, CP0_CFG_ISSHF; \ + li size, 64; \ + sll size, t0; \ + and t0, t7, CP0_CFG_IAMSK; \ + srl t0, t0, CP0_CFG_IASHF; \ + add t0, 1; \ + mult size, t0; \ + mflo size; \ + mult size, linesize; \ + mflo size + +#define size_dcache(size, linesize) \ + mfc0 t7, C0_CONFIG, 1; \ + and t0, t7, CP0_CFG_DLMSK; \ + srl t0, t0, CP0_CFG_DLSHF; \ + move linesize, zero; \ + beq t0, zero,1f; \ + add t0, 1; \ + li linesize, 1; \ + sll linesize, t0; \ +1: and t0, t7, CP0_CFG_DSMSK; \ + srl t0, t0, CP0_CFG_DSSHF; \ + li size, 64; \ + sll size, t0; \ + and t0, t7, CP0_CFG_DAMSK; \ + srl t0, t0, CP0_CFG_DASHF; \ + add t0, 1; \ + mult size, t0; \ + mflo size; \ + mult size, linesize; \ + mflo size + + +/* ********************************************************************* + * BCMCORE_L1CACHE_INIT() + * + * Initialize the L1 Cache + * + * Input parameters: + * nothing + * + * Return value: + * nothing + * + * Registers used: + * t0,t1,t2 + ********************************************************************* */ + +LEAF(bcmcore_l1cache_init) + + mtc0 zero, C0_TAGLO # Initialize TAGLO register + mtc0 zero, C0_TAGLO,1 # Initialize DataLo register + + li a0, K0BASE # Initialise primary instruction cache. + size_icache(a1, a2) + cacheop(a0, a1, a2, Index_Store_Tag_I) + + li a0, K0BASE # Initialise primary data cache. + size_dcache(a1, a2) + cacheop(a0, a1, a2, Index_Store_Tag_D) + + jr ra + +END(bcmcore_l1cache_init) + +/* ********************************************************************* + * BCMCORE_L1CACHE_INVAL_I() + * + * Invalidate the entire ICache + * + * Input parameters: + * nothing + * + * Return value: + * nothing + * + * Registers used: + * t0,t1,t2 + ********************************************************************* */ +LEAF(bcmcore_l1cache_inval_i) + + li a0, K0BASE + size_icache(a1, a2) + cacheop(a0, a1, a2, Index_Invalidate_I) + + j ra + +END(bcmcore_l1cache_inval_i) + +/* ********************************************************************* + * BCMCORE_L1CACHE_FLUSH_D() + * + * Flush the entire DCache + * + * Input parameters: + * nothing + * + * Return value: + * nothing + * + * Registers used: + * t0,t1,t2 + ********************************************************************* */ +LEAF(bcmcore_l1cache_flush_d) + + li a0, K0BASE + size_dcache(a1, a2) + +# before flushing cache clear tags pointing to flash memory to avoid writes into flash + addu t1, a0, a1 + subu t2, a2, 1 + not t2 + and t0, a0, t2 + addu t1, -1 + and t1, t2 +1: + cache Index_Load_Tag_D, 0(t0) + nop + nop + nop + nop + nop + nop + mfc0 t2, C0_TAGLO # Read TAGLO register + and t2, 0x1f000000 # check address + li t3, 0x1f000000 + bne t2, t3, 2f + mtc0 zero, C0_TAGLO + cache Index_Store_Tag_D, 0(t0) # Reset tag for flash memory locations +2: + .set noreorder; + bne t0, t1, 1b + addu t0, a2 + .set reorder + + cacheop(a0, a1, a2, Index_Writeback_Inv_D) + + j ra + +END(bcmcore_l1cache_flush_d) + + .set pop + +/* ********************************************************************* + * End + ********************************************************************* */ + diff --git a/cfe/cfe/dev/SIBYTE_PRIVATE_FILES b/cfe/cfe/dev/SIBYTE_PRIVATE_FILES new file mode 100644 index 0000000..eae0411 --- /dev/null +++ b/cfe/cfe/dev/SIBYTE_PRIVATE_FILES @@ -0,0 +1,6 @@ +dev_ptflash.c +bcm5700.h +dev_bcm5700.c +bcm5821.h +dev_bcm5821.c + diff --git a/cfe/cfe/dev/bcm5700.h b/cfe/cfe/dev/bcm5700.h new file mode 100644 index 0000000..76aa3ea --- /dev/null +++ b/cfe/cfe/dev/bcm5700.h @@ -0,0 +1,1007 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * BCM5700 (10/100/1K EthernetMAC) registers File: bcm5700.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _BCM5700_H_ +#define _BCM5700_H_ + +/* + * Register and bit definitions for the Broadcom BCM570X family (aka + * Tigon3) of Integrated MACs. + * + * References: + * + * Host Programmer Interface Specification for the BCM570X Family + * of Highly-Integrated Media Access Controllers, 570X-PG106-R. + * Broadcom Corp., 16215 Alton Parkway, Irvine CA, 09/27/02 + * + * Simplified Programmer Interface Specification for the BCM570X Family + * of Highly Integrated Media Access Controllers, 570X-PG202-R. + * Broadcom Corp., 16215 Alton Parkway, Irvine CA, 10/14/02 + */ + +#define K_PCI_VENDOR_BROADCOM 0x14e4 +#define K_PCI_ID_BCM5700 0x1644 +#define K_PCI_ID_BCM5701 0x1645 +#define K_PCI_ID_BCM5702 0x16A6 +#define K_PCI_ID_BCM5703 0x16A7 +#define K_PCI_ID_BCM5704C 0x1648 +#define K_PCI_ID_BCM5704S 0x16A8 +#define K_PCI_ID_BCM5705 0x1653 + +#define _DD_MAKEMASK1(n) (1 << (n)) +#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n)) +#define _DD_MAKEVALUE(v,n) ((v) << (n)) +#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n)) + + +/* Registers 0x0000 - 0x00FF are PCI Configuration registers (shadow) */ + +#define PCI_PCIX_CMD_REG 0x40 +#define PCI_PCIX_STAT_REG 0x44 + +#define PCI_PMC_REG 0x48 +#define PCI_PMCSR_REG 0x4C + +#define R_MISC_HOST_CTRL 0x0068 +#define R_DMA_RW_CTRL 0x006C +#define R_PCI_STATE 0x0070 +#define R_PCI_CLK_CTRL 0x0074 +#define R_REG_BASE_ADDR 0x0078 +#define R_MEMWIN_BASE_ADDR 0x007C +#define R_REG_DATA 0x0080 +#define R_MEMWIN_DATA 0x0084 +/* For 5700 and 5701, 0x0088-0x0090 shadow 0x6800-0x6808 */ +#define R_INT_MBOX0 0x0B0 /* 8 bytes, shadows R_INT_MBOX(0) */ + +/* Registers 0x0200 - 0x03FF are High Priority Mailbox registers */ + +#define R_INT_MBOX(n) (0x0200 + 8*(n)) /* 0 <= n < 4 */ +#define R_GEN_MBOX(n) (0x0220 + 8*(n)-8) /* 1 <= n <= 8 */ +#define R_RELOAD_STATS_MBOX 0x0260 +#define R_RCV_BD_STD_PI 0x0268 +#define R_RCV_BD_JUMBO_PI 0x0270 +#define R_RCV_BD_MINI_PI 0x0278 +#define R_RCV_BD_RTN_CI(n) (0x0280 + 8*(n)-8) /* 1 <= n <= 16 */ +#define R_SND_BD_PI(n) (0x0300 + 8*(n)-8) /* 1 <= n <= 16 */ +#define R_SND_BD_NIC_PI(n) (0x0380 + 8*(n)-8) /* 1 <= n <= 16 */ + +/* Registers 0x0400 - 0x0BFF are MAC Control registers */ + +#define R_MAC_MODE 0x0400 +#define R_MAC_STATUS 0x0404 +#define R_MAC_EVENT_ENB 0x0408 +#define R_MAC_LED_CTRL 0x040C + +#define R_MAC_ADDR1_HIGH 0x0410 +#define R_MAC_ADDR1_LOW 0x0414 +#define R_MAC_ADDR2_HIGH 0x0418 +#define R_MAC_ADDR2_LOW 0x041C +#define R_MAC_ADDR3_HIGH 0x0420 +#define R_MAC_ADDR3_LOW 0x0424 +#define R_MAC_ADDR4_HIGH 0x0428 +#define R_MAC_ADDR4_LOW 0x042C + +#define R_WOL_PATTERN_PTR 0x0430 +#define R_WOL_PATTERN_CFG 0x0434 +#define R_TX_BACKOFF 0x0438 +#define R_RX_MTU 0x043C +#define R_PCS_TEST 0x0440 +#define R_TX_AUTONEG 0x0444 +#define R_RX_AUTONEG 0x0448 + +#define R_MI_COMM 0x044C +#define R_MI_STATUS 0x0450 +#define R_MI_MODE 0x0454 + +#define R_AUTOPOLL_STAT 0x0458 +#define R_TX_MODE 0x045C +#define R_TX_STAT 0x0460 +#define R_TX_LENS 0x0464 +#define R_RX_MODE 0x0468 +#define R_RX_STAT 0x046C + +#define R_MAC_HASH(n) (0x0470 + 4*(n)) /* 0 <= n < 4 */ + +#define R_RX_BD_RULES_CTRL(n) (0x0480 + 8*(n)) /* 0 <= n < 16 */ +#define R_RX_BD_RULES_MASK(n) (0x0484 + 8*(n)) + +#define R_RX_RULES_CFG 0x0500 +#define R_RX_FRAMES_LOW 0x0504 +#define R_MAC_HASH_EXT(n) (0x0520 + 4*(n)) /* 0 <= n < 4 */ +#define R_MAC_ADDR_EXT(n) (0x0530 + 8*(n)) /* 0 <= n < 12 */ +#define R_SERDES_CTRL 0x0590 +#define R_SERDES_STAT 0x0594 +#define R_RX_STATS_MEM 0x0800 +#define R_TX_STATS_MEM 0x0880 + + +/* + * Note on Buffer Descriptor (BD) Ring indices: + * Numbering follows Broadcom literature, which uses indices 1-16. + * PI = producer index, CI = consumer index. + */ + +/* Registers 0x0C00 - 0x0FFF are Send Data Initiator Control registers */ + +#define R_SND_DATA_MODE 0x0C00 +#define R_SND_DATA_STAT 0x0C04 +#define R_SND_DATA_STATS_CTRL 0x0C08 +#define R_SND_DATA_STATS_ENB 0x0C0C +#define R_SND_DATA_STATS_INCR 0x0C10 + +#define R_STATS_CTR_SND_COS(n) (0x0C80 + 4*(n)-4) /* 1 <= n <= 16 */ +#define R_STATS_DMA_RDQ_FULL 0x0CC0 +#define R_STATS_DMA_HP_RDQ_FULL 0x0CC4 +#define R_STATS_SDCQ_FULL 0x0CC8 +#define R_STATS_NIC_SET_SND_PI 0x0CCC +#define R_STATS_STAT_UPDATED 0x0CD0 +#define R_STATS_IRQS 0x0CD4 +#define R_STATS_IRQS_AVOIDED 0x0CD8 +#define R_STATS_SND_THRSH_HIT 0x0CDC + +/* Registers 0x1000 - 0x13FF are Send Data Completion Control registers */ + +#define R_SND_DATA_COMP_MODE 0x1000 + +/* Registers 0x1400 - 0x17FF are Send BD Ring Selection Control registers */ + +#define R_SND_BD_SEL_MODE 0x1400 +#define R_SND_BD_SEL_STAT 0x1404 +#define R_SND_BD_DIAG 0x1408 +#define R_SND_BD_SEL_CI(n) (0x1440 + 4*(n)-4) /* 1 <= n <= 16 */ + +/* Registers 0x1800 - 0x1BFF are Send BD Initiator Control registers */ + +#define R_SND_BD_INIT_MODE 0x1800 +#define R_SND_BD_INIT_STAT 0x1804 +#define R_SND_BD_INIT_PI(n) (0x1808 + 4*(n)-4) /* 1 <= n <= 16 */ + +/* Registers 0x1C00 - 0x1FFF are Send BD Completion Control registers */ + +#define R_SND_BD_COMP_MODE 0x1C00 + +/* Registers 0x2000 - 0x23FF are Receive List Placement Control registers */ + +#define R_RCV_LIST_MODE 0x2000 +#define R_RCV_LIST_STAT 0x2004 +#define R_RCV_LIST_LOCK 0x2008 +#define R_RCV_NONEMPTY_BITS 0x200C +#define R_RCV_LIST_CFG 0x2010 +#define R_RCV_LIST_STATS_CTRL 0x2014 +#define R_RCV_LIST_STATS_ENB 0x2018 +#define R_RCV_LIST_STATS_INC 0x201C +#define R_RCV_LIST_HEAD(n) (0x2100 + 16*(n)-16) /* 1 <= n <= 16 */ +#define R_RCV_LIST_TAIL(n) (0x2104 + 16*(n)-16) +#define R_RCV_LIST_CNT(n) (0x2108 + 16*(n)-16) +#define R_STATS_CTR_RCV_COS(n) (0x2200 + 4*(n)-4) /* 1 <= n <= 16 */ +#define R_STATS_FILT_DROP 0x2240 +#define R_STATS_DMA_WRQ_FULL 0x2244 +#define R_STATS_DMA_HP_WRQ_FULL 0x2248 +#define R_STATS_NO_RCV_BDS 0x224C +#define R_STATS_IN_DISCARDS 0x2250 +#define R_STATS_IN_ERRORS 0x2254 +#define R_STATS_RCV_THRSH_HIT 0x2258 + +/* Registers 0x2400 - 0x27FF are Receive Data/BD Initiator Control registers */ + +#define R_RCV_DATA_INIT_MODE 0x2400 +#define R_RCV_DATA_INIT_STAT 0x2404 +#define R_JUMBO_RCV_BD_RCB 0x2440 /* 16 bytes */ +#define R_STD_RCV_BD_RCB 0x2450 /* 16 bytes */ +#define R_MINI_RCV_BD_RCB 0x2460 /* 16 bytes */ +#define R_RCV_BD_INIT_JUMBO_CI 0x2470 +#define R_RCV_BD_INIT_STD_CI 0x2474 +#define R_RCV_BD_INIT_MINI_CI 0x2478 +#define R_RCV_BD_INIT_RTN_PI(n) (0x2480 + 4*(n)-4) /* 1 <= n <= 16 */ +#define R_RCV_BD_INIT_DIAG 0x24C0 + +/* Registers 0x2800 - 0x2BFF are Receive Data Completion Control registers */ + +#define R_RCV_COMP_MODE 0x2800 + +/* Registers 0x2C00 - 0x2FFF are Receive BD Initiator Control registers */ + +#define R_RCV_BD_INIT_MODE 0x2C00 +#define R_RCV_BD_INIT_STAT 0x2C04 +#define R_RCV_BD_INIT_JUMBO_PI 0x2C08 +#define R_RCV_BD_INIT_STD_PI 0x2C0C +#define R_RCV_BD_INIT_MINI_PI 0x2C10 +#define R_MINI_RCV_BD_THRESH 0x2C14 +#define R_STD_RCV_BD_THRESH 0x2C18 +#define R_JUMBO_RCV_BD_THRESH 0x2C1C + +/* Registers 0x3000 - 0x33FF are Receive BD Completion Control registers */ + +#define R_RCV_BD_COMP_MODE 0x3000 +#define R_RCV_BD_COMP_STAT 0x3004 +#define R_NIC_JUMBO_RCV_BD_PI 0x3008 +#define R_NIC_STD_RCV_BD_PI 0x300C +#define R_NIC_MINI_RCV_BD_PI 0x3010 + +/* Registers 0x3400 - 0x37FF are Receive List Selector Control registers */ + +#define R_RCV_LIST_SEL_MODE 0x3400 +#define R_RCV_LIST_SEL_STATUS 0x3404 + +/* Registers 0x3800 - 0x3BFF are Mbuf Cluster Free registers */ + +#define R_MBUF_FREE_MODE 0x3800 +#define R_MBUF_FREE_STATUS 0x3804 + +/* Registers 0x3C00 - 0x3FFF are Host Coalescing Control registers */ + +#define R_HOST_COAL_MODE 0x3C00 +#define R_HOST_COAL_STAT 0x3C04 +#define R_RCV_COAL_TICKS 0x3C08 +#define R_SND_COAL_TICKS 0x3C0C +#define R_RCV_COAL_MAX_CNT 0x3C10 +#define R_SND_COAL_MAX_CNT 0x3C14 +#define R_RCV_COAL_INT_TICKS 0x3C18 +#define R_SND_COAL_INT_TICKS 0x3C1C +#define R_RCV_COAL_INT_CNT 0x3C20 +#define R_SND_COAL_INT_CNT 0x3C24 +#define R_STATS_TICKS 0x3C28 +#define R_STATS_HOST_ADDR 0x3C30 /* 8 bytes */ +#define R_STATUS_HOST_ADDR 0x3C38 /* 8 bytes */ +#define R_STATS_BASE_ADDR 0x3C40 +#define R_STATUS_BASE_ADDR 0x3C44 +#define R_FLOW_ATTN 0x3C48 +#define R_NIC_JUMBO_RCV_BD_CI 0x3C50 +#define R_NIC_STD_RCV_BD_CI 0x3C54 +#define R_NIC_MINI_RCV_BD_CI 0x3C58 +#define R_NIC_RTN_PI(n) (0x3C80 + 4*(n)-4) /* 1 <= n <= 16 */ +#define R_NIC_SND_BD_CD(n) (0x3CC0 + 4*(n)-4) /* 1 <= n <= 16 */ + +/* Registers 0x4000 - 0x43FF are Memory Arbiter registers */ + +#define R_MEM_MODE 0x4000 +#define R_MEM_STATUS 0x4004 +#define R_MEM_TRAP_LOW 0x4008 +#define R_MEM_TRAP_HIGH 0x400C + + +/* Registers 0x4400 - 0x47FF are Buffer Manager Control registers */ + +#define R_BMGR_MODE 0x4400 +#define R_BMGR_STATUS 0x4404 +#define R_BMGR_MBUF_BASE 0x4408 +#define R_BMGR_MBUF_LEN 0x440C +#define R_BMGR_MBUF_DMA_LOW 0x4410 +#define R_BMGR_MBUF_RX_LOW 0x4414 +#define R_BMGR_MBUF_HIGH 0x4418 + +#define R_BMGR_DMA_BASE 0x442C +#define R_BMGR_DMA_LEN 0x4430 +#define R_BMGR_DMA_LOW 0x4434 +#define R_BMGR_DMA_HIGH 0x4438 + +#define R_BMGR_DIAG1 0x444C +#define R_BMGR_DIAG2 0x4450 +#define R_BMGR_DIAG3 0x4454 +#define R_BMGR_RCV_FLOW_THRESH 0x4458 + +/* Registers 0x4800 - 0x4BFF are Read DMA Control registers */ + +#define R_RD_DMA_MODE 0x4800 +#define R_RD_DMA_STAT 0x4804 + +/* Registers 0x4C00 - 0x4FFF are Write DMA Control registers */ + +#define R_WR_DMA_MODE 0x4C00 +#define R_WR_DMA_STAT 0x4C04 + +/* Registers 0x5000 - 0x53FF are RX RISC registers */ + +#define R_RX_RISC_MODE 0x5000 +#define R_RX_RISC_STATE 0x5004 +#define R_RX_RISC_PC 0x501C + +/* Registers 0x5400 - 0x57FF are TX RISC registers */ + +#define R_TX_RISC_MODE 0x5400 +#define R_TX_RISC_STATE 0x5404 +#define R_TX_RISC_PC 0x541C + +/* Registers 0x5800 - 0x5BFF are Low Priority Mailbox registers (8 bytes) */ + +#define R_LP_INT_MBOX(n) (0x5800 + 8*(n)) /* 0 <= n < 4 */ +#define R_LP_GEN_MBOX(n) (0x5820 + 8*(n)-8) /* 1 <= n <= 8 */ +#define R_LP_RELOAD_STATS_MBOX 0x5860 +#define R_LP_RCV_BD_STD_PI 0x5868 +#define R_LP_RCV_BD_JUMBO_PI 0x5870 +#define R_LP_RCV_BD_MINI_PI 0x5878 +#define R_LP_RCV_BD_RTN_CI(n) (0x5880 + 8*(n)-8) /* 1 <= n <= 16 */ +#define R_LP_SND_BD_PI(n) (0x5900 + 8*(n)-8) /* 1 <= n <= 16 */ + +/* Registers 0x5C00 - 0x5C03 are Flow Through Queues */ + +#define R_FTQ_RESET 0x5C00 + +/* Registers 0x6000 - 0x63FF are Message Signaled Interrupt registers */ + +/* Registers 0x6400 - 0x67FF are DMA Completion registers */ + +#define R_DMA_COMP_MODE 0x6400 + +/* Registers 0x6800 - 0x68ff are General Control registers */ + +#define R_MODE_CTRL 0x6800 +#define R_MISC_CFG 0x6804 +#define R_MISC_LOCAL_CTRL 0x6808 +#define R_TIMER 0x680C +#define R_MEM_PWRUP 0x6030 /* 8 bytes */ +#define R_EEPROM_ADDR 0x6838 +#define R_EEPROM_DATA 0x683C +#define R_EEPROM_CTRL 0x6840 +#define R_MDI_CTRL 0x6844 +#define R_EEPROM_DELAY 0x6848 + +/* Registers 0x6C00 - 0x6CFF are ASF Support registers (NYI) */ + +/* Registers 0x7000 - 0x7024 are NVM Interface registers (NYI) */ + + +/* PCI Capability registers (should be moved to PCI headers) */ + +/* PCI-X Capability and Command Register (0x40) */ + +#define PCIX_CMD_DPREC_ENABLE 0x00010000 +#define PCIX_CMD_RLXORDER_ENABLE 0x00020000 +#define PCIX_CMD_RD_CNT_SHIFT 18 +#define PCIX_CMD_RD_CNT_MASK 0x000C0000 +#define PCIX_CMD_MAX_SPLIT_SHIFT 20 +#define PCIX_CMD_MAX_SPLIT_MASK 0x00700000 + +/* PCI-X Status Register (0x44) */ + + +/* Generic bit fields shared by most MODE and STATUS registers */ + +#define M_MODE_RESET _DD_MAKEMASK1(0) +#define M_MODE_ENABLE _DD_MAKEMASK1(1) +#define M_MODE_ATTNENABLE _DD_MAKEMASK1(2) + +#define M_STAT_ERROR _DD_MAKEMASK1(1) + +/* Generic bit fields shared by STATS_CTRL registers */ + +#define M_STATS_ENABLE _DD_MAKEMASK1(0) +#define M_STATS_FASTUPDATE _DD_MAKEMASK1(1) +#define M_STATS_CLEAR _DD_MAKEMASK1(2) +#define M_STATS_FLUSH _DD_MAKEMASK1(3) +#define M_STATS_ZERO _DD_MAKEMASK1(4) + +/* Private PCI Configuration registers (p 335) */ + +/* MHC: Miscellaneous Host Control Register (0x68) */ + +#define M_MHC_CLEARINTA _DD_MAKEMASK1(0) +#define M_MHC_MASKPCIINT _DD_MAKEMASK1(1) +#define M_MHC_ENBYTESWAP _DD_MAKEMASK1(2) +#define M_MHC_ENWORDSWAP _DD_MAKEMASK1(3) +#define M_MHC_ENPCISTATERW _DD_MAKEMASK1(4) +#define M_MHC_ENCLKCTRLRW _DD_MAKEMASK1(5) +#define M_MHC_ENREGWORDSWAP _DD_MAKEMASK1(6) +#define M_MHC_ENINDIRECT _DD_MAKEMASK1(7) +#define S_MHC_ASICREV 16 +#define M_MHC_ASICREV _DD_MAKEMASK(16,S_MHC_ASICREV) +#define G_MHC_ASICREV(x) _DD_GETVALUE(x,S_MHC_ASICREV,M_MHC_ASICREV) + +/* DMAC: DMA Read/Write Control Register (0x6c) */ + +#define S_DMAC_MINDMA 0 +#define M_DMAC_MINDMA _DD_MAKEMASK(8,S_DMAC_MINDMA) +#define V_DMAC_MINDMA(x) _DD_MAKEVALUE(x,S_DMAC_MINDMA) +#define G_DMAC_MINDMA(x) _DD_GETVALUE(x,S_DMAC_MINDMA,M_DMAC_MINDMA) + +#define M_DMAC_MEMRDMULT _DD_MAKEMASK1(22) /* 570{0,1} only */ +#define M_DMAC_BEALL _DD_MAKEMASK1(23) /* 570{0,1} only */ + +#define S_DMAC_RDCMD 24 /* 570{0,1} only */ +#define M_DMAC_RDCMD _DD_MAKEMASK(4,S_DMAC_RDCMD) +#define V_DMAC_RDCMD(x) _DD_MAKEVALUE(x,S_DMAC_RDCMD) +#define G_DMAC_RDCMD(x) _DD_GETVALUE(x,S_DMAC_RDCMD,M_DMAC_RDCMD) +#define K_PCI_MEMRD 0x6 + +#define S_DMAC_WRCMD 28 +#define M_DMAC_WRCMD _DD_MAKEMASK(4,S_DMAC_WRCMD) +#define V_DMAC_WRCMD(x) _DD_MAKEVALUE(x,S_DMAC_WRCMD) +#define G_DMAC_WRCMD(x) _DD_GETVALUE(x,S_DMAC_WRCMD,M_DMAC_WRCMD) +#define K_PCI_MEMWR 0x7 + +/* PCIS: PCI State Register (0x70) */ + +#define M_PCIS_RESET _DD_MAKEMASK1(0) +#define M_PCIS_INT _DD_MAKEMASK1(1) +#define M_PCIS_MODE _DD_MAKEMASK1(2) +#define M_PCIS_33MHZ _DD_MAKEMASK1(3) +#define M_PCIS_32BIT _DD_MAKEMASK1(4) +#define M_PCIS_ROMEN _DD_MAKEMASK1(5) +#define M_PCIS_ROMRETRY _DD_MAKEMASK1(6) +#define M_PCIS_FLATVIEW _DD_MAKEMASK1(8) +/* ... more ... */ + +/* PCI Clock Control Register (0x74) */ + +/* Register Base Address Register (0x78) */ + +/* Memory Window Base Address Register (0x7c) */ + + +/* High Priority Mailboxes (p 323) */ + + +/* Ethernet MAC Control registers (p 358) */ + +/* MACM: Ethernet MAC Mode Register (0x400) */ + +#define M_MACM_GLBRESET _DD_MAKEMASK1(0) +#define M_MACM_HALFDUPLEX _DD_MAKEMASK1(1) + +#define S_MACM_PORTMODE 2 +#define M_MACM_PORTMODE _DD_MAKEMASK(2,S_MACM_PORTMODE) +#define V_MACM_PORTMODE(x) _DD_MAKEVALUE(x,S_MACM_PORTMODE) +#define G_MACM_PORTMODE(x) _DD_GETVALUE(x,S_MACM_PORTMODE,M_MACM_PORTMODE) +#define K_MACM_PORTMODE_NONE 0x0 +#define K_MACM_PORTMODE_MII 0x1 +#define K_MACM_PORTMODE_GMII 0x2 +#define K_MACM_PORTMODE_TBI 0x3 + +#define M_MACM_LOOPBACK _DD_MAKEMASK1(4) +#define M_MACM_TAGGEDMAC _DD_MAKEMASK1(7) +#define M_MACM_TXBURST _DD_MAKEMASK1(8) +#define M_MACM_MAXDEFER _DD_MAKEMASK1(9) +#define M_MACM_LINKPOLARITY _DD_MAKEMASK1(10) +#define M_MACM_RXSTATSENB _DD_MAKEMASK1(11) +#define M_MACM_RXSTATSCLR _DD_MAKEMASK1(12) +#define M_MACM_RXSTATSFLUSH _DD_MAKEMASK1(13) +#define M_MACM_TXSTATSENB _DD_MAKEMASK1(14) +#define M_MACM_TXSTATSCLR _DD_MAKEMASK1(15) +#define M_MACM_TXSTATSFLUSH _DD_MAKEMASK1(16) +#define M_MACM_SENDCFGS _DD_MAKEMASK1(17) +#define M_MACM_MAGICPKT _DD_MAKEMASK1(18) +#define M_MACM_ACPI _DD_MAKEMASK1(19) +#define M_MACM_MIPENB _DD_MAKEMASK1(20) +#define M_MACM_TDEENB _DD_MAKEMASK1(21) +#define M_MACM_RDEENB _DD_MAKEMASK1(22) +#define M_MACM_FHDEENB _DD_MAKEMASK1(23) + +/* MACSTAT: Ethernet MAC Status Register (0x404) */ +/* MACEVNT: Ethernet MAC Event Enable Register (0x408) */ + +/* Status Register only */ +#define M_MACSTAT_PCSSYNC _DD_MAKEMASK1(0) +#define M_MACSTAT_SIGDET _DD_MAKEMASK1(1) +#define M_MACSTAT_RCVCFG _DD_MAKEMASK1(2) +#define M_MACSTAT_CFGCHNG _DD_MAKEMASK1(3) +#define M_MACSTAT_SYNCCHNG _DD_MAKEMASK1(4) +/* Status and Enable Registers */ +#define M_EVT_PORTERR _DD_MAKEMASK1(10) +#define M_EVT_LINKCHNG _DD_MAKEMASK1(12) +#define M_EVT_MICOMPLETE _DD_MAKEMASK1(22) +#define M_EVT_MIINT _DD_MAKEMASK1(23) +#define M_EVT_APERR _DD_MAKEMASK1(24) +#define M_EVT_ODIERR _DD_MAKEMASK1(25) +#define M_EVT_RXSTATOVRUN _DD_MAKEMASK1(26) +#define M_EVT_TXSTATOVRUN _DD_MAKEMASK1(27) + +/* MICOMM: MI Communication Register (0x44c) */ + +#define S_MICOMM_DATA 0 +#define M_MICOMM_DATA _DD_MAKEMASK(16,S_MICOMM_DATA) +#define V_MICOMM_DATA(x) _DD_MAKEVALUE(x,S_MICOMM_DATA) +#define G_MICOMM_DATA(x) _DD_GETVALUE(x,S_MICOMM_DATA,M_MICOMM_DATA) + +#define S_MICOMM_REG 16 +#define M_MICOMM_REG _DD_MAKEMASK(5,S_MICOMM_REG) +#define V_MICOMM_REG(x) _DD_MAKEVALUE(x,S_MICOMM_REG) +#define G_MICOMM_REG(x) _DD_GETVALUE(x,S_MICOMM_REG,M_MICOMM_REG) + +#define S_MICOMM_PHY 21 +#define M_MICOMM_PHY _DD_MAKEMASK(5,S_MICOMM_PHY) +#define V_MICOMM_PHY(x) _DD_MAKEVALUE(x,S_MICOMM_PHY) +#define G_MICOMM_PHY(x) _DD_GETVALUE(x,S_MICOMM_PHY,M_MICOMM_PHY) + +#define S_MICOMM_CMD 26 +#define M_MICOMM_CMD _DD_MAKEMASK(2,S_MICOMM_CMD) +#define V_MICOMM_CMD(x) _DD_MAKEVALUE(x,S_MICOMM_CMD) +#define G_MICOMM_CMD(x) _DD_GETVALUE(x,S_MICOMM_CMD,M_MICOMM_CMD) +#define K_MICOMM_CMD_WR 0x1 +#define K_MICOMM_CMD_RD 0x2 +#define V_MICOMM_CMD_WR V_MICOMM_CMD(K_MICOMM_CMD_WR) +#define V_MICOMM_CMD_RD V_MICOMM_CMD(K_MICOMM_CMD_RD) + +#define M_MICOMM_RDFAIL _DD_MAKEMASK1(28) +#define M_MICOMM_BUSY _DD_MAKEMASK1(29) + +/* MISTAT: MI Status Register (0x450) */ + +#define M_MISTAT_LINKED _DD_MAKEMASK1(0) +#define M_MISTAT_10MBPS _DD_MAKEMASK1(1) + +/* MIMODE: MI Mode Register (0x454) */ + +#define M_MIMODE_SHORTPREAMBLE _DD_MAKEMASK1(1) +#define M_MIMODE_POLLING _DD_MAKEMASK1(4) + +#define S_MIMODE_CLKCNT 16 +#define M_MIMODE_CLKCNT _DD_MAKEMASK(5,S_MIMODE_CLKCNT) +#define V_MIMODE_CLKCNT(x) _DD_MAKEVALUE(x,S_MIMODE_CLKCNT) +#define G_MIMODE_CLKCNT(x) _DD_GETVALUE(x,S_MIMODE_CLKCNT,M_MIMODE_CLKCNT) + +/* TXLEN: Transmit MAC Lengths Register (0x464) */ + +#define S_TXLEN_SLOT 0 +#define M_TXLEN_SLOT _DD_MAKEMASK(8,S_TXLEN_SLOT) +#define V_TXLEN_SLOT(x) _DD_MAKEVALUE(x,S_TXLEN_SLOT) +#define G_TXLEN_SLOT(x) _DD_GETVALUE(x,S_TXLEN_SLOT,M_TXLEN_SLOT) + +#define S_TXLEN_IPG 8 +#define M_TXLEN_IPG _DD_MAKEMASK(4,S_TXLEN_IPG) +#define V_TXLEN_IPG(x) _DD_MAKEVALUE(x,S_TXLEN_IPG) +#define G_TXLEN_IPG(x) _DD_GETVALUE(x,S_TXLEN_IPG,M_TXLEN_IPG) + +#define S_TXLEN_IPGCRS 12 +#define M_TXLEN_IPGCRS _DD_MAKEMASK(2,S_TXLEN_IPGCRS) +#define V_TXLEN_IPGCRS(x) _DD_MAKEVALUE(x,S_TXLEN_IPGCRS) +#define G_TXLEN_IPGCRS(x) _DD_GETVALUE(x,S_TXLEN_IPGCRS,M_TXLEN_IPGCRS) + +/* RULESCFG: Receive Rules Configuration Register (0x500) */ + +#define S_RULESCFG_DEFAULT 3 +#define M_RULESCFG_DEFAULT _DD_MAKEMASK(5,S_RULESCFG_DEFAULT) +#define V_RULESCFG_DEFAULT(x) _DD_MAKEVALUE(x,S_RULESCFG_DEFAULT) +#define G_RULESCFG_DEFAULT(x) _DD_GETVALUE(x,S_RULESCFG_DEFAULT,M_RULESCFG_DEFAULT) + + +/* Send Data Initiator Control Registers (p 383) */ +/* Send BD Ring Selector Control Registers (p 387) */ +/* Send BD Initiator Control Registers (p 389) */ + + +/* Receive List Placement Control Registers (p 392) */ + +/* LISTCFG: Receive List Placement Configuration Register (0x2010) */ + +#define S_LISTCFG_GROUP 0 +#define M_LISTCFG_GROUP _DD_MAKEMASK(3,S_LISTCFG_GROUP) +#define V_LISTCFG_GROUP(x) _DD_MAKEVALUE(x,S_LISTCFG_GROUP) +#define G_LISTCFG_GROUP(x) _DD_GETVALUE(x,S_LISTCFG_GROUP,M_LISTCFG_GROUP) + +#define S_LISTCFG_ACTIVE 3 +#define M_LISTCFG_ACTIVE _DD_MAKEMASK(5,S_LISTCFG_ACTIVE) +#define V_LISTCFG_ACTIVE(x) _DD_MAKEVALUE(x,S_LISTCFG_ACTIVE) +#define G_LISTCFG_ACTIVE(x) _DD_GETVALUE(x,S_LISTCFG_ACTIVE,M_LISTCFG_ACTIVE) + +#define S_LISTCFG_BAD 8 +#define M_LISTCFG_BAD _DD_MAKEMASK(5,S_LISTCFG_BAD) +#define V_LISTCFG_BAD(x) _DD_MAKEVALUE(x,S_LISTCFG_BAD) +#define G_LISTCFG_BAD(x) _DD_GETVALUE(x,S_LISTCFG_BAD,M_LISTCFG_BAD) + +#define S_LISTCFG_DEFAULT 13 +#define M_LISTCFG_DEFAULT _DD_MAKEMASK(2,S_LISTCFG_DEFAULT) +#define V_LISTCFG_DEFAULT(x) _DD_MAKEVALUE(x,S_LISTCFG_DEFAULT) +#define G_LISTCFG_DEFAULT(x) _DD_GETVALUE(x,S_LISTCFG_DEFAULT,M_LISTCFG_DEFAULT) + + +/* Receive Data and Receive BD Initiator Control Registers (p 399) */ + +/* RCVINITMODE: Receive Data and Receive BD Initiator Mode Register (0x2400) */ + +#define M_RCVINITMODE_JUMBO _DD_MAKEMASK1(2) +#define M_RCVINITMODE_FRMSIZE _DD_MAKEMASK1(3) +#define M_RCVINITMODE_RTNSIZE _DD_MAKEMASK1(4) + + +/* Receive Initiator Control Registers (p 404) */ +/* Receive BD Completion Control Registers (p 406) */ +/* Receive List Selector Control Registers (p 408) */ +/* Mbuf Cluster Free Registers (p 409) */ + + +/* Host Coalescing Control registers (p 410) */ + +/* HCM: Host Coalescing Mode Register (0x3C00) */ + +#define M_HCM_RESET _DD_MAKEMASK1(0) +#define M_HCM_ENABLE _DD_MAKEMASK1(1) +#define M_HCM_ATTN _DD_MAKEMASK1(2) +#define M_HCM_COAL_NOW _DD_MAKEMASK1(3) + +#define S_HCM_MSIBITS 4 +#define M_HCM_MSIBITS _DD_MAKEMASK(3,S_HCM_MSIBITS) +#define V_HCM_MSIBITS(x) _DD_MAKEVALUE(x,S_HCM_MSIBITS) +#define G_HCM_MSIBITS _DD_GETVALUE(x,S_HCM_MSIBITS,M_HCM_MSIBITS) + +#define S_HCM_SBSIZE 7 +#define M_HCM_SBSIZE _DD_MAKEMASK(2,S_HCM_SBSIZE) +#define V_HCM_SBSIZE(x) _DD_MAKEVALUE(x,S_HCM_SBSIZE) +#define G_HCM_SBSIZE _DD_GETVALUE(x,S_HCM_SBSIZE,M_HCM_SBSIZE) +#define K_HCM_SBSIZE_80 0x0 +#define K_HCM_SBSIZE_64 0x1 +#define K_HCM_SBSIZE_32 0x2 +/* ... more ... */ + + +/* Memory Arbiter Registers (p 420) */ + +/* MAM: Memory Arbiter Mode Register (0x4000) */ + +#define M_MAM_RESET _DD_MAKEMASK1(0) +#define M_MAM_ENABLE _DD_MAKEMASK1(1) + +/* Memory Arbiter Status Register (0x4004) */ + +/* Memory Arbiter Trap Low and Trap High Registers (0x4008, 0x400C) */ + + +/* Buffer Manager Control Registers (p 424) */ + +/* BMODE: Buffer Manager Control Register (0x4400) */ + +#define M_BMODE_RESET _DD_MAKEMASK1(0) +#define M_BMODE_ENABLE _DD_MAKEMASK1(1) +#define M_BMODE_ATTN _DD_MAKEMASK1(2) +#define M_BMODE_TEST _DD_MAKEMASK1(3) +#define M_BMODE_MBUFLOWATTN _DD_MAKEMASK1(4) + + +/* Read DMA Control Registers (p 428) */ +/* Write DMA Control Registers (p 431) */ + +/* Bit fields shared by DMA_MODE and DMA_STATUS registers */ + +#define M_ATTN_TGTABORT _DD_MAKEMASK1(2) +#define M_ATTN_MSTRABORT _DD_MAKEMASK1(3) +#define M_ATTN_PERR _DD_MAKEMASK1(4) +#define M_ATTN_ADDROVFL _DD_MAKEMASK1(5) +#define M_ATTN_FIFOOVFL _DD_MAKEMASK1(6) +#define M_ATTN_FIFOUNFL _DD_MAKEMASK1(7) +#define M_ATTN_FIFOREAD _DD_MAKEMASK1(8) +#define M_ATTN_LENERR _DD_MAKEMASK1(9) +#define M_ATTN_ALL (M_ATTN_TGTABORT | M_ATTN_MSTRABORT | \ + M_ATTN_PERR | M_ATTN_ADDROVFL | \ + M_ATTN_FIFOOVFL | M_ATTN_FIFOUNFL | \ + M_ATTN_FIFOREAD | M_ATTN_LENERR) + +/* Read DMA Mode Register (0x4800) */ +/* Write DMA Mode Register (0x4C00) */ + +/* Read DMA Status Register (0x4804) */ +/* Write DMA Status Register (0x4C04) */ + + +/* RX RISC Registers (p 433) */ +/* TX RISC Registers (p 437) */ +/* Low Priority Mailboxes (p 441) */ +/* Flow Through Queues (p 445) */ +/* Message Signaled Interrupt Registers (p 447) */ +/* DMA Completion Registers (p 449) */ + + +/* General Control registers (p 450) */ + +/* MCTL: Miscellaneous Host Control Register (0x6800) */ + +#define M_MCTL_UPDATE _DD_MAKEMASK1(0) +#define M_MCTL_BSWAPCTRL _DD_MAKEMASK1(1) +#define M_MCTL_WSWAPCTRL _DD_MAKEMASK1(2) +#define M_MCTL_BSWAPDATA _DD_MAKEMASK1(4) +#define M_MCTL_WSWAPDATA _DD_MAKEMASK1(5) +#define M_MCTL_NOCRACK _DD_MAKEMASK1(9) +#define M_MCTL_NOCRC _DD_MAKEMASK1(10) +#define M_MCTL_ACCEPTBAD _DD_MAKEMASK1(11) +#define M_MCTL_NOTXINT _DD_MAKEMASK1(13) +#define M_MCTL_NORTRNINT _DD_MAKEMASK1(14) +#define M_MCTL_PCI32 _DD_MAKEMASK1(15) +#define M_MCTL_HOSTUP _DD_MAKEMASK1(16) +#define M_MCTL_HOSTBDS _DD_MAKEMASK1(17) +#define M_MCTL_NOTXPHSUM _DD_MAKEMASK1(20) +#define M_MCTL_NORXPHSUM _DD_MAKEMASK1(23) +#define M_MCTL_TXINT _DD_MAKEMASK1(24) +#define M_MCTL_RXINT _DD_MAKEMASK1(25) +#define M_MCTL_MACINT _DD_MAKEMASK1(26) +#define M_MCTL_DMAINT _DD_MAKEMASK1(27) +#define M_MCTL_FLOWINT _DD_MAKEMASK1(28) +#define M_MCTL_4XRINGS _DD_MAKEMASK1(29) +#define M_MCTL_MCASTEN _DD_MAKEMASK1(30) + +/* MCFG: Miscellaneous Configuration Register (0x6804) */ + +#define M_MCFG_CORERESET _DD_MAKEMASK1(0) +#define S_MCFG_PRESCALER 1 +#define M_MCFG_PRESCALER _DD_MAKEMASK(7,S_MCFG_PRESCALER) +#define V_MCFG_PRESCALER(x) _DD_MAKEVALUE(x,S_MCFG_PRESCALER) +#define G_MCFG_PRESCALER(x) _DD_GETVALUE(x,S_MCFG_PRESCALER,M_MCFG_PRESCALER) + +/* MLCTL: Miscellaneous Local Control Register (0x6808) */ + +#define M_MLCTL_INTSTATE _DD_MAKEMASK1(0) +#define M_MLCTL_INTCLR _DD_MAKEMASK1(1) +#define M_MLCTL_INTSET _DD_MAKEMASK1(2) +#define M_MLCTL_INTATTN _DD_MAKEMASK1(3) +/* ... */ +#define M_MLCTL_EPAUTOACCESS _DD_MAKEMASK1(24) + +/* EPADDR: Serial EEPROM Address Register (0x6838) */ + +#define S_EPADDR_ADDR 0 +#define M_EPADDR_ADDR (_DD_MAKEMASK(16,S_EPADDR_ADDR) & ~3) +#define V_EPADDR_ADDR(x) _DD_MAKEVALUE(x,S_EPADDR_ADDR) +#define G_EPADDR_ADDR(x) _DD_GETVALUE(x,S_EPADDR_ADDR,M_EPADDR_ADDR) + +#define S_EPADDR_HPERIOD 16 +#define M_EPADDR_HPERIOD _DD_MAKEMASK(9,S_EPADDR_HPERIOD) +#define V_EPADDR_HPERIOD(x) _DD_MAKEVALUE(x,S_EPADDR_HPERIOD) +#define G_EPADDR_HPERIOD(x) _DD_GETVALUE(x,S_EPADDR_HPERIOD,M_EPADDR_HPERIOD) + +#define M_EPADDR_START _DD_MAKEMASK1(25) + +#define S_EPADDR_DEVID 26 +#define M_EPADDR_DEVID _DD_MAKEMASK(3,S_EPADDR_DEVID) +#define V_EPADDR_DEVID(x) _DD_MAKEVALUE(x,S_EPADDR_DEVID) +#define G_EPADDR_DEVID(x) _DD_GETVALUE(x,S_EPADDR_DEVID,M_EPADDR_DEVID) + +#define M_EPADDR_RESET _DD_MAKEMASK1(29) +#define M_EPADDR_COMPLETE _DD_MAKEMASK1(30) +#define M_EPADDR_RW _DD_MAKEMASK1(31) + +/* EPDATA: Serial EEPROM Data Register (0x683C) */ + +/* EPCTL: Serial EEPROM Control Register (0x6840) */ + +#define M_EPCTL_CLOCKTS0 _DD_MAKEMASK1(0) +#define M_EPCTL_CLOCKO _DD_MAKEMASK1(1) +#define M_EPCTL_CLOCKI _DD_MAKEMASK1(2) +#define M_EPCTL_DATATSO _DD_MAKEMASK1(3) +#define M_EPCTL_DATAO _DD_MAKEMASK1(4) +#define M_EPCTL_DATAI _DD_MAKEMASK1(5) + +/* MDCTL: MDI Control Register (0x6844) */ + +#define M_MDCTL_DATA _DD_MAKEMASK1(0) +#define M_MDCTL_ENABLE _DD_MAKEMASK1(1) +#define M_MDCTL_SELECT _DD_MAKEMASK1(2) +#define M_MDCTL_CLOCK _DD_MAKEMASK1(3) + + +/* Ring Control Blocks (p 97) */ + +#define RCB_HOST_ADDR_HIGH 0x0 +#define RCB_HOST_ADDR_LOW 0x4 +#define RCB_CTRL 0x8 +#define RCB_NIC_ADDR 0xC + +#define RCB_SIZE 0x10 + +#define RCB_FLAG_USE_EXT_RCV_BD _DD_MAKEMASK1(0) +#define RCB_FLAG_RING_DISABLED _DD_MAKEMASK1(1) + +#define S_RCB_MAXLEN 16 +#define M_RCB_MAXLEN _DD_MAKEMASK(16,S_RCB_MAXLEN) +#define V_RCB_MAXLEN(x) _DD_MAKEVALUE(x,S_RCB_MAXLEN) +#define G_RCB_MAXLEN(x) _DD_GETVALUE(x,S_RCB_MAXLEN,M_RCB_MAXLEN) + + +/* On-chip Memory Map (Tables 70 and 71, pp 178-179) This is the map + for the 5700 with no external SRAM, the 5701, 5702 and 5703. The + 5705 does not fully implement some ranges and maps the buffer pool + differently. */ + +/* Locations 0x0000 - 0x00FF are Page Zero */ + +/* Locations 0x0100 - 0x01FF are Send Producer Ring RCBs */ + +#define A_SND_RCBS 0x0100 +#define L_SND_RCBS (16*RCB_SIZE) +#define A_SND_RCB(n) (A_SND_RCBS + ((n)-1)*RCB_SIZE) + +/* Locations 0x0200 - 0x02FF are Receive Return Ring RCBs */ + +#define A_RTN_RCBS 0x0200 +#define L_RTN_RCBS (16*RCB_SIZE) +#define A_RTN_RCB(n) (A_RTN_RCBS + ((n)-1)*RCB_SIZE) + +/* Locations 0x0300 - 0x0AFF are Statistics Block */ + +#define A_MAC_STATS 0x0300 +#define L_MAC_STATS (0x0B00-A_MAC_STATS) + +/* Locations 0x0B00 - 0x0B4F are Status Block */ + +#define A_MAC_STATUS 0x0B00 +#define L_MAC_STATUS (0x0B50-A_MAC_STATUS) + +/* Locations 0x0B50 - 0x0FFF are Software General Communication */ + +#define A_PXE_MAILBOX 0x0B50 +#define T3_MAGIC_NUMBER 0x4B657654 + +/* Locations 0x1000 - 0x1FFF are unmapped */ + +/* Locations 0x2000 - 0x3FFF are DMA Descriptors */ + +#define A_DMA_DESCS 0x2000 +#define L_DMA_DESCS (0x4000-A_DMA_DESCS) + +/* Locations 0x4000 - 0x5FFF are Send Rings 1-4 */ + +#define A_SND_RINGS 0x4000 +#define L_SND_RINGS (0x6000-A_SND_RINGS) + +/* Locations 0x6000 - 0x6FFF are Standard Receive Rings */ + +#define A_STD_RCV_RINGS 0x6000 +#define L_STD_RCV_RINGS (0x7000-A_STD_RCV_RINGS) + +/* Locations 0x7000 - 0x7FFF are Jumbo Receive Rings */ + +#define A_JUMBO_RCV_RINGS 0x7000 +#define L_JUMBO_RCV_RINGS (0x8000-A_JUMBO_RCV_RINGS) + +/* Locations 0x08000 - 0x0FFFF are Buffer Pool 1 */ +/* Locations 0x10000 - 0x17FFF are Buffer Pool 2 */ +/* Locations 0x18000 - 0x1FFFF are Buffer Pool 3 */ + +#define A_BUFFER_POOL 0x08000 +#define L_BUFFER_POOL (0x20000-A_BUFFER_POOL) + +/* Locations 0x08000 - 0x09FFF are TXMBUF (5705) */ +/* Locations 0x10000 - 0x1DFFF are RXMBUF (5705) */ + +#define A_TXMBUF 0x080000 +#define L_TXMBUF (0x0A000-A_TXMBUF) +#define A_RXMBUF 0x100000 +#define L_RXMBUF (0x1E000-A_RXMBUF) + + +/* Indices of (8-byte) counters in the Statistics Block. */ + +#define ifHCInOctets 32 +#define etherStatsFragments 34 +#define ifHCInUcastPkts 35 +#define ifHCInMulticastPkts 36 +#define ifHCInBroadcastPkts 37 +#define dot3StatsFCSErrors 38 +#define dot3StatsAlignmentErrors 39 +#define xonPauseFramesReceived 40 +#define xoffPauseFramesReceived 41 +#define macControlFramesReceived 42 +#define xoffSateEntered 43 +#define dot3StatsFrameTooLongs 44 +#define etherStatsJabbers 45 +#define etherStatsUndersizePkts 46 +#define inRangeLengthError 47 +#define outRangeLengthError 48 +#define etherStatsPkts64Octets 49 +#define etherStatsPkts65to127Octets 50 +#define etherStatsPkts128to255Octets 51 +#define etherStatsPkts256to511Octets 52 +#define etherStatsPkts512to1023Octets 53 +#define etherStatsPkts1024to1522Octets 54 +#define etherStatsPkts1523to2047Octets 55 +#define etherStatsPkts2048to4095Octets 56 +#define etherStatsPkts4096to8191Octets 57 +#define etherStatsPkts8192to9022Octets 58 + +#define ifHCOutOctets 96 +#define etherStatsCollisions 98 +#define outXonSent 99 +#define outXoffSent 100 +#define flowControlDone 101 +#define dot3StatsInternalMacTransmitErrors 102 +#define dot3StatsSingleCollisionFrames 103 +#define dot3StatsMultipleCollisionFrames 104 +#define dot3StatsDeferredTransmissions 105 +#define dot3StatsExcessiveCollisions 107 +#define dot3StatsLateCollisions 108 +#define dot3Collided2Times 109 +#define dot3Collided3Times 110 +#define dot3Collided4Times 111 +#define dot3Collided5Times 112 +#define dot3Collided6Times 113 +#define dot3Collided7Times 114 +#define dot3Collided8Times 115 +#define dot3Collided9Times 116 +#define dot3Collided10Times 117 +#define dot3Collided11Times 118 +#define dot3Collided12Times 119 +#define dot3Collided13Times 120 +#define dot3Collided14Times 121 +#define dot3Collided15Times 122 +#define ifHCOutUcastPkts 123 +#define ifHCOutMulticastPkts 124 +#define ifHCOutBroadcastPkts 125 +#define dot3StatsCarrierSenseErrors 126 +#define ifOutDiscards 127 +#define ifOutErrors 128 + +#define COSifHCInPkts1 160 +#define COSifHCInPkts2 161 +#define COSifHCInPkts3 162 +#define COSifHCInPkts4 163 +#define COSifHCInPkts5 164 +#define COSifHCInPkts6 165 +#define COSifHCInPkts7 166 +#define COSifHCInPkts8 167 +#define COSifHCInPkts9 168 +#define COSifHCInPkts10 169 +#define COSifHCInPkts11 170 +#define COSifHCInPkts12 171 +#define COSifHCInPkts13 172 +#define COSifHCInPkts14 173 +#define COSifHCInPkts15 174 +#define COSifHCInPkts16 175 +#define COSFramesDroppedDueToFilters 176 +#define nicDmaWriteQueueFull 177 +#define nicDmaWriteHighPriQueueFull 178 +#define nicNoMoreRxBDs 179 +#define ifInDiscards 180 +#define ifInErrors 181 +#define nicRecvThresholdHit 182 + +#define COSifHCOutPkts1 192 +#define COSifHCOutPkts2 193 +#define COSifHCOutPkts3 194 +#define COSifHCOutPkts4 195 +#define COSifHCOutPkts5 196 +#define COSifHCOutPkts6 197 +#define COSifHCOutPkts7 198 +#define COSifHCOutPkts8 199 +#define COSifHCOutPkts9 200 +#define COSifHCOutPkts10 201 +#define COSifHCOutPkts11 202 +#define COSifHCOutPkts12 203 +#define COSifHCOutPkts13 204 +#define COSifHCOutPkts14 205 +#define COSifHCOutPkts15 206 +#define COSifHCOutPkts16 207 +#define nicDmaReadQueueFull 208 +#define nicDmaReadHighPriQueueFull 209 +#define nicSendDataCompQueueFull 210 +#define nicRingSetSendProdIndex 211 +#define nicRingStatusUpdate 212 +#define nicInterrupts 213 +#define nicAvoidedInterrupts 214 +#define nicSendThresholdHit 215 + +#endif /* _BCM_5700_H_ */ diff --git a/cfe/cfe/dev/bcm5821.h b/cfe/cfe/dev/bcm5821.h new file mode 100644 index 0000000..29ece60 --- /dev/null +++ b/cfe/cfe/dev/bcm5821.h @@ -0,0 +1,278 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * BCM5821 cryptoaccelerator File: bcm5821.h + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _BCM5821_H_ +#define _BCM5821_H_ + +/* Register and field definitions for the Broadcom BCM5821 crypto + accelerator. The BCM5820 implements a compatible (modulo bugs) + subset of the BCM5821. */ + +#define K_PCI_VENDOR_BROADCOM 0x14e4 +#define K_PCI_ID_BCM5820 0x5820 +#define K_PCI_ID_BCM5821 0x5821 + +#define _DD_MAKEMASK1(n) (1 << (n)) +#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n)) +#define _DD_MAKEVALUE(v,n) ((v) << (n)) +#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n)) + + +/* DMA Control and Status Register offsets */ + +#define R_MCR1 0x00 +#define R_DMA_CTRL 0x04 +#define R_DMA_STAT 0x08 +#define R_DMA_ERR 0x0C +#define R_MCR2 0x10 + + +/* 0x00 MCR1@: Master Command Record 1 Address */ +/* 0x10 MCR2@: Master Command Record 2 Address */ + + +/* 0x04 DMA Control */ + +#define M_DMA_CTRL_WR_BURST _DD_MAKEMASK1(16) /* Not 5820 */ + +#define K_DMA_WR_BURST_128 0 +#define K_DMA_WR_BURST_240 M_DMA_CRTL_WR_BURST + +#define M_DMA_CTRL_MOD_NORM _DD_MAKEMASK1(22) +#define M_DMA_CTRL_RNG_MODE _DD_MAKEMASK1(23) +#define M_DMA_CTRL_DMAERR_EN _DD_MAKEMASK1(25) +#define M_DMA_CTRL_NORM_PCI _DD_MAKEMASK1(26) /* Not 5820 */ +#define M_DMA_CTRL_LE_CRYPTO _DD_MAKEMASK1(27) /* Not 5820 */ +#define M_DMA_CTRL_MCR1_INT_EN _DD_MAKEMASK1(29) +#define M_DMA_CTRL_MCR2_INT_EN _DD_MAKEMASK1(30) +#define M_DMA_CTRL_RESET _DD_MAKEMASK1(31) + + +/* 0x08 DMA Status */ + +#define M_DMA_STAT_MCR2_EMPTY _DD_MAKEMASK1(24) /* Not 5820 */ +#define M_DMA_STAT_MCR1_EMPTY _DD_MAKEMASK1(25) /* Not 5820 */ +#define M_DMA_STAT_MCR2_INTR _DD_MAKEMASK1(26) +#define M_DMA_STAT_MCR2_FULL _DD_MAKEMASK1(27) +#define M_DMA_STAT_DMAERR_INTR _DD_MAKEMASK1(28) +#define M_DMA_STAT_MCR1_INTR _DD_MAKEMASK1(29) +#define M_DMA_STAT_MCR1_FULL _DD_MAKEMASK1(30) +#define M_DMA_STAT_MSTR_ACCESS _DD_MAKEMASK1(31) + +/* 0x0C DMA Error Address */ + +#define M_DMA_ERR_RD_FAULT _DD_MAKEMASK1(1) +#define M_DMA_ERR_ADDR 0xFFFFFFFC + + +/* Master Command Record Header Format */ + +#define S_MCR_NUM_PACKETS 0 +#define M_MCR_NUM_PACKETS _DD_MAKEMASK(16,S_MCR_NUM_PACKETS) +#define V_MCR_NUM_PACKETS(x) _DD_MAKEVALUE(x,S_MCR_NUM_PACKETS) +#define G_MCR_NUM_PACKETS(x) _DD_GETVALUE(x,S_MCR_NUM_PACKETS,M_MCR_NUM_PACKETS) + +/* Input flags */ + +#define M_MCR_SUPPRESS_INTR _DD_MAKEMASK1(31) + +/* Output flags */ + +#define M_MCR_DONE _DD_MAKEMASK1(16) +#define M_MCR_ERROR _DD_MAKEMASK1(17) + +#define S_MCR_ERROR_CODE 24 +#define M_MCR_ERROR_CODE _DD_MAKEMASK(8,S_MCR_ERROR_CODE) +#define V_MCR_ERROR_CODE(x) _DD_MAKEVALUE(x,S_MCR_ERROR_CODE) +#define G_MCR_ERROR_CODE(x) _DD_GETVALUE(x,S_MCR_ERROR_CODE,M_MCR_ERROR_CODE) +#define K_MCR_ERROR_OK 0 +#define K_MCR_ERROR_UNKNOWN_OP 1 +#define K_MCR_ERROR_DSA_SHORT 2 +#define K_MCR_ERROR_PKI_SHORT 3 +#define K_MCR_ERROR_PKO_SHORT 4 /* Not 5820 */ +#define K_MCR_ERROR_CHAIN_SHORT 5 /* Not 5820 */ +#define K_MCR_ERROR_FIFO 6 /* Not 5820 */ + +/* In both cases, the header word is followed by an array of N PD entries: + commandContext[0] + dataBuffer[0] + pktLen[0] + outputBuffer[0] + ... + commandContext[n-1] + dataBuffer[n-1] + pktLen[n-1] + outputBuffer[n-1] +*/ + +#define MCR_WORDS(n) (1+8*(n)) +#define MCR_BYTES(n) ((1+8*(n))*4) + + +/* Data Buffer Chain Entry Offsets */ + +#define DBC_ADDR 0 +#define DBC_NEXT 4 +#define DBC_LEN 8 + +#define CHAIN_WORDS 3 + +#define S_DBC_DATA_LEN 0 +#define M_DBC_DATA_LEN _DD_MAKEMASK(16,S_DBC_DATA_LEN) +#define V_DBC_DATA_LEN(x) _DD_MAKEVALUE(x,S_DBC_DATA_LEN) +#define G_DBC_DATA_LEN(x) _DD_GETVALUE(x,S_DBC_DATA_LEN,M_DBC_DATA_LEN) + +/* Packet Descriptor Offsets */ + +#define PD_CC_ADDR 0 +#define PD_INPUT_FRAG 4 +#define PD_INPUT_FRAG_ADDR (PD_INPUT_FRAG+DBC_ADDR) +#define PD_INPUT_FRAG_NEXT (PD_INPUT_FRAG+DBC_NEXT) +#define PD_INPUT_FRAG_LEN (PD_INPUT_FRAG+DBC_LEN) +#define PD_PKT_LEN 16 +#define PD_OUTPUT_FRAG 20 +#define PD_OUTPUT_FRAG_ADDR (PD_OUTPUT_FRAG+DBC_ADDR) +#define PD_OUTPUT_FRAG_NEXT (PD_OUTPUT_FRAG+DBC_NEXT) +#define PD_OUTPUT_FRAG_LEN (PD_OUTPUT_FRAG+DBC_LEN) + +#define PD_SIZE 32 + +#define S_PD_PKT_LEN 16 +#define M_PD_PKT_LEN _DD_MAKEMASK(16,S_PD_PKT_LEN) +#define V_PD_PKT_LEN(x) _DD_MAKEVALUE(x,S_PD_PKT_LEN) +#define G_PD_PKT_LEN(x) _DD_GETVALUE(x,S_PD_PKT_LEN,M_PD_PKT_LEN) + + +/* Crypotographic Operations */ + +/* MCR1 only (symmetric) */ +#define K_IPSEC_3DES 0x0000 /* Not 5820 */ +#define K_SSL_MAC 0x0001 +#define K_TLS_HMAC 0x0002 +#define K_SSL_3DES 0x0003 +#define K_ARC4 0x0004 +#define K_HASH 0x0005 + +/* MCR2 only (asymmetric) */ +#define K_DH_PK_GEN 0x0001 +#define K_DH_SK_GEN 0x0002 +#define K_RSA_PK_OP 0x0003 +#define K_RSA_SK_OP 0x0004 +#define K_DSA_SIGN 0x0005 +#define K_DSA_VERIF 0x0006 +#define K_RNG_DIRECT 0x0041 +#define K_RNG_SHA1 0x0042 +#define K_MOD_ADD 0x0043 +#define K_MOD_SUB 0x0044 +#define K_MOD_MUL 0x0045 +#define K_MOD_REDUCE 0x0046 +#define K_MOD_EXP 0x0047 +#define K_MOD_INV 0x0048 /* Not 5821 */ +#define K_MOD_2EXP 0x0049 /* Not 5820 */ + + +/* Command Context Header */ + +/* Word 0 */ + +#define S_CC_OPCODE 16 +#define M_CC_OPCODE _DD_MAKEMASK(16,S_CC_OPCODE) +#define V_CC_OPCODE(x) _DD_MAKEVALUE(x,S_CC_OPCODE) +#define G_CC_OPCODE(x) _DD_GETVALUE(x,S_CC_OPCODE,M_CC_OPCODE) + +#define S_CC_LEN 0 +#define M_CC_LEN _DD_MAKEMASK(16,S_CC_LEN) +#define V_CC_LEN(x) _DD_MAKEVALUE(x,S_CC_LEN) +#define G_CC_LEN(x) _DD_GETVALUE(x,S_CC_LEN,M_CC_LEN) + +/* Word 1 */ + +#define S_CC_FLAGS 12 +#define M_CC_FLAGS _DD_MAKEMASK(4,S_CC_FLAGS) +#define V_CC_FLAGS(x) _DD_MAKEVALUE(x,S_CC_FLAGS) +#define G_CC_FLAGS(x) _DD_GETVALUE(x,S_CC_OPCODE,M_CC_OPCODE) + +/* The remaining command context fields depend on the opcode. */ + +/* IPSEC 3DES (K_IPSEC_3DES) */ + +/* SSL MAC (K_SSL_MAC) */ +/* TLS HMAC (K_TLS_HMAC) */ +/* Pure MD5/SHA-1 Hash (K_HASH) */ + +#define K_HASH_FLAGS_MD5 1 +#define K_HASH_FLAGS_SHA1 2 + +/* SSL MAC (K_SSL_MAC) */ + +#define SSL_MAC_CMD_WORDS 22 + +/* TLS HMAC (K_TLS_HMAC) */ + +#define TLS_HMAC_CMD_WORDS 16 + +/* Pure MD5/SHA-1 Hash (K_HASH) */ + +/* SSL/TLS DES/3DES (K_SSL_3DES) */ + +/* ARCFOUR (K_ARC4) */ + +#define ARC4_STATE_WORDS (1 + 256/4) +#define ARC4_CMD_WORDS (2 + ARC4_STATE_WORDS) + +#define M_ARC4_FLAGS_KEY _DD_MAKEMASK1(10) +#define M_ARC4_FLAGS_WRITEBACK _DD_MAKEMASK1(11) +#define M_ARC4_FLAGS_NULLDATA _DD_MAKEMASK1(12) + + +/* Random number generation (K_RNG_DIRECT, K_RNG_SHA1) */ + +/* Modular arithmetic (K_MOD_ADD, K_MOD_SUB, K_MOD_MUL) */ + +/* Modular Remainder (K_MOD_REDUCE) */ + +/* Modular Exponentiation (K_MOD_EXP) */ + +/* Double Modular Exponentiation (K_MOD_2EXP) */ + + +#endif /* _BCM_5821_H_ */ diff --git a/cfe/cfe/dev/dc21143.h b/cfe/cfe/dev/dc21143.h new file mode 100644 index 0000000..65f3255 --- /dev/null +++ b/cfe/cfe/dev/dc21143.h @@ -0,0 +1,588 @@ +/* + * Register and bit definitions for the DEC/Intel 21143 Ethernet controller, + * part of the Tulip family of 10 and 10/100 controllers. + * Reference: + * 21143 PCI/CardBus 10/100 Mb/s Ethernet LAN Controller, + * Hardware Reference Manual, Revision 1.0. + * Document No. 278074-001 + * Intel Corp., October 1998 + * Includes extensions/alternatives for the DEC 21040, 21041 and 21140(A) + * Ethernet controllers. + */ +#ifndef _DC21143_H_ +#define _DC21143_H_ + +#define _DD_MAKEMASK1(n) (1 << (n)) +#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n)) +#define _DD_MAKEVALUE(v,n) ((v) << (n)) +#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n)) + + +/* ********************************************************************* + * PCI Configuration Register offsets (Tulip nomenclature) + ********************************************************************* */ + +#define R_CFG_CFID PCI_ID_REG +#define K_PCI_VENDOR_DEC 0x1011 +#define K_PCI_ID_DC21040 0x0002 +#define K_PCI_ID_DC21041 0x0014 +#define K_PCI_ID_DC21140 0x0009 +#define K_PCI_ID_DC21143 0x0019 + +#define R_CFG_CFRV PCI_CLASS_REG + +#define R_CFG_CBIO PCI_MAPREG(0) +#define R_CFG_CBMA PCI_MAPREG(1) + +#define R_CFG_CFIT PCI_BPARAM_INTERRUPT_REG + +/* Tulip extensions */ +#define R_CFG_CFDD 0x40 + +#define M_CFDD_SLEEP __DD_MAKEMASK1(31) +#define M_CFDD_SNOOZE __DD_MAKEMASK1(30) + +#define R_CFG_CPMS 0xE0 + + +/* ********************************************************************* + * CSRs: offsets + ********************************************************************* */ + +#define R_CSR_BUSMODE 0x00 +#define R_CSR_TXPOLL 0x08 +#define R_CSR_RXPOLL 0x10 +#define R_CSR_RXRING 0x18 +#define R_CSR_TXRING 0x20 +#define R_CSR_STATUS 0x28 +#define R_CSR_OPMODE 0x30 +#define R_CSR_INTMASK 0x38 +#define R_CSR_MISSEDFRAME 0x40 +#define R_CSR_ROM_MII 0x48 +#define R_CSR_BOOTROM_ADRR 0x50 +#define R_CSR_GENTIMER 0x58 + +/* The following registers are specific to the 21040 */ + +#define R_CSR_FDUPLEX 0x58 + +/* The following registers are specific to the 21040/21041 and 21142/21143 */ + +#define R_CSR_SIASTATUS 0x60 +#define R_CSR_SIAMODE0 0x68 +#define R_CSR_SIAMODE1 0x70 +#define R_CSR_SIAMODE2 0x78 + +/* The following registers are specific to the 21140/21140A */ + +#define R_CSR_GENPORT 0x60 +#define R_CSR_WATCHDOG_TIMER 0x78 + + +/* CSR0: Bus Mode register */ + +#define M_CSR0_SWRESET _DD_MAKEMASK1(0) +#define M_CSR0_BUSARB _DD_MAKEMASK1(1) + +#define S_CSR0_SKIPLEN 2 +#define M_CSR0_SKIPLEN _DD_MAKEMASK(5,S_CSR0_SKIPLEN) +#define V_CSR0_SKIPLEN(x) _DD_MAKEVALUE(x,S_CSR0_SKIPLEN) +#define G_CSR0_SKIPLEN(x) _DD_GETVALUE(x,S_CSR0_SKIPLEN,M_CSR0_SKIPLEN) + +#define M_CSR0_BIGENDIAN _DD_MAKEMASK1(7) + +#define S_CSR0_BURSTLEN 8 +#define M_CSR0_BURSTLEN _DD_MAKEMASK(6,S_CSR0_BURSTLEN) +#define V_CSR0_BURSTLEN(x) _DD_MAKEVALUE(x,S_CSR0_BURSTLEN) +#define G_CSR0_BURSTLEN(x) _DD_GETVALUE(x,S_CSR0_BURSTLEN,M_CSR0_BURSTLEN) + +#define S_CSR0_CACHEALIGN 14 +#define M_CSR0_CACHEALIGN _DD_MAKEMASK(2,S_CSR0_CACHEALIGN) +#define V_CSR0_CACHEALIGN(x) _DD_MAKEVALUE(x,S_CSR0_CACHEALIGN) +#define G_CSR0_CACHEALIGN(x) _DD_GETVALUE(x,S_CSR0_CACHEALIGN,M_CSR0_CACHEALIGN) + +#define S_CSR0_TXAUTOPOLL 17 +#define M_CSR0_TXAUTOPOLL _DD_MAKEMASK(3,S_CSR0_AUTOPOLL) +#define V_CSR0_TXAUTOPOLL(x) _DD_MAKEVALUE(x,S_CSR0_TXAUTOPOLL) +#define G_CSR0_TXAUTOPOLL(x) _DD_GETVALUE(x,S_CSR0_TXAUTOPOLL,M_CSR0_TXAUTOPOLL) + +#define M_CSR0_DESCBYTEORDER _DD_MAKEMASK1(20) /* not 21040 */ +#define M_CSR0_READMULTENAB _DD_MAKEMASK1(21) /* not 2104{0,1} */ +#define M_CSR0_READLINEENAB _DD_MAKEMASK1(23) /* not 2104{0,1} */ +#define M_CSR0_WRITEINVALENAB _DD_MAKEMASK1(24) /* not 2104{0,1} */ + +#define K_CSR0_TAPDISABLED 0x00 +#define K_CSR0_TAP200US 0x01 +#define K_CSR0_TAP800US 0x02 +#define K_CSR0_TAP1600US 0x03 + +#define K_CSR0_ALIGNNONE 0 +#define K_CSR0_ALIGN32 1 +#define K_CSR0_ALIGN64 2 +#define K_CSR0_ALIGN128 3 + +#define K_CSR0_BURST32 32 +#define K_CSR0_BURST16 16 +#define K_CSR0_BURST8 8 +#define K_CSR0_BURST4 4 +#define K_CSR0_BURST2 2 +#define K_CSR0_BURST1 1 + + +#define M_CSR3_RXDSCRADDR 0xFFFFFFFC +#define M_CSR4_TXDSCRADDR 0xFFFFFFFC + + +/* CSR5: Status register */ + +#define M_CSR5_TXINT _DD_MAKEMASK1(0) +#define M_CSR5_TXSTOP _DD_MAKEMASK1(1) +#define M_CSR5_TXBUFUNAVAIL _DD_MAKEMASK1(2) +#define M_CSR5_TXJABTIMEOUT _DD_MAKEMASK1(3) +#define M_CSR5_LINKPASS _DD_MAKEMASK1(4) /* not 21040 */ +#define M_CSR5_TXUNDERFLOW _DD_MAKEMASK1(5) +#define M_CSR5_RXINT _DD_MAKEMASK1(6) +#define M_CSR5_RXBUFUNAVAIL _DD_MAKEMASK1(7) +#define M_CSR5_RXSTOPPED _DD_MAKEMASK1(8) +#define M_CSR5_RXWDOGTIMEOUT _DD_MAKEMASK1(9) +#define M_CSR5_AUITPPIN _DD_MAKEMASK1(10) /* 21040 only */ +#define M_CSR5_TXEARLYINT _DD_MAKEMASK1(10) /* not 2104{0,1} */ +#define M_CSR5_FDSHORTFRAME _DD_MAKEMASK1(11) /* 21040 only */ +#define M_CSR5_GPTIMEREXPIRE _DD_MAKEMASK1(11) /* not 21040 */ +#define M_CSR5_LINKFAIL _DD_MAKEMASK1(12) +#define M_CSR5_FATALBUSERROR _DD_MAKEMASK1(13) +#define M_CSR5_RXEARLYINT _DD_MAKEMASK1(14) /* not 21040 */ +#define M_CSR5_ABNORMALINT _DD_MAKEMASK1(15) +#define M_CSR5_NORMALINT _DD_MAKEMASK1(16) + +#define S_CSR5_RXPROCSTATE 17 +#define M_CSR5_RXPROCSTATE _DD_MAKEMASK(3,S_CSR5_RXPROCSTATE) +#define V_CSR5_RXPROCSTATE(x) _DD_MAKEVALUE(x,S_CSR5_RXPROCSTATE) +#define G_CSR5_RXPROCSTATE(x) _DD_GETVALUE(x,S_CSR5_RXPROCSTATE,M_CSR5_RXPROCSTATE) + +#define K_CSR5_RXSTOPPED 0x00 /* RESET or STOP command */ +#define K_CSR5_RXFETCH 0x01 /* fetching rx desc */ +#define K_CSR5_RXCHECK 0x02 /* checking end of rx pkt */ +#define K_CSR5_RXWAIT 0x03 /* waiting for rx pkt */ +#define K_CSR5_RXSUSPEND 0x04 /* unavailable rx buffer */ +#define K_CSR5_RXCLOSE 0x05 /* closing rx desc */ +#define K_CSR5_RXFLUSH 0x06 /* flushing rx frame */ +#define K_CSR5_RXQUEUE 0x07 /* reading rx frame from FIFO */ + +#define S_CSR5_TXPROCSTATE 20 +#define M_CSR5_TXPROCSTATE _DD_MAKEMASK(3,S_CSR5_TXPROCSTATE) +#define V_CSR5_TXPROCSTATE(x) _DD_MAKEVALUE(x,S_CSR5_TXPROCSTATE) +#define G_CSR5_TXPROCSTATE(x) _DD_GETVALUE(x,S_CSR5_TXPROCSTATE,M_CSR5_TXPROCSTATE) + +#define K_CSR5_TXSTOPPED 0x00 /* RESET or STOP command */ +#define K_CSR5_TXFETCH 0x01 /* fetching tx desc */ +#define K_CSR5_TXWAIT 0x02 /* waiting for end of tx */ +#define K_CSR5_TXREAD 0x03 /* reading buffer into FIFO */ +#define K_CSR5_TXSETUP 0x05 /* setup packet */ +#define K_CSR5_TXSUSPEND 0x06 /* tx underflow or no tx desc */ +#define K_CSR5_TXCLOSE 0x07 /* closing tx desc */ + +#define S_CSR5_ERRORBITS 23 +#define M_CSR5_ERRORBITS _DD_MAKEMASK(3,S_CSR5_ERRORBITS) +#define V_CSR5_ERRORBITS(x) _DD_MAKEVALUE(x,S_CSR5_ERRORBITS) +#define G_CSR5_ERRORBITS(x) _DD_GETVALUE(x,S_CSR5_ERRORBITS,M_CSR5_ERRORBITS) + +#define K_CSR5_FBE_PARITY 0x00 +#define K_CSR5_FBE_MABORT 0x01 +#define K_CSR5_FBE_TABORT 0x02 + +#define M_CSR5_GPPORTINT _DD_MAKEMASK1(26) /* not 2104{0,1} */ +#define M_CSR5_LINKCHANGED _DD_MAKEMASK1(27) /* not 2104{0,1} */ + + +/* CSR6: Operating Mode register */ + +#define M_CSR6_RXHASHFILT _DD_MAKEMASK1(0) +#define M_CSR6_RXSTART _DD_MAKEMASK1(1) +#define M_CSR6_HASHONLY _DD_MAKEMASK1(2) +#define M_CSR6_PASSBADFRAMES _DD_MAKEMASK1(3) +#define M_CSR6_INVERSEFILT _DD_MAKEMASK1(4) +#define M_CSR6_STOPBACKOFF _DD_MAKEMASK1(5) +#define M_CSR6_PROMISCUOUS _DD_MAKEMASK1(6) +#define M_CSR6_PASSALLMULTI _DD_MAKEMASK1(7) +#define M_CSR6_FULLDUPLEX _DD_MAKEMASK1(9) + +#define M_CSR6_INTLOOPBACK _DD_MAKEMASK1(10) +#define M_CSR6_EXTLOOPBACK _DD_MAKEMASK1(11) + +#define S_CSR6_OPMODE 10 +#define M_CSR6_OPMODE _DD_MAKEMASK(2,S_CSR6_OPMODE) +#define V_CSR6_OPMODE(x) _DD_MAKEVALUE(x,S_CSR6_OPMODE) +#define G_CSR6_OPMODE(x) _DD_GETVALUE(x,S_CSR6_OPMODE,M_CSR6_OPMODE) + +#define M_CSR6_FORCECOLL _DD_MAKEMASK1(12) +#define M_CSR6_TXSTART _DD_MAKEMASK1(13) + +#define S_CSR6_THRESHCONTROL 14 +#define M_CSR6_THRESHCONTROL _DD_MAKEMASK(2,S_CSR6_THRESHCONTROL) +#define V_CSR6_THRESHCONTROL(x) _DD_MAKEVALUE(x,S_CSR6_THRESHCONTROL) +#define G_CSR6_THRESHCONTROL(x) _DD_GETVALUE(x,S_CSR6_THRESHCONTROL,M_CSR6_THRESHCONTROL) + +#define M_CSR6_BACKPRESSURE _DD_MAKEMASK1(16) /* 21040 only */ +#define M_CSR6_CAPTUREEFFECT _DD_MAKEMASK1(17) + +#define M_CSR6_PORTSEL _DD_MAKEMASK1(18) /* not 2104{0,1} */ +#define M_CSR6_HBDISABLE _DD_MAKEMASK1(19) /* not 2104{0,1} */ +#define M_CSR6_STOREFWD _DD_MAKEMASK1(21) /* not 2104{0,1} */ +#define M_CSR6_TXTHRESH _DD_MAKEMASK1(22) /* not 2104{0,1} */ +#define M_CSR6_PCSFUNC _DD_MAKEMASK1(23) /* not 2104{0,1} */ +#define M_CSR6_SCRAMMODE _DD_MAKEMASK1(24) /* not 2104{0,1} */ +#define M_CSR6_MBO _DD_MAKEMASK1(25) /* not 2104{0,1} */ +#define M_CSR6_RXALL _DD_MAKEMASK1(30) /* not 2104{0,1} */ + +#define M_CSR6_SPECCAP _DD_MAKEMASK1(31) /* not 21040 */ + +#define K_CSR6_TXTHRES_128_72 0x00 +#define K_CSR6_TXTHRES_256_96 0x01 +#define K_CSR6_TXTHRES_512_128 0x02 +#define K_CSR6_TXTHRES_1024_160 0x03 + + +#define M_CSR6_SPEED_10 (M_CSR6_TXTHRESH) + +#define M_CSR6_SPEED_100 (M_CSR6_HBDISABLE | \ + M_CSR6_SCRAMMODE | \ + M_CSR6_PCSFUNC | \ + M_CSR6_PORTSEL) + +#define M_CSR6_SPEED_10_MII (M_CSR6_TXTHRESH | \ + M_CSR6_PORTSEL) + +#define M_CSR6_SPEED_100_MII (M_CSR6_HBDISABLE | \ + M_CSR6_PORTSEL) + + +/* CSR7: Interrupt mask register */ + +#define M_CSR7_TXINT _DD_MAKEMASK1(0) +#define M_CSR7_TXSTOP _DD_MAKEMASK1(1) +#define M_CSR7_TXBUFUNAVAIL _DD_MAKEMASK1(2) +#define M_CSR7_TXJABTIMEOUT _DD_MAKEMASK1(3) +#define M_CSR7_LINKPASS _DD_MAKEMASK1(4) /* not 21040 */ +#define M_CSR7_TXUNDERFLOW _DD_MAKEMASK1(5) +#define M_CSR7_RXINT _DD_MAKEMASK1(6) +#define M_CSR7_RXBUFUNAVAIL _DD_MAKEMASK1(7) +#define M_CSR7_RXSTOPPED _DD_MAKEMASK1(8) +#define M_CSR7_RXWDOGTIMEOUT _DD_MAKEMASK1(9) +#define M_CSR7_AUITPSW _DD_MAKEMASK1(10) /* 21040 only */ +#define M_CSR7_TXEARLY _DD_MAKEMASK1(10) /* not 2104{0,1} */ +#define M_CSR7_FD _DD_MAKEMASK1(11) /* 21040 only */ +#define M_CSR7_GPTIMER _DD_MAKEMASK1(11) /* not 21040 */ +#define M_CSR7_LINKFAIL _DD_MAKEMASK1(12) +#define M_CSR7_FATALBUSERROR _DD_MAKEMASK1(13) +#define M_CSR7_RXEARLY _DD_MAKEMASK1(14) /* not 21040 */ +#define M_CSR7_ABNORMALINT _DD_MAKEMASK1(15) +#define M_CSR7_NORMALINT _DD_MAKEMASK1(16) +#define M_CSR7_GPPORT _DD_MAKEMASK1(26) /* not 2104{0,1} */ +#define M_CSR7_LINKCHANGED _DD_MAKEMASK1(27) /* not 2104{0,1} */ + + +/* CSR8: Missed Frame register */ + +#define M_CSR8_RXOVER_WRAP _DD_MAKEMASK1(28) /* not 2104{0,1} */ +#define S_CSR8_RXOVER 17 +#define M_CSR8_RXOVER _DD_MAKEMASK(11,S_CSR8_RXOVER) /* not 2104{0,1} */ +#define V_CSR8_RXOVER(x) _DD_MAKEVALUE(x,S_CSR8_RXOVER) +#define G_CSR8_RXOVER(x) _DD_GETVALUE(x,S_CSR8_RXOVER,M_CSR8_RXOVER) + +#define M_CSR8_MISSEDWRAP _DD_MAKEMASK1(16) +#define S_CSR8_MISSED 0 +#define M_CSR8_MISSED _DD_MAKEMASK(16,S_CSR8_MISSED) +#define V_CSR8_MISSED(x) _DD_MAKEVALUE(x,S_CSR8_MISSED) +#define G_CSR8_MISSED(x) _DD_GETVALUE(x,S_CSR8_MISSED,M_CSR8_MISSED) + + +/* CSR9: ROM and MII register */ + +#define S_CSR9_ROMDATA 0 +#define M_CSR9_ROMDATA _DD_MAKEMASK(8,S_CSR9_ROMDATA) +#define V_CSR9_ROMDATA(x) _DD_MAKEVALUE(x,S_CSR9_ROMDATA) +#define G_CSR9_ROMDATA(x) _DD_GETVALUE(x,S_CSR9_ROMDATA,M_CSR9_ROMDATA) + +#define M_CSR9_SROMCHIPSEL _DD_MAKEMASK1(0) /* not 21040 */ +#define M_CSR9_SROMCLOCK _DD_MAKEMASK1(1) /* not 21040 */ +#define M_CSR9_SROMDATAIN _DD_MAKEMASK1(2) /* not 21040 */ +#define M_CSR9_SROMDATAOUT _DD_MAKEMASK1(3) /* not 21040 */ + +#define M_CSR9_REGSELECT _DD_MAKEMASK1(10) /* not 21040 */ +#define M_CSR9_SERROMSEL _DD_MAKEMASK1(11) /* not 21040 */ +#define M_CSR9_ROMSEL _DD_MAKEMASK1(12) /* not 21040 */ +#define M_CSR9_ROMWRITE _DD_MAKEMASK1(13) /* not 21040 */ +#define M_CSR9_ROMREAD _DD_MAKEMASK1(14) /* not 21040 */ +#define M_CSR9_MODESEL _DD_MAKEMASK1(15) /* 21041 only */ +#define M_CSR9_MDC _DD_MAKEMASK1(16) /* not 2104{0,1} */ +#define M_CSR9_MDO _DD_MAKEMASK1(17) /* not 2104{0,1} */ +#define M_CSR9_MIIMODE _DD_MAKEMASK1(18) /* not 2104{0,1} */ +#define M_CSR9_MDI _DD_MAKEMASK1(19) /* not 2104{0,1} */ + +#define M_CSR9_DATANOTVALID _DD_MAKEMASK1(31) /* 21040 only */ + +#define M_CSR10_BOOTROMADDR _DD_MAKEMASK(18,0) /* not 21040 */ + + +/* CSR11 General Purpose Timer register */ + +#define S_CSR11_GPTIMER 0 /* not 21040 */ +#define M_CSR11_GPTIMER _DD_MAKEMASK(16,S_CSR11_GPTIMER) +#define V_CSR11_GPTIMER(x) _DD_MAKEVALUE(x,S_CSR11_GPTIMER) +#define G_CSR11_GPTIMER(x) _DD_GETVALUE(x,S_CSR11_GPTIMER,M_CSR11_GPTIMER) + + +#define M_CSR11_GPTIMERCONT _DD_MAKEMASK1(16) /* not 21040 */ + +#define S_CSR11_FDAUTOCONF 0 /* 21040 only */ +#define M_CSR11_FDAUTOCONF _DD_MAKEMASK(16,S_CSR11_FDAUTOCONF) +#define V_CSR11_FDAUTOCONF(x) _DD_MAKEVALUE(x,S_CSR11_FDAUTOCONF) +#define G_CSR11_FRAUTOCONF(x) _DD_GETVALUE(x,S_CSR11_FDAUTOCONF,M_CSR11_AUTOCONF) + + +/* CSR12: SIA Status register (21143) */ + +#define M_CSR12_MIIRPA _DD_MAKEMASK1(0) +#define M_CSR12_100MBLINK _DD_MAKEMASK1(1) +#define M_CSR12_10MBLINK _DD_MAKEMASK1(2) +#define M_CSR12_AUTOPOLSTATE _DD_MAKEMASK1(3) + +#define M_CSR12_RXAUIACT _DD_MAKEMASK1(8) +#define M_CSR12_RX10BASETACT _DD_MAKEMASK1(9) +#define M_CSR12_NLPDETECT _DD_MAKEMASK1(10) +#define M_CSR12_TXREMFAULT _DD_MAKEMASK1(11) + +#define S_CSR12_AUTONEGARBIT 12 +#define M_CSR12_AUTONEGARBIT _DD_MAKEMASK(3,S_CSR12_AUTONEGARBIT) +#define V_CSR12_AUTONEGARBIT(x) _DD_MAKEVALUE(x,S_CSR12_AUTONEGARBIT) +#define G_CSR12_AUTONEGARBIT(x) _DD_GETVALUE(x,S_CSR12_AUTONEGARBIT,M_CSR12_AUTONEGARBIT) + +#define M_CSR12_LINKPARTNEG _DD_MAKEMASK1(15) + +#define S_CSR12_LINKPARTCODE 16 +#define M_CSR12_LINKPARTCODE _DD_MAKEMASK(16,S_CSR12_LINKPARTCODE) +#define V_CSR12_LINKPARTCODE(x) _DD_MAKEVALUE(x,S_CSR12_LINKPARTCODE) +#define G_CSR12_LINKPARTCODE(x) _DD_GETVALUE(x,S_CSR12_LINKPARTCODE,M_CSR12_LINKPARTCODE) + + +/* CSR12: SIA Status register (21041, also 31:12, 3:3 as for 21143) */ + +#define M_CSR12_NETCONNERR _DD_MAKEMASK1(1) +#define M_CSR12_LINKFAIL _DD_MAKEMASK1(2) +#define M_CSR12_SELPORTACT _DD_MAKEMASK1(8) +#define M_CSR12_NONSELPORTACT _DD_MAKEMASK1(9) +#define M_CSR12_AUTONEGRESTART _DD_MAKEMASK1(10) +#define M_CSR12_UNSTABLENLP _DD_MAKEMASK1(11) + + +/* CSR12: General Purpose Port register (21140) */ + +#define S_CSR12_DATA 0 +#define M_CSR12_DATA _DD_MAKEMASK(8,S_CSR12_DATA) +#define V_CSR12_DATA _DD_MAKEVALUE(x,S_CSR12_DATA,M_CSR12_DATA) +#define G_CSR12_DATA(x) _DD_GETVALUE(x,S_CSR12_DATA,M_CSR12_DATA) + +#define M_CSR12_CONTROL _DD_MAKEMASK1(8) + + +/* CSR13: SIA Mode 0 register (21143 and 21041) */ + +#define M_CSR13_CONN_NOT_RESET _DD_MAKEMASK1(0) +#define M_CSR13_CONN_CSR_AUTO _DD_MAKEMAKS1(2) /* 21041 only */ +#define M_CSR13_CONN_AUI_10BT _DD_MAKEMASK1(3) + + +/* CSR14: SIA Mode 1 register (21143 and 21041) */ + +#define M_CSR14_ENCODER _DD_MAKEMASK1(0) +#define M_CSR14_LOOPBACK _DD_MAKEMASK1(1) +#define M_CSR14_DRIVER _DD_MAKEMASK1(2) +#define M_CSR14_LINKPULSE _DD_MAKEMASK1(3) + +#define S_CSR14_COMPENSATE 4 +#define M_CSR14_COMPENSATE _DD_MAKEMASK(2,S_CSR14_COMPENSATE) +#define V_CSR15_COMPENSATE(x) _DD_MAKEVALUE(x,S_CSR15_COMPENSATE) +#define G_CSR15_COMPENSATE(x) _DD_GETVALUE(x,S_CSR15_COMPENSATE,M_CSR15_COMPENSATE) + +#define M_CSR14_HALFDUPLEX10BASET _DD_MAKEMASK1(6) +#define M_CSR14_AUTONEGOTIATE _DD_MAKEMASK1(7) +#define M_CSR14_RXSQUELCH _DD_MAKEMASK1(8) +#define M_CSR14_COLLSQUELCH _DD_MAKEMASK1(9) +#define M_CSR14_COLLDETECT _DD_MAKEMASK1(10) +#define M_CSR14_SIGQUALGEN _DD_MAKEMASK1(11) +#define M_CSR14_LINKTEST _DD_MAKEMASK1(12) +#define M_CSR14_AUTOPOLARITY _DD_MAKEMASK1(13) +#define M_CSR14_SETPOLARITY _DD_MAKEMASK1(14) +#define M_CSR14_10BASETAUIAUTO _DD_MAKEMASK1(15) +#define M_CSR14_100BASETHALFDUP _DD_MAKEMASK1(16) /* not 21041 */ +#define M_CSR14_100BASETFULLDUP _DD_MAKEMASK1(17) /* not 21041 */ +#define M_CSR14_100BASET4 _DD_MAKEMASK1(18) /* not 21041 */ + +#define M_CSR14_10BT_HD 0x7F3F +#define M_CSR14_10BT_FD 0x7F3D + + +/* CSR15: SIA Mode 2 register (21143 and 21041) */ + +#define M_CSR15_GP_JABBERDIS _DD_MAKEMASK1(0) /* 21041 only */ +#define M_CSR15_GP_HOSTUNJAB _DD_MAKEMASK1(1) +#define M_CSR15_GP_JABBERCLK _DD_MAKEMASK1(2) +#define M_CSR15_GP_AUIBNC _DD_MAKEMASK1(3) +#define M_CSR15_GP_RXWATCHDIS _DD_MAKEMASK1(4) +#define M_CSR15_GP_RXWATCHREL _DD_MAKEMASK1(5) + +/* (CSR15: 21143 only) */ + +#define S_CSR15_GP_GPDATA 16 +#define M_CSR15_GP_GPDATA _DD_MAKEMASK(4,S_CSR15_GP_GPDATA) +#define V_CSR15_GP_GPDATA(x) _DD_MAKEVALUE(x,S_CSR15_GP_GPDATA) +#define G_CSR15_GP_GPDATA(x) _DD_GETVALUE(x,S_CSR15_GP_GPDATA,M_CSR15_GP_GPDATA) + +#define M_CSR15_GP_LED0 _DD_MAKEMASK1(20) +#define M_CSR15_GP_LED1 _DD_MAKEMASK1(21) +#define M_CSR15_GP_LED2 _DD_MAKEMASK1(22) +#define M_CSR15_GP_LED3 _DD_MAKEMASK1(23) +#define M_CSR15_GP_INTPORT0 _DD_MAKEMASK1(24) +#define M_CSR15_GP_INTPORT1 _DD_MAKEMASK1(25) +#define M_CSR15_GP_RXMATCH _DD_MAKEMASK1(26) +#define M_CSR15_GP_CONTROLWRITE _DD_MAKEMASK1(27) +#define M_CSR15_GP_GPINT0 _DD_MAKEMASK1(28) +#define M_CSR15_GP_GPINT1 _DD_MAKEMASK1(29) +#define M_CSR15_GP_RXMATCHINT _DD_MAKEMASK1(30) + +#define M_CSR15_DEFAULT_VALUE 0x00050008 +#define M_CSR15_CONFIG_GEPS_LEDS 0x08af0000 + +/* (CSR15: 21041 only) */ + +#define M_CSR15_GP_LED1ENB _DD_MAKEMASK1(6) +#define M_CSR15_GP_LED1VALUE _DD_MAKEMASK1(7) +#define M_CSR15_GP_TSTCLK _DD_MAKEMASK1(8) +#define M_CSR15_GP_FORCEUNSQ _DD_MAKEMASK1(9) +#define M_CSR15_GP_FORCEFAIL _DD_MAKEMASK1(10) +#define M_CSR15_GP_LEDSTRDIS _DD_MAKEMASK1(11) +#define M_CSR15_GP_PLLTEST _DD_MAKEMASK1(12) +#define M_CSR15_GP_FORCERXLOW _DD_MAKEMASK1(13) +#define M_CSR15_GP_LED2ENB _DD_MAKEMASK1(14) +#define M_CSR15_GP_LED2VALUE _DD_MAKEMASK1(15) + + +/* CSR15: Watchdog Timer register (21140) */ + +#define M_CSR15_WT_JABBER _DD_MAKEMASK1(0) +#define M_CSR15_WT_HOSTUNJAB _DD_MAKEMASK1(1) +#define M_CSR15_WT_JABBERCLK _DD_MAKEMASK1(2) +#define M_CSR15_WT_RXWATCHDIS _DD_MAKEMASK1(4) +#define M_CSR15_WT_RXWATCHREL _DD_MAKEMASK1(5) + + +/* ********************************************************************* + * Receive Descriptors + ********************************************************************* */ + +#define M_RDES0_OWNSYS 0 +#define M_RDES0_OWNADAP _DD_MAKEMASK1(31) + +#define S_RDES0_FRAMELEN 16 +#define M_RDES0_FRAMELEN _DD_MAKEMASK(14,S_RDES0_FRAMELEN) +#define V_RDES0_FRAMELEN(x) _DD_MAKEVALUE(x,S_RDES0_FRAMELEN) +#define G_RDES0_FRAMELEN(x) _DD_GETVALUE(x,S_RDES0_FRAMELEN,M_RDES0_FRAMELEN) + +#define M_RDES0_ZERO _DD_MAKEMASK1(0) +#define M_RDES0_OVFL _DD_MAKEMAKS1(0) /* 21041 only */ +#define M_RDES0_CRCERR _DD_MAKEMASK1(1) +#define M_RDES0_DRIBBLE _DD_MAKEMASK1(2) +#define M_RDES0_MIIERROR _DD_MAKEMASK1(3) /* not 21041 */ +#define M_RDES0_WDOGTIMER _DD_MAKEMASK1(4) +#define M_RDES0_FRAMETYPE _DD_MAKEMASK1(5) +#define M_RDES0_COLLSEEN _DD_MAKEMASK1(6) +#define M_RDES0_FRAMETOOLONG _DD_MAKEMASK1(7) +#define M_RDES0_LASTDES _DD_MAKEMASK1(8) +#define M_RDES0_FIRSTDES _DD_MAKEMASK1(9) +#define M_RDES0_MCASTFRAME _DD_MAKEMASK1(10) +#define M_RDES0_RUNTFRAME _DD_MAKEMASK1(11) + +#define S_RDES0_DATATYPE 12 +#define M_RDES0_DATATYPE _DD_MAKEMASK(2,S_RDES0_DATATYPE) +#define V_RDES0_DATATYPE(x) _DD_MAKEVALUE(x,S_RDES0_DATATYPE) +#define G_RDES0_DATATYPE(x) _DD_GETVALUE(x,S_RDES0_DATATYPE,M_RDES0_DATATYPE) + +#define M_RDES0_ERROR _DD_MAKEMASK1(14) +#define M_RDES0_ERRORSUM _DD_MAKEMASK1(15) +#define M_RDES0_FILTFAIL _DD_MAKEMASK1(30) /* not 21041 */ + +#define S_RDES1_BUF1SIZE 0 +#define M_RDES1_BUF1SIZE _DD_MAKEMASK(11,S_TDES1_BUF1SIZE) +#define V_RDES1_BUF1SIZE(x) _DD_MAKEVALUE(x,S_RDES1_BUF1SIZE) +#define G_RDES1_BUF1SIZE(x) _DD_GETVALUE(x,S_RDES1_BUF1SIZE,M_RDES1_BUF1SIZE) + +#define S_RDES1_BUF2SIZE 11 +#define M_RDES1_BUF2SIZE _DD_MAKEMASK(11,S_TDES2_BUF2SIZE) +#define V_RDES1_BUF2SIZE(x) _DD_MAKEVALUE(x,S_RDES1_BUF2SIZE) +#define G_RDES1_BUF2SIZE(x) _DD_GETVALUE(x,S_RDES1_BUF2SIZE,M_RDES1_BUF2SIZE) + +#define M_RDES1_CHAINED _DD_MAKEMASK1(24) +#define M_RDES1_ENDOFRING _DD_MAKEMASK1(25) + +#define M_RDES2_BUFADDR 0xFFFFFFFF +#define M_RDES3_BUFADDR 0xFFFFFFFF + +/* ********************************************************************* + * Transmit Descriptors + ********************************************************************* */ + +#define M_TDES0_OWNSYS 0 +#define M_TDES0_OWNADAP _DD_MAKEMASK1(31) + +#define M_TDES0_DEFERRED _DD_MAKEMASK1(0) +#define M_TDES0_UNDERFLOW _DD_MAKEMASK1(1) +#define M_TDES0_LINK_FAIL _DD_MAKEMASK1(2) + +#define S_TDES0_COLLCOUNT 3 +#define M_TDES0_COLLCOUNT _DD_MAKEMASK(4,S_TDES0_COLLCOUNT) +#define V_TDES0_COLLCOUNT(x) _DD_MAKEVALUE(x,S_TDES0_COLLCOUNT) +#define G_TDES0_COLLCOUNT(x) _DD_GETVALUE(x,S_TDES0_COLLCOUNT,M_TDES0_COLLCOUNT) + +#define M_TDES0_HEARTBEAT_FAIL _DD_MAKEMASK1(7) +#define M_TDES0_EXCESSIVE_COLLISIONS _DD_MAKEMASK1(8) +#define M_TDES0_LATE_COLLISION _DD_MAKEMASK1(9) +#define M_TDES0_NO_CARRIER _DD_MAKEMASK1(10) +#define M_TDES0_LOSS_OF_CARRIER _DD_MAKEMASK1(11) +#define M_TDES0_TX_JABBER_TIMEOUT _DD_MAKEMASK1(14) +#define M_TDES0_ERROR_SUMMARY _DD_MAKEMASK1(15) +#define M_TDES0_OWN_BIT _DD_MAKEMASK1(31) + +#define S_TDES1_BUF1SIZE 0 +#define M_TDES1_BUF1SIZE _DD_MAKEMASK(11,S_TDES1_BUF1SIZE) +#define V_TDES1_BUF1SIZE(x) _DD_MAKEVALUE(x,S_TDES1_BUF1SIZE) +#define G_TDES1_BUF1SIZE(x) _DD_GETVALUE(x,S_TDES1_BUF1SIZE,M_TDES1_BUF1SIZE) + +#define S_TDES1_BUF2SIZE 11 +#define M_TDES1_BUF2SIZE _DD_MAKEMASK(11,S_TDES2_BUF2SIZE) +#define V_TDES1_BUF2SIZE(x) _DD_MAKEVALUE(x,S_TDES1_BUF2SIZE) +#define G_TDES1_BUF2SIZE(x) _DD_GETVALUE(x,S_TDES1_BUF2SIZE,M_TDES1_BUF2SIZE) + +#define M_TDES1_FT0 _DD_MAKEMASK1(22) +#define M_TDES1_NOPADDING _DD_MAKEMASK1(23) +#define M_TDES1_CHAINED _DD_MAKEMASK1(24) +#define M_TDES1_ENDOFRING _DD_MAKEMASK1(25) +#define M_TDES1_NOADDCRC _DD_MAKEMASK1(26) +#define M_TDES1_SETUP _DD_MAKEMASK1(27) +#define M_TDES1_FT1 _DD_MAKEMASK1(28) +#define M_TDES1_FIRSTSEG _DD_MAKEMASK1(29) +#define M_TDES1_LASTSEG _DD_MAKEMASK1(30) +#define M_TDES1_INTERRUPT _DD_MAKEMASK1(31) + +#define M_TDES2_BUFADDR 0xFFFFFFFF +#define M_TDES3_BUFADDR 0xFFFFFFFF + + +/* CAM */ + +#define CAM_HASH_THRESHOLD 14 +#define CAM_PERFECT_ENTRIES 16 + +#define CAM_SETUP_BUFFER_SIZE 192 + +#endif /* _DC21143_H_ */ diff --git a/cfe/cfe/dev/dev_atapi.c b/cfe/cfe/dev/dev_atapi.c new file mode 100644 index 0000000..b5f4d9a --- /dev/null +++ b/cfe/cfe/dev/dev_atapi.c @@ -0,0 +1,222 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * ATAPI device driver File: dev_atapi.c + * + * This is a simple driver for ATAPI devices. The disks + * are expected to be connected to the generic bus (this + * driver doesn't support PCI). + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_timer.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" + +#include "dev_ide_common.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define GETWORD_LE(buf,wordidx) (((unsigned int) (buf)[(wordidx)*2]) + \ + (((unsigned int) (buf)[(wordidx)*2+1]) << 8)) + + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + +extern void _wbflush(void); +static void atapidrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +const static cfe_devdisp_t atapidrv_dispatch = { + idecommon_open, + idecommon_read, + idecommon_inpstat, + idecommon_write, + idecommon_ioctl, + idecommon_close, + NULL, + NULL +}; + +const cfe_driver_t atapidrv = { + "ATAPI device", + "atapi", + CFE_DEV_DISK, + &atapidrv_dispatch, + atapidrv_probe +}; + + + +/* ********************************************************************* + * Port I/O routines + * + * These routines are called back from the common code to do + * I/O cycles to the IDE disk. We provide routines for + * reading and writing bytes, words, and strings of words. + ********************************************************************* */ + +static uint8_t atapidrv_inb(idecommon_dispatch_t *disp,uint32_t reg) +{ + return *((volatile uint8_t *) PHYS_TO_K1(reg+disp->baseaddr)); +} + +static uint16_t atapidrv_inw(idecommon_dispatch_t *disp,uint32_t reg) +{ + return *((volatile uint16_t *) PHYS_TO_K1((reg+disp->baseaddr))); +} + +static void atapidrv_ins(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len) +{ + uint16_t data; + + while (len > 0) { + data = *((volatile uint16_t *) PHYS_TO_K1(reg+disp->baseaddr)); + +#ifdef _BYTESWAP_ + *buf++ = (data >> 8) & 0xFF; + *buf++ = (data & 0xFF); +#else + *buf++ = (data & 0xFF); + *buf++ = (data >> 8) & 0xFF; +#endif + len--; + len--; + } + +} + +static void atapidrv_outb(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val) +{ + *((volatile uint8_t *) PHYS_TO_K1(reg+disp->baseaddr)) = val; + _wbflush(); +} + +static void atapidrv_outw(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val) +{ + *((volatile uint16_t *) PHYS_TO_K1(reg+disp->baseaddr)) = val; + _wbflush(); +} + +static void atapidrv_outs(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len) +{ + uint16_t data; + + while (len > 0) { +#ifdef _BYTESWAP_ + data = (uint16_t) buf[1] + ((uint16_t) buf[0] << 8); +#else + data = (uint16_t) buf[0] + ((uint16_t) buf[1] << 8); +#endif + + *((volatile uint16_t *) PHYS_TO_K1(reg+disp->baseaddr)) = data; + _wbflush(); + + buf++; + buf++; + len--; + len--; + } +} + + + +static void atapidrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + idecommon_t *softc; + idecommon_dispatch_t *disp; + char descr[80]; + char unitstr[50]; + int res; + + /* + * probe_a is the IDE base address + * probe_b is the unit number and other flags + * probe_ptr is unused. + */ + + softc = (idecommon_t *) KMALLOC(sizeof(idecommon_t),0); + disp = (idecommon_dispatch_t *) KMALLOC(sizeof(idecommon_dispatch_t),0); + + if (softc && disp) { + softc->idecommon_addr = probe_a; + softc->idecommon_unit = probe_b; + + disp->ref = softc; + disp->baseaddr = softc->idecommon_addr; + softc->idecommon_dispatch = disp; + + disp->outb = atapidrv_outb; + disp->outw = atapidrv_outw; + disp->outs = atapidrv_outs; + + disp->inb = atapidrv_inb; + disp->inw = atapidrv_inw; + disp->ins = atapidrv_ins; + + res = idecommon_devprobe(softc); + if (res < 0) { + KFREE(softc); + KFREE(disp); + return; + } + + xsprintf(descr,"%s unit %d at %08X",drv->drv_description,probe_b,probe_a); + xsprintf(unitstr,"%d",probe_b); + cfe_attach(drv,softc,unitstr,descr); + } +} + + diff --git a/cfe/cfe/dev/dev_bcm1250.c b/cfe/cfe/dev/dev_bcm1250.c new file mode 100644 index 0000000..8343a46 --- /dev/null +++ b/cfe/cfe/dev/dev_bcm1250.c @@ -0,0 +1,275 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * BCM1250 (BCM1250 as PCI device) driver File: dev_bcm1250.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" + +#ifndef _SB_MAKE64 +#define _SB_MAKE64(x) ((uint64_t)(x)) +#endif +#ifndef _SB_MAKEMASK1 +#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n)) +#endif + +#include "lib_types.h" +#include "lib_hssubr.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_error.h" +#include "cfe_device.h" + +#include "pcivar.h" +#include "pcireg.h" + +#include "bsp_config.h" + +/* Note that PHYSADDR only works with 32-bit addresses */ +#define PHYSADDR(x) (K0_TO_PHYS((uint32_t)(uintptr_t)(x))) + + +static void bcm1250_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +static int bcm1250_open(cfe_devctx_t *ctx); +static int bcm1250_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm1250_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int bcm1250_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm1250_close(cfe_devctx_t *ctx); + +const static cfe_devdisp_t bcm1250_dispatch = { + bcm1250_open, + bcm1250_read, + bcm1250_inpstat, + bcm1250_write, + bcm1250_ioctl, + bcm1250_close, + NULL, + NULL +}; + +const cfe_driver_t bcm1250drv = { + "BCM1250", + "widget", + CFE_DEV_OTHER, + &bcm1250_dispatch, + bcm1250_probe +}; + + +typedef struct bcm1250_s { + uint64_t mailbox; + uint64_t mem_base; + uint8_t irq; /* interrupt mapping */ + pcitag_t tag; /* tag for configuration register */ + + int downloaded; /* code has already been downloaded. */ +} bcm1250_t; + + +/* + * BCM1250_PROBE + * probe_a, probe_b and probe_ptr all unused + */ + +static void +bcm1250_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + int index; + + index = 0; + for (;;) { + pcitag_t tag; + + if (pci_find_device(0x166d, 0x0001, index, &tag) != 0) + break; + + if (tag != 0x00000000) { /* don't configure ourselves */ + bcm1250_t *softc; + char descr[80]; + phys_addr_t pa; + + softc = (bcm1250_t *) KMALLOC(sizeof(bcm1250_t), 0); + if (softc == NULL) { + xprintf("BCM1250: No memory to complete probe\n"); + break; + } + + softc->tag = tag; + + pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BYTES, &pa); + xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)pa); + softc->mem_base = PHYS_TO_XKSEG_UNCACHED(pa); + + /* Map the CPU0 mailbox registers of the device 1250. + Note that our BAR2 space maps to its "alias" mailbox + registers. Set bit 3 for mbox_set; clear bit 3 for + reading. Address bits 15-4 are don't cares. */ + pci_map_mem(tag, PCI_MAPREG(2), PCI_MATCH_BYTES, &pa); + softc->mailbox = PHYS_TO_XKSEG_UNCACHED(pa); + + softc->downloaded = 0; + + cfe_attach(drv, softc, NULL, descr); + } + index++; + } +} + + +#include "elf.h" + +static int +elf_header (const uint8_t *hdr) +{ + return (hdr[EI_MAG0] == ELFMAG0 && + hdr[EI_MAG1] == ELFMAG1 && + hdr[EI_MAG2] == ELFMAG2 && + hdr[EI_MAG3] == ELFMAG3); +} + + +#include "cfe_timer.h" + +typedef struct { + uint32_t addr; /* source address, in device's PCI space */ + uint32_t len; /* length of this chunk */ +} chunk_desc; + + +#define MBOX_SET_BIT 0x8 + +extern void download_start(void), download_end(void); + +static int +bcm1250_open(cfe_devctx_t *ctx) +{ + bcm1250_t *softc = ctx->dev_softc; + uint64_t cmd_p = softc->mailbox + 4; + + if (softc->downloaded) { + xprintf("bcm1250_open: Warning: Device previously downloaded\n"); + softc->downloaded = 0; + } + + if (hs_read32(cmd_p) != 0) { + xprintf("bcm1250_open: Device not in initial state\n"); + return -1; + } + + return 0; +} + +static int +bcm1250_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + return -1; +} + +static int +bcm1250_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + return -1; +} + +static int +bcm1250_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + bcm1250_t *softc = ctx->dev_softc; + uint64_t arg_p = softc->mailbox + 0; + uint64_t cmd_p = softc->mailbox + 4; + chunk_desc code; + uint32_t cmd; + int64_t timer; + int res; + + /* Note: This code assumes that PHYSADDR gives a PCI memory space + address that is accessible via our BAR4 or BAR5 */ + + code.addr = PHYSADDR((uint8_t *)buffer->buf_ptr); + code.len = buffer->buf_length; + + cmd = 0x1; /* load */ + if (!elf_header((uint8_t *)buffer->buf_ptr)) { + /* No recognizable elf seal, so assume compressed. */ + cmd |= 0x2; + } + + hs_write32(arg_p | MBOX_SET_BIT, PHYSADDR(&code)); + hs_write32(cmd_p | MBOX_SET_BIT, cmd); /* load */ + + /* Wait for handshake */ + + res = CFE_ERR_TIMEOUT; + TIMER_SET(timer, 5*CFE_HZ); + while (!TIMER_EXPIRED(timer)) { + if ((hs_read32(cmd_p) & 0x3) == 0) { + softc->downloaded = 1; + buffer->buf_retlen = 0; /* XXX check this */ + /* Note that the result code need not be translated only + because we are assuming a CFE in the device that is + compatible with us. */ + res = (int)hs_read32(arg_p); + break; + } + POLL(); + } + + return res; +} + +static int +bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + return -1; +} + +static int +bcm1250_close(cfe_devctx_t *ctx) +{ + return 0; +} diff --git a/cfe/cfe/dev/dev_bcm5700.c b/cfe/cfe/dev/dev_bcm5700.c new file mode 100644 index 0000000..a7bef89 --- /dev/null +++ b/cfe/cfe/dev/dev_bcm5700.c @@ -0,0 +1,2557 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * BCM5700/Tigon3 (10/100/1000 EthernetMAC) driver File: dev_bcm5700.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" + +#ifndef _SB_MAKE64 +#define _SB_MAKE64(x) ((uint64_t)(x)) +#endif +#ifndef _SB_MAKEMASK1 +#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n)) +#endif + +#include "lib_types.h" +#include "lib_hssubr.h" +#include "lib_malloc.h" +#include "lib_string.h" +#define blockcopy memcpy +#include "lib_printf.h" +#include "lib_queue.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_error.h" +#include "cfe_irq.h" + +#include "pcivar.h" +#include "pcireg.h" + +#include "bcm5700.h" +#include "mii.h" + +/* This is a driver for the Broadcom 570x ("Tigon 3") 10/100/1000 MAC. + Currently, only the 5700, 5701 and 5705 have been tested. The 5704 + dual MAC is not supported, nor is any device with a SerDes PHY. + + Reference: + Host Programmer Interface Specification for the BCM570X Family + of Highly-Integrated Media Access Controllers, 570X-PG106-R. + Broadcom Corp., 16215 Alton Parkway, Irvine CA, 09/27/02 + + This BCM1250 version takes advantage of DMA coherence and uses + "preserve bit lanes" addresses for all accesses that cross the + ZBbus-PCI bridge. + + Note that the 5705 does not fully map all address ranges. Per + the manual, reads and writes of the unmapped regions are permitted + and do not fault; however, it apparently has some poisoned registers, + at least in early revs, that should not be touched. See the + conditionals in the code. */ + +/* PIOSWAP controls whether word-swapping takes place for transactions + in which the 570x is the target device. In theory, either value + should work (with access macros adjusted as below) and it should be + set to be consistent with the settings for 570x as initiator. + Empirically, however, some combinations work with the bit clear: + + SWAP=0 SWAP=1 + 5700 32 PCI OK OK + 5700 64 Sturgeon OK OK + 5701-32 32 PCI OK OK + 5701-32 64 Sturgeon OK OK + 5701-32 64 Golem OK OK + 5701-64 64 Sturgeon OK OK + 5701-64 64 Golem OK FAIL + 5705 32 PCI OK OK + 5705 64 Sturgeon (OK)* FAIL + 5705 64 Golem OK OK + + * PCI status/interrupt ordering problem under load. */ + +#define PIOSWAP 0 + +#ifndef T3_DEBUG +#define T3_DEBUG 0 +#endif + +#ifndef T3_BRINGUP +#define T3_BRINGUP 0 +#endif + +/* Broadcom recommends using PHY interrupts instead of autopolling, + but I haven't made it work yet. */ +#define T3_AUTOPOLL 1 + +/* Set IPOLL to drive processing through the pseudo-interrupt + dispatcher. Set XPOLL to drive processing by an external polling + agent. One must be set; setting both is ok. */ + +#ifndef IPOLL +#define IPOLL 0 +#endif +#ifndef XPOLL +#define XPOLL 1 +#endif + +#define ENET_ADDR_LEN 6 /* size of an ethernet address */ +#define MIN_ETHER_PACK 64 /* min size of a packet */ +#define MAX_ETHER_PACK 1518 /* max size of a packet */ +#define VLAN_TAG_LEN 4 /* VLAN type plus tag */ +#define CRC_SIZE 4 /* size of CRC field */ + +/* Packet buffers. For the Tigon 3, packet buffer alignment is + arbitrary and can be to any byte boundary. We would like it + aligned to a cache line boundary for performance, although there is + a trade-off with IP/TCP header alignment. */ + +#define ETH_PKTBUF_LEN (((MAX_ETHER_PACK+31)/32)*32) + +#if __long64 +typedef struct eth_pkt_s { + queue_t next; /* 16 */ + uint8_t *buffer; /* 8 */ + uint32_t flags; /* 4 */ + int32_t length; /* 4 */ + uint8_t data[ETH_PKTBUF_LEN]; +} eth_pkt_t; +#else +typedef struct eth_pkt_s { + queue_t next; /* 8 */ + uint8_t *buffer; /* 4 */ + uint32_t flags; /* 4 */ + int32_t length; /* 4 */ + uint32_t unused[3]; /* 12 */ + uint8_t data[ETH_PKTBUF_LEN]; +} eth_pkt_t; +#endif + +#define CACHE_ALIGN 32 +#define ETH_PKTBUF_LINES ((sizeof(eth_pkt_t) + (CACHE_ALIGN-1))/CACHE_ALIGN) +#define ETH_PKTBUF_SIZE (ETH_PKTBUF_LINES*CACHE_ALIGN) +#define ETH_PKTBUF_OFFSET (offsetof(eth_pkt_t, data)) + +#define ETH_PKT_BASE(data) ((eth_pkt_t *)((data) - ETH_PKTBUF_OFFSET)) + +static void +show_packet(char c, eth_pkt_t *pkt) +{ + int i; + int n = (pkt->length < 32 ? pkt->length : 32); + + xprintf("%c[%4d]:", c, pkt->length); + for (i = 0; i < n; i++) { + if (i % 4 == 0) + xprintf(" "); + xprintf("%02x", pkt->buffer[i]); + } + xprintf("\n"); +} + + +static void t3_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +/* BCM570X Hardware Common Data Structures + XXX These work for 1250 big endian. Need endian testing. + XXX Should they move to the header file? */ + +/* Chip documentation numbers the rings with 1-origin. */ + +#define RI(n) ((n)-1) + +/* BCM570x Ring Sizes (no external memory). Pages 97-98 */ + +#define TXP_MAX_RINGS 16 +#define TXP_INTERNAL_RINGS 4 +#define TXP_RING_ENTRIES 512 + +#define RXP_STD_ENTRIES 512 + +#define RXR_MAX_RINGS 16 +#define RXR_RING_ENTRIES 1024 + +#define RXR_MAX_RINGS_05 1 +#define RXR_RING_ENTRIES_05 512 + + +/* BCM570x Send Buffer Descriptors as a struct. Pages 100-101 */ + +typedef struct t3_snd_bd_s { + uint32_t bufptr_hi; + uint32_t bufptr_lo; +#ifdef __MIPSEB + uint16_t length; + uint16_t flags; + uint16_t pad; + uint16_t vlan_tag; +#elif __MIPSEL + uint16_t flags; + uint16_t length; + uint16_t vlan_tag; + uint16_t pad; +#else +#error "bcm5700: endian not set" +#endif +} t3_snd_bd_t; + +#define SND_BD_SIZE 16 + +#define TX_FLAG_TCP_CKSUM 0x0001 +#define TX_FLAG_IP_CKSUM 0x0002 +#define TX_FLAG_PACKET_END 0x0004 +#define TX_FLAG_IP_FRAG 0x0008 +#define TX_FLAG_IP_FRAG_END 0x0010 +#define TX_FLAG_VLAN_TAG 0x0040 +#define TX_FLAG_COAL_NOW 0x0080 +#define TX_FLAG_CPU_PRE_DMA 0x0100 +#define TX_FLAG_CPU_POST_DMA 0x0200 +#define TX_FLAG_ADD_SRC 0x1000 +#define TX_FLAG_SRC_ADDR_SEL 0x6000 +#define TX_FLAG_NO_CRC 0x8000 + +/* BCM570x Receive Buffer Descriptors as a struct. Pages 105-107 */ + +typedef struct t3_rcv_bd_s { + uint32_t bufptr_hi; + uint32_t bufptr_lo; +#ifdef __MIPSEB + uint16_t index; + uint16_t length; + uint16_t type; + uint16_t flags; + uint16_t ip_cksum; + uint16_t tcp_cksum; + uint16_t error_flag; + uint16_t vlan_tag; +#elif __MIPSEL + uint16_t length; + uint16_t index; + uint16_t flags; + uint16_t type; + uint16_t tcp_cksum; + uint16_t ip_cksum; + uint16_t vlan_tag; + uint16_t error_flag; +#else +#error "bcm5700: endian not set" +#endif + uint32_t pad; + uint32_t opaque; +} t3_rcv_bd_t; + +#define RCV_BD_SIZE 32 + +#define RX_FLAG_PACKET_END 0x0004 +#define RX_FLAG_JUMBO_RING 0x0020 +#define RX_FLAG_VLAN_TAG 0x0040 +#define RX_FLAG_ERROR 0x0400 +#define RX_FLAG_MINI_RING 0x0800 +#define RX_FLAG_IP_CKSUM 0x1000 +#define RX_FLAG_TCP_CKSUM 0x2000 +#define RX_FLAG_IS_TCP 0x4000 + +#define RX_ERR_BAD_CRC 0x0001 +#define RX_ERR_COLL_DETECT 0x0002 +#define RX_ERR_LINK_LOST 0x0004 +#define RX_ERR_PHY_DECODE 0x0008 +#define RX_ERR_DRIBBLE 0x0010 +#define RX_ERR_MAC_ABORT 0x0020 +#define RX_ERR_SHORT_PKT 0x0040 +#define RX_ERR_TRUNC_NO_RES 0x0080 +#define RX_ERR_GIANT_PKT 0x0100 + +/* BCM570x Status Block format as a struct (not BCM5705). Pages 110-111. */ + +typedef struct t3_status_s { + uint32_t status; + uint32_t tag; +#ifdef __MIPSEB + uint16_t rxc_std_index; + uint16_t rxc_jumbo_index; + uint16_t reserved2; + uint16_t rxc_mini_index; + struct { + uint16_t send_c; + uint16_t return_p; + } index [16]; +#elif __MIPSEL + uint16_t rxc_jumbo_index; + uint16_t rxc_std_index; + uint16_t rxc_mini_index; + uint16_t reserved2; + struct { + uint16_t return_p; + uint16_t send_c; + } index [16]; +#else +#error "bcm5700: endian not set" +#endif +} t3_status_t; + +#define M_STATUS_UPDATED 0x00000001 +#define M_STATUS_LINKCHNG 0x00000002 +#define M_STATUS_ERROR 0x00000004 + +/* BCM570x Statistics Block format as a struct. Pages 112-120 */ + +typedef struct t3_stats_s { + uint64_t stats[L_MAC_STATS/sizeof(uint64_t)]; +} t3_stats_t; + +/* End of 570X defined data structures */ + + +typedef enum { + eth_state_uninit, + eth_state_off, + eth_state_on, +} eth_state_t; + +typedef struct t3_ether_s { + /* status block */ + volatile t3_status_t *status; /* should be cache-aligned */ + + /* PCI access information */ + uint32_t regbase; + uint32_t membase; + uint8_t irq; + pcitag_t tag; /* tag for configuration registers */ + + uint8_t hwaddr[6]; + uint16_t device; /* chip device code */ + uint8_t revision; /* chip revision */ + + eth_state_t state; /* current state */ + uint32_t intmask; /* interrupt mask */ + + /* packet lists */ + queue_t freelist; + uint8_t *pktpool; + queue_t rxqueue; + + /* rings */ + /* For now, support only the standard Rx Producer Ring */ + t3_rcv_bd_t *rxp_std; /* Standard Rx Producer Ring */ + uint32_t rxp_std_index; + uint32_t prev_rxp_std_index; + + /* For now, support only 1 priority */ + uint32_t rxr_entries; + t3_rcv_bd_t *rxr_1; /* Rx Return Ring 1 */ + uint32_t rxr_1_index; + t3_snd_bd_t *txp_1; /* Send Ring 1 */ + uint32_t txp_1_index; + uint32_t txc_1_index; + + cfe_devctx_t *devctx; + + /* PHY access */ + int phy_addr; + uint16_t phy_status; + uint16_t phy_ability; + uint16_t phy_xability; + + /* MII polling control */ + int phy_change; + int mii_polling; + + /* statistics block */ + t3_stats_t *stats; /* should be cache-aligned */ + + /* additional driver statistics */ + uint32_t rx_interrupts; + uint32_t tx_interrupts; + uint32_t bogus_interrupts; +} t3_ether_t; + + +/* Address mapping macros */ + +#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x))) +#define PHYS_TO_PTR(a) ((uint8_t *)PHYS_TO_K0(a)) + +/* All mappings through the PCI host bridge use match bits mode. */ +#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000) +#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF) + +#define PCI_TO_PTR(a) (PHYS_TO_PTR(PCI_TO_PHYS(a))) +#define PTR_TO_PCI(x) (PHYS_TO_PCI(PTR_TO_PHYS(x))) + + +/* Chip access macros */ + +/* These macros attempt to be compatible with match-bits mode, + which may put the data and byte masks into the wrong 32-bit word + for 64-bit accesses. See the comment above on PIOSWAP. + Externally mastered DMA (control and data) uses match-bits and does + specify word-swaps when operating big endian. */ + +/* Most registers are 32 bits wide and are accessed by 32-bit + transactions. The mailbox registers and on-chip RAM are 64-bits + wide but are generally accessed by 32-bit transactions. + Furthermore, the documentation is ambiguous about which 32-bits of + the mailbox is significant. To localize the potential confusions, + we define macros for the 3 different cases. */ + +#if __long64 +#define READCSR(sc,csr) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr))))) + +#define WRITECSR(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val)) + +#if PIOSWAP +#define READMBOX(sc,csr) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+((csr)+4))))) + +#define WRITEMBOX(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+((csr)+4)))) = (val)) + +#define READMEM(sc,csr) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr))))) + +#define WRITEMEM(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr)))) = (val)) + +#else +#define READMBOX(sc,csr) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr))))) + +#define WRITEMBOX(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val)) + +#define READMEM(sc,csr) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->membase+((csr) ^ 4))))) + +#define WRITEMEM(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->membase+((csr) ^ 4)))) = (val)) + +#endif +#else +#define READCSR(sc,csr) \ + (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) + +#define WRITECSR(sc,csr,val) \ + (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr), (val)))) + +#define READMBOX(sc,csr) \ + (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr))))) + +#define WRITEMBOX(sc,csr,val) \ + (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val)) + +#define READMEM(sc,csr) \ + (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr)))) + +#define WRITEMEM(sc,csr,val) \ + (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr), (val)))) + +#endif + + +/* Entry to and exit from critical sections (currently relative to + interrupts only, not SMP) */ + +#if CFG_INTERRUPTS +#define CS_ENTER(sc) cfe_disable_irq(sc->irq) +#define CS_EXIT(sc) cfe_enable_irq(sc->irq) +#else +#define CS_ENTER(sc) ((void)0) +#define CS_EXIT(sc) ((void)0) +#endif + + +static void +dumpseq(t3_ether_t *sc, int start, int next) +{ + int offset, i, j; + int columns = 4; + int lines = (((next - start)/4 + 1) + 3)/columns; + int step = lines*4; + + offset = start; + for (i = 0; i < lines; i++) { + xprintf("\nCSR"); + for (j = 0; j < columns; j++) { + if (offset + j*step < next) + xprintf(" %04X: %08X ", + offset+j*step, READCSR(sc, offset+j*step)); + } + offset += 4; + } + xprintf("\n"); +} + +static void +dumpcsrs(t3_ether_t *sc, const char *legend) +{ + xprintf("%s:\n", legend); + + /* Some device-specific PCI configuration registers */ + xprintf("-----PCI-----"); + dumpseq(sc, 0x68, 0x78); + + /* Some general control registers */ + xprintf("---General---"); + dumpseq(sc, 0x6800, 0x6810); + + xprintf("-------------\n"); +} + + +/* Packet management */ + +#define ETH_PKTPOOL_SIZE 64 +#define MIN_RXP_STD_BDS 32 + + +static eth_pkt_t * +eth_alloc_pkt(t3_ether_t *sc) +{ + eth_pkt_t *pkt; + + CS_ENTER(sc); + pkt = (eth_pkt_t *) q_deqnext(&sc->freelist); + CS_EXIT(sc); + if (!pkt) return NULL; + + pkt->buffer = pkt->data; + pkt->length = ETH_PKTBUF_LEN; + pkt->flags = 0; + + return pkt; +} + + +static void +eth_free_pkt(t3_ether_t *sc, eth_pkt_t *pkt) +{ + CS_ENTER(sc); + q_enqueue(&sc->freelist, &pkt->next); + CS_EXIT(sc); +} + +static void +eth_initfreelist(t3_ether_t *sc) +{ + int idx; + uint8_t *ptr; + eth_pkt_t *pkt; + + q_init(&sc->freelist); + + ptr = sc->pktpool; + for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) { + pkt = (eth_pkt_t *) ptr; + eth_free_pkt(sc, pkt); + ptr += ETH_PKTBUF_SIZE; + } +} + + +/* Utilities */ + +static const char * +t3_devname(t3_ether_t *sc) +{ + return (sc->devctx != NULL ? cfe_device_name(sc->devctx) : "eth?"); +} + + +/* CRCs */ + +#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */ + +uint32_t eth_crc32(const uint8_t *databuf, unsigned int datalen); +/*static*/ uint32_t +eth_crc32(const uint8_t *databuf, unsigned int datalen) +{ + unsigned int idx, bit, data; + uint32_t crc; + + crc = 0xFFFFFFFFUL; + for (idx = 0; idx < datalen; idx++) + for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0); + return crc; +} + + +/* Descriptor ring management */ + +static int +t3_add_rcvbuf(t3_ether_t *sc, eth_pkt_t *pkt) +{ + t3_rcv_bd_t *rxp; + + rxp = &(sc->rxp_std[sc->rxp_std_index]); + rxp->bufptr_lo = PTR_TO_PCI(pkt->buffer); + rxp->length = ETH_PKTBUF_LEN; + sc->rxp_std_index++; + if (sc->rxp_std_index == RXP_STD_ENTRIES) + sc->rxp_std_index = 0; + return 0; +} + +static void +t3_fillrxring(t3_ether_t *sc) +{ + eth_pkt_t *pkt; + unsigned rxp_ci, rxp_onring; + + rxp_ci = sc->status->rxc_std_index; /* Get a snapshot */ + + if (sc->rxp_std_index >= rxp_ci) + rxp_onring = sc->rxp_std_index - rxp_ci; + else + rxp_onring = (sc->rxp_std_index + RXP_STD_ENTRIES) - rxp_ci; + + while (rxp_onring < MIN_RXP_STD_BDS) { + pkt = eth_alloc_pkt(sc); + if (pkt == NULL) { + /* could not allocate a buffer */ + break; + } + if (t3_add_rcvbuf(sc, pkt) != 0) { + /* could not add buffer to ring */ + eth_free_pkt(sc, pkt); + break; + } + rxp_onring++; + } +} + +static void +t3_rx_callback(t3_ether_t *sc, eth_pkt_t *pkt) +{ + if (T3_DEBUG) show_packet('>', pkt); /* debug */ + + CS_ENTER(sc); + q_enqueue(&sc->rxqueue, &pkt->next); + CS_EXIT(sc); +} + +static void +t3_procrxring(t3_ether_t *sc) +{ + eth_pkt_t *pkt; + t3_rcv_bd_t *rxc; + volatile t3_status_t *status = sc->status; + + rxc = &(sc->rxr_1[sc->rxr_1_index]); + do { + pkt = ETH_PKT_BASE(PCI_TO_PTR(rxc->bufptr_lo)); + pkt->length = rxc->length; + if ((rxc->flags & RX_FLAG_ERROR) == 0) + t3_rx_callback(sc, pkt); + else { +#if T3_BRINGUP + xprintf("%s: rx error %04X\n", t3_devname(sc), rxc->error_flag); +#endif + eth_free_pkt(sc, pkt); /* Could optimize */ + } + sc->rxr_1_index++; + rxc++; + if (sc->rxr_1_index == sc->rxr_entries) { + sc->rxr_1_index = 0; + rxc = &(sc->rxr_1[0]); + } + } while (status->index[RI(1)].return_p != sc->rxr_1_index); + + /* Update the return ring */ + WRITEMBOX(sc, R_RCV_BD_RTN_CI(1), sc->rxr_1_index); + + /* Refill the producer ring */ + t3_fillrxring(sc); +} + + +static int +t3_transmit(t3_ether_t *sc, eth_pkt_t *pkt) +{ + t3_snd_bd_t *txp; + + if (T3_DEBUG) show_packet('<', pkt); /* debug */ + + txp = &(sc->txp_1[sc->txp_1_index]); + txp->bufptr_hi = 0; + txp->bufptr_lo = PTR_TO_PCI(pkt->buffer); + txp->length = pkt->length; + txp->flags = TX_FLAG_PACKET_END; + + sc->txp_1_index++; + if (sc->txp_1_index == TXP_RING_ENTRIES) + sc->txp_1_index = 0; + + WRITEMBOX(sc, R_SND_BD_PI(1), sc->txp_1_index); + + return 0; +} + + +static void +t3_proctxring(t3_ether_t *sc) +{ + eth_pkt_t *pkt; + t3_snd_bd_t *txc; + volatile t3_status_t *status = sc->status; + + txc = &(sc->txp_1[sc->txc_1_index]); + do { + pkt = ETH_PKT_BASE(PCI_TO_PTR(txc->bufptr_lo)); + eth_free_pkt(sc, pkt); + sc->txc_1_index++; + txc++; + if (sc->txc_1_index == TXP_RING_ENTRIES) { + sc->txc_1_index = 0; + txc = &(sc->txp_1[0]); + } + } while (status->index[RI(1)].send_c != sc->txc_1_index); +} + + +static void +t3_initrings(t3_ether_t *sc) +{ + int i; + t3_rcv_bd_t *rxp; + volatile t3_status_t *status = sc->status; + + /* Clear all Producer BDs */ + rxp = &(sc->rxp_std[0]); + for (i = 0; i < RXP_STD_ENTRIES; i++) { + rxp->bufptr_hi = rxp->bufptr_lo = 0; + rxp->length = 0; + rxp->index = i; + rxp->flags = 0; + rxp->type = 0; + rxp->ip_cksum = rxp->tcp_cksum = 0; + rxp++; + } + + /* Init the ring pointers */ + + sc->rxp_std_index = 0; status->rxc_std_index = 0; + sc->rxr_1_index = 0; status->index[RI(1)].return_p = 0; + sc->txp_1_index = 0; status->index[RI(1)].send_c = 0; + + /* Allocate some initial buffers for the Producer BD ring */ + sc->prev_rxp_std_index = 0; + t3_fillrxring(sc); + + /* Nothing consumed yet */ + sc->txc_1_index = 0; +} + +static void +t3_init(t3_ether_t *sc) +{ + /* Allocate buffer pool */ + sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, CACHE_ALIGN); + eth_initfreelist(sc); + q_init(&sc->rxqueue); + + t3_initrings(sc); +} + +static void +t3_reinit(t3_ether_t *sc) +{ + eth_initfreelist(sc); + q_init(&sc->rxqueue); + + t3_initrings(sc); +} + + +/* Byte swap utilities. */ + +#define SWAP4(x) \ + ((((x) & 0x00FF) << 24) | \ + (((x) & 0xFF00) << 8) | \ + (((x) >> 8) & 0xFF00) | \ + (((x) >> 24) & 0x00FF)) + +static uint32_t +swap4(uint32_t x) +{ + uint32_t t; + + t = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); + return (t >> 16) | ((t & 0xFFFF) << 16); +} + + +/* EEPROM access functions (BCM5700 and BCM5701 version) */ + +/* The 570x chips support multiple access methods. We use "Auto Access", + which requires that + Miscellaneous_Local_Control.Auto_SEEPROM_Access be set, + Serial_EEprom.Address.HalfClock be programmed for <= 400 Hz. + (both done by initialization code) */ + +#define EP_MAX_RETRIES 500 +#define EP_DEVICE_ID 0x00 /* default ATMEL device ID */ + +static void +eeprom_access_init(t3_ether_t *sc) +{ + uint32_t mlctl; + + WRITECSR(sc, R_EEPROM_ADDR, M_EPADDR_RESET | V_EPADDR_HPERIOD(0x60)); + + mlctl = READCSR(sc, R_MISC_LOCAL_CTRL); + mlctl |= M_MLCTL_EPAUTOACCESS; + WRITECSR(sc, R_MISC_LOCAL_CTRL, mlctl); +} + + +static uint32_t +eeprom_read_word(t3_ether_t *sc, unsigned int offset) +{ + /* Assumes that SEEPROM is already set up for auto access. */ + uint32_t epaddr, epdata; + volatile uint32_t temp; + int i; + + epaddr = READCSR(sc, R_EEPROM_ADDR); + epaddr &= M_EPADDR_HPERIOD; + epaddr |= (V_EPADDR_ADDR(offset) | V_EPADDR_DEVID(EP_DEVICE_ID) + | M_EPADDR_RW | M_EPADDR_START | M_EPADDR_COMPLETE); + WRITECSR(sc, R_EEPROM_ADDR, epaddr); + temp = READCSR(sc, R_EEPROM_ADDR); /* push */ + + for (i = 0; i < EP_MAX_RETRIES; i++) { + temp = READCSR(sc, R_EEPROM_ADDR); + if ((temp & M_EPADDR_COMPLETE) != 0) + break; + cfe_usleep(10); + } + if (i == EP_MAX_RETRIES) + xprintf("%s: eeprom_read_word: no SEEPROM response @ %x\n", + t3_devname(sc), offset); + + epdata = READCSR(sc, R_EEPROM_DATA); /* little endian */ +#ifdef __MIPSEB + return swap4(epdata); +#else + return epdata; +#endif +} + +static int +eeprom_read_range(t3_ether_t *sc, unsigned int offset, unsigned int len, + uint32_t buf[]) +{ + int index; + + offset &= ~3; len &= ~3; /* 4-byte words only */ + index = 0; + + while (len > 0) { + buf[index++] = eeprom_read_word(sc, offset); + offset += 4; len -= 4; + } + + return index; +} + +static void +eeprom_dump_range(const char *label, + uint32_t buf[], unsigned int offset, unsigned int len) +{ + int index; + + xprintf("EEPROM: %s", label); + + offset &= ~3; len &= ~3; /* 4-byte words only */ + index = 0; + + for (index = 0; len > 0; index++) { + if (index % 8 == 0) + xprintf("\n %04x: ", offset); + xprintf(" %08x", buf[offset/4]); + offset += 4; len -= 4; + } + xprintf("\n"); +} + + +/* MII access functions. */ + +/* BCM5401 device specific registers */ + +#define MII_ISR 0x1A /* Interrupt Status Register */ +#define MII_IMR 0x1B /* Interrupt Mask Register */ + +#define M_INT_LINKCHNG 0x0002 + + +/* The 570x chips support multiple access methods. We use "Auto + Access", which requires that MDI_Control_Register.MDI_Select be + clear (done by initialization code) */ + +#define MII_MAX_RETRIES 5000 + +static void +mii_access_init(t3_ether_t *sc) +{ + WRITECSR(sc, R_MDI_CTRL, 0); /* here for now */ +#if !T3_AUTOPOLL + WRITECSR(sc, R_MI_MODE, V_MIMODE_CLKCNT(0x1F)); /* max divider */ +#endif +} + +/* XXX Autopolling should be disabled during reads and writes per the + manual, but doing so currently generates recurvise LINKCHNG + attentions. */ + +static uint16_t +mii_read_register(t3_ether_t *sc, int phy, int index) +{ + uint32_t mode; + uint32_t comm, val; + int i; + + mode = READCSR(sc, R_MI_MODE); +#if 0 /* for now */ + if (mode & M_MIMODE_POLLING) { + WRITECSR(sc, R_MI_MODE, mode & ~M_MIMODE_POLLING); + cfe_usleep(40); + } +#endif + + comm = (V_MICOMM_CMD_RD | V_MICOMM_PHY(phy) | V_MICOMM_REG(index) + | M_MICOMM_BUSY); + WRITECSR(sc, R_MI_COMM, comm); + + for (i = 0; i < MII_MAX_RETRIES; i++) { + val = READCSR(sc, R_MI_COMM); + if ((val & M_MICOMM_BUSY) == 0) + break; + } + if (i == MII_MAX_RETRIES) + xprintf("%s: mii_read_register: MII always busy\n", t3_devname(sc)); + +#if 0 + if (mode & M_MIMODE_POLLING) + WRITECSR(sc, R_MI_MODE, mode); +#endif + + return G_MICOMM_DATA(val); +} + +/* Register reads occasionally return spurious 0's. Verify a zero by + doing a second read, or spinning when a zero is "impossible". */ +static uint16_t +mii_read_register_v(t3_ether_t *sc, int phy, int index, int spin) +{ + uint32_t val; + + val = mii_read_register(sc, phy, index); + if (val == 0) { + do { + val = mii_read_register(sc, phy, index); + } while (spin && val == 0); + } + return val; +} + +static void +mii_write_register(t3_ether_t *sc, int phy, int index, uint16_t value) +{ + uint32_t mode; + uint32_t comm, val; + int i; + + mode = READCSR(sc, R_MI_MODE); +#if 0 /* for now */ + if (mode & M_MIMODE_POLLING) { + WRITECSR(sc, R_MI_MODE, mode & ~M_MIMODE_POLLING); + cfe_usleep(40); + } +#endif + + comm = (V_MICOMM_CMD_WR | V_MICOMM_PHY(phy) | V_MICOMM_REG(index) + | V_MICOMM_DATA(value) | M_MICOMM_BUSY); + WRITECSR(sc, R_MI_COMM, comm); + + for (i = 0; i < MII_MAX_RETRIES; i++) { + val = READCSR(sc, R_MI_COMM); + if ((val & M_MICOMM_BUSY) == 0) + break; + } + if (i == MII_MAX_RETRIES) + xprintf("%s: mii_write_register: MII always busy\n", t3_devname(sc)); + +#if 0 + if (mode & M_MIMODE_POLLING) + WRITECSR(sc, R_MI_MODE, mode); +#endif +} + +static int +mii_probe(t3_ether_t *sc) +{ +#if T3_AUTOPOLL /* With autopolling, the code below is not reliable. */ + return 1; /* Guaranteed for integrated PHYs */ +#else + int i; + uint16_t id1, id2; + + for (i = 0; i < 32; i++) { + id1 = mii_read_register(sc, i, MII_PHYIDR1); + id2 = mii_read_register(sc, i, MII_PHYIDR2); + if ((id1 != 0x0000 && id1 != 0xFFFF) || + (id2 != 0x0000 && id2 != 0xFFFF)) { + if (id1 != id2) return i; + } + } + return -1; +#endif +} + +#if T3_DEBUG +#define OUI_BCM 0x001018 +#define IDR_BCM 0x000818 +/* 5400: 4, 5401: 5, 5411: 6, 5421: e, 5701: 11 */ + +static void +mii_dump(t3_ether_t *sc, const char *label) +{ + int i; + uint16_t r; + uint32_t idr, part; + + xprintf("%s, MII:\n", label); + idr = part = 0; + + /* Required registers */ + for (i = 0x0; i <= 0x6; ++i) { + r = mii_read_register(sc, sc->phy_addr, i); + xprintf(" REG%02X: %04X", i, r); + if (i == 3 || i == 6) + xprintf("\n"); + if (i == MII_PHYIDR1) { + idr |= r << 6; + } + else if (i == MII_PHYIDR2) { + idr |= (r >> 10) & 0x3F; + part = (r >> 4) & 0x3F; + } + } + + /* GMII extensions */ + for (i = 0x9; i <= 0xA; ++i) { + r = mii_read_register(sc, sc->phy_addr, i); + xprintf(" REG%02X: %04X", i, r); + } + r = mii_read_register(sc, sc->phy_addr, 0xF); + xprintf(" REG%02X: %04X\n", 0xF, r); + + /* Broadcom extensions (54xx family) */ + if (idr == IDR_BCM) { + for (i = 0x10; i <= 0x14; i++) { + r = mii_read_register(sc, sc->phy_addr, i); + xprintf(" REG%02X: %04X", i, r); + } + xprintf("\n"); + for (i = 0x18; i <= 0x1A; i++) { + r = mii_read_register(sc, sc->phy_addr, i); + xprintf(" REG%02X: %04X", i, r); + } + xprintf("\n"); + } +} +#else +#define mii_dump(sc,label) +#endif + +static void +mii_enable_interrupts(t3_ether_t *sc) +{ + mii_write_register(sc, sc->phy_addr, MII_IMR, ~M_INT_LINKCHNG); +} + + +/* For 5700/5701, LINKCHNG is read-only in the status register and + cleared by writing to CFGCHNG | SYNCCHNG. For the 5705 + (empirically), LINKCHNG is cleared by writing a one, while CFGCHNG + and SYNCCHNG are unimplemented. Thus we can safely clear the + interrupt by writing ones to all the above bits. */ + +#define M_LINKCHNG_CLR \ + (M_EVT_LINKCHNG | M_MACSTAT_CFGCHNG | M_MACSTAT_SYNCCHNG) + +static int +mii_poll(t3_ether_t *sc) +{ + uint32_t macstat; + uint16_t status, ability, xability; + uint16_t isr; + + macstat = READCSR(sc, R_MAC_STATUS); + if ((macstat & (M_EVT_LINKCHNG | M_EVT_MIINT)) != 0) + WRITECSR(sc, R_MAC_STATUS, M_LINKCHNG_CLR); + + /* BMSR has read-to-clear bits; read twice. */ + + status = mii_read_register(sc, sc->phy_addr, MII_BMSR); + status = mii_read_register_v(sc, sc->phy_addr, MII_BMSR, 1); + ability = mii_read_register_v(sc, sc->phy_addr, MII_ANLPAR, 0); + if (status & BMSR_1000BT_XSR) + xability = mii_read_register_v(sc, sc->phy_addr, MII_K1STSR, 0); + else + xability = 0; + isr = mii_read_register(sc, sc->phy_addr, MII_ISR); + + if (status != sc->phy_status + || ability != sc->phy_ability || xability != sc->phy_xability) { +#if T3_DEBUG + xprintf("[%04x]", isr); + xprintf((macstat & (M_EVT_LINKCHNG | M_EVT_MIINT)) != 0 ? "+" : "-"); + + if (status != sc->phy_status) + xprintf(" ST: %04x %04x", sc->phy_status, status); + if (ability != sc->phy_ability) + xprintf(" AB: %04x %04x", sc->phy_ability, ability); + if (xability != sc->phy_xability) + xprintf(" XA: %04x %04x", sc->phy_xability, xability); + xprintf("\n"); +#endif + sc->phy_status = status; + sc->phy_ability = ability; + sc->phy_xability = xability; + return 1; + } + else if ((macstat & (M_EVT_LINKCHNG | M_EVT_MIINT)) != 0) { + isr = mii_read_register(sc, sc->phy_addr, MII_ISR); + } + return 0; +} + +static void +mii_set_speed(t3_ether_t *sc, int speed) +{ + uint16_t control; + + control = mii_read_register(sc, sc->phy_addr, MII_BMCR); + + control &= ~(BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, sc->phy_addr, MII_BMCR, control); + control &= ~(BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX); + + switch (speed) { + case ETHER_SPEED_10HDX: + default: + break; + case ETHER_SPEED_10FDX: + control |= BMCR_DUPLEX; + break; + case ETHER_SPEED_100HDX: + control |= BMCR_SPEED100; + break; + case ETHER_SPEED_100FDX: + control |= BMCR_SPEED100 | BMCR_DUPLEX ; + break; + } + + mii_write_register(sc, sc->phy_addr, MII_BMCR, control); +} + +static void +mii_autonegotiate(t3_ether_t *sc) +{ + uint16_t control, status, remote, xremote; + unsigned int timeout; + int linkspeed; + uint32_t mode; + + linkspeed = ETHER_SPEED_UNKNOWN; + + /* Read twice to clear latching bits */ + status = mii_read_register(sc, sc->phy_addr, MII_BMSR); + status = mii_read_register_v(sc, sc->phy_addr, MII_BMSR, 1); + mii_dump(sc, "query PHY"); + + if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) == + (BMSR_AUTONEG | BMSR_LINKSTAT)) + control = mii_read_register(sc, sc->phy_addr, MII_BMCR); + else { + for (timeout = 4*CFE_HZ; timeout > 0; timeout -= CFE_HZ/2) { + status = mii_read_register(sc, sc->phy_addr, MII_BMSR); + if ((status & BMSR_ANCOMPLETE) != 0 || timeout <= 0) + break; + cfe_sleep(CFE_HZ/2); + } + } + + remote = mii_read_register_v(sc, sc->phy_addr, MII_ANLPAR, 0); + + /* XXX Empirically, it appears best to set/keep PortMode non-null to + get STATUS_LINKCHNG assertions. */ + mode = READCSR(sc, R_MAC_MODE); + + xprintf("%s: Link speed: ", t3_devname(sc)); + if ((status & BMSR_ANCOMPLETE) != 0) { + /* A link partner was negogiated... */ + + if (status & BMSR_1000BT_XSR) + xremote = mii_read_register_v(sc, sc->phy_addr, MII_K1STSR, 0); + else + xremote = 0; + + mode &= ~(M_MACM_PORTMODE | M_MACM_HALFDUPLEX); + + if ((xremote & K1STSR_LP1KFD) != 0) { + xprintf("1000BaseT FDX\n"); + linkspeed = ETHER_SPEED_1000FDX; + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_GMII); + } + else if ((xremote & K1STSR_LP1KHD) != 0) { + xprintf("1000BaseT HDX\n"); + linkspeed = ETHER_SPEED_1000HDX; + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_GMII) | M_MACM_HALFDUPLEX; + } + else if ((remote & ANLPAR_TXFD) != 0) { + xprintf("100BaseT FDX\n"); + linkspeed = ETHER_SPEED_100FDX; + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII); + } + else if ((remote & ANLPAR_TXHD) != 0) { + xprintf("100BaseT HDX\n"); + linkspeed = ETHER_SPEED_100HDX; + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII) | M_MACM_HALFDUPLEX; + } + else if ((remote & ANLPAR_10FD) != 0) { + xprintf("10BaseT FDX\n"); + linkspeed = ETHER_SPEED_10FDX; + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII); + } + else if ((remote & ANLPAR_10HD) != 0) { + xprintf("10BaseT HDX\n"); + linkspeed = ETHER_SPEED_10HDX; + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII) | M_MACM_HALFDUPLEX; + } + + WRITECSR(sc, R_MAC_MODE, mode); + } + else { + /* no link partner convergence */ + xprintf("Unknown\n"); + linkspeed = ETHER_SPEED_UNKNOWN; + remote = xremote = 0; + if (G_MACM_PORTMODE(mode) == K_MACM_PORTMODE_NONE) { + /* Keep any previous port mode as the one most likely to reappear. + Otherwise, choose one, and 10/100FDX is more likely. */ + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII); + WRITECSR(sc, R_MAC_MODE, mode); + } + } + + /* clear latching bits, XXX fix flakey reads */ + status = mii_read_register_v(sc, sc->phy_addr, MII_BMSR, 1); + (void)mii_read_register(sc, sc->phy_addr, MII_ISR); + + sc->phy_status = status; + sc->phy_ability = remote; + sc->phy_xability = xremote; + + mii_dump(sc, "final PHY"); +} + + +static void +t3_clear(t3_ether_t *sc, unsigned reg, uint32_t mask) +{ + uint32_t val; + int timeout; + + val = READCSR(sc, reg); + val &= ~mask; + WRITECSR(sc, reg, val); + val = READCSR(sc, reg); + + for (timeout = 4000; (val & mask) != 0 && timeout > 0; timeout -= 100) { + cfe_usleep(100); + val = READCSR(sc, reg); + } + if (timeout <= 0) + xprintf("%s: cannot clear %04X/%08X\n", t3_devname(sc), reg, mask); +} + + +/* The following functions collectively implement the recommended + BCM5700 Initialization Procedure (Section 8: Device Control) */ + +static int +t3_coldreset(t3_ether_t *sc) +{ + pcireg_t cmd; + pcireg_t bhlc, subsysid; + pcireg_t bar0, bar1; + pcireg_t cmdx; + uint32_t mhc, mcr, mcfg; + uint32_t mode; + int timeout; + + /* Steps 1-18 */ + /* Enable memory, also clear R/WC status bits (1) */ + cmd = pci_conf_read(sc->tag, PCI_COMMAND_STATUS_REG); + cmd |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; + pci_conf_write(sc->tag, PCI_COMMAND_STATUS_REG, cmd); + + /* Clear and disable INTA output. (2) */ + mhc = READCSR(sc, R_MISC_HOST_CTRL); + mhc |= M_MHC_MASKPCIINT | M_MHC_CLEARINTA; + WRITECSR(sc, R_MISC_HOST_CTRL, mhc); + + /* Save some config registers modified by core clock reset (3). */ + bhlc = pci_conf_read(sc->tag, PCI_BHLC_REG); + subsysid = pci_conf_read(sc->tag, PCI_SUBSYS_ID_REG); + /* Empirically, these are clobbered too. */ + bar0 = pci_conf_read(sc->tag, PCI_MAPREG(0)); + bar1 = pci_conf_read(sc->tag, PCI_MAPREG(1)); + + /* Reset the core clocks (4, 5). */ + mcfg = READCSR(sc, R_MISC_CFG); + mcfg |= M_MCFG_CORERESET; + WRITECSR(sc, R_MISC_CFG, mcfg); + cfe_usleep(100); /* 100 usec delay */ + + /* NB: Until the BARs are restored and reenabled, only PCI + configuration reads and writes will succeed. */ + + /* Reenable MAC memory (7) */ + pci_conf_write(sc->tag, PCI_MAPREG(0), bar0); + pci_conf_write(sc->tag, PCI_MAPREG(1), bar1); + (void)pci_conf_read(sc->tag, PCI_MAPREG(1)); /* push */ + pci_conf_write(sc->tag, PCI_COMMAND_STATUS_REG, cmd); + (void)pci_conf_read(sc->tag, PCI_COMMAND_STATUS_REG); /* push */ + + /* Undo some of the resets (6) */ + mhc = READCSR(sc, R_MISC_HOST_CTRL); + mhc |= M_MHC_MASKPCIINT; + WRITECSR(sc, R_MISC_HOST_CTRL, mhc); + + /* Verify that core clock resets completed and autocleared. */ + mcfg = READCSR(sc, R_MISC_CFG); + if ((mcfg & M_MCFG_CORERESET) != 0) { + xprintf("bcm5700: core clocks stuck in reset\n"); + } + + /* Configure PCI-X (8) */ + if (sc->device != K_PCI_ID_BCM5705) { + cmdx = pci_conf_read(sc->tag, PCI_PCIX_CMD_REG); + cmdx &= ~PCIX_CMD_RLXORDER_ENABLE; + pci_conf_write(sc->tag, PCI_PCIX_CMD_REG, cmdx); + } + + /* Enable memory arbiter (9) */ + mode = READCSR(sc, R_MEM_MODE); + mode |= M_MAM_ENABLE; /* enable memory arbiter */ + WRITECSR(sc, R_MEM_MODE, mode); + + /* Assume no external SRAM for now (10) */ + + /* Set up MHC for endianness and write enables (11-15) */ + mhc = READCSR(sc, R_MISC_HOST_CTRL); +#ifdef __MIPSEL + mhc |= M_MHC_ENWORDSWAP; /* XXX check this */ +#endif +#ifdef __MIPSEB + /* Since we use match-bits for Direct PCI access, don't swap bytes. */ +#if PIOSWAP + mhc |= M_MHC_ENWORDSWAP; +#endif +#endif + mhc |= M_MHC_ENINDIRECT | M_MHC_ENPCISTATERW | M_MHC_ENCLKCTRLRW; + WRITECSR(sc, R_MISC_HOST_CTRL, mhc); + + /* Set byte swapping (16, 17) */ + mcr = READCSR(sc, R_MODE_CTRL); +#ifdef __MIPSEL + mcr &= ~M_MCTL_BSWAPDATA; + mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA; /* XXX check this */ +#endif +#ifdef __MIPSEB + mcr &= ~(M_MCTL_BSWAPCTRL | M_MCTL_BSWAPDATA); + mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA; +#endif + WRITECSR(sc, R_MODE_CTRL, mcr); + + /* Disable PXE restart, wait for firmware (18, 19) */ + if (READMEM(sc, A_PXE_MAILBOX) != T3_MAGIC_NUMBER) { + /* Apparently, if the magic number is already set, firmware + ignores this attempted handshake. */ + WRITEMEM(sc, A_PXE_MAILBOX, T3_MAGIC_NUMBER); + for (timeout = CFE_HZ; timeout > 0; timeout -= CFE_HZ/10) { + if (READMEM(sc, A_PXE_MAILBOX) == ~T3_MAGIC_NUMBER) + break; + cfe_sleep(CFE_HZ/10); + } + if (READMEM(sc, A_PXE_MAILBOX) != ~T3_MAGIC_NUMBER) + xprintf("bcm5700: no firmware PXE rendevous\n"); + } + else + xprintf("bcm5700: PXE magic number already set\n"); + + /* Clear Ethernet MAC Mode (20) */ + WRITECSR(sc, R_MAC_MODE, 0x00000000); + + /* Restore remaining config registers (21) */ + pci_conf_write(sc->tag, PCI_BHLC_REG, bhlc); + pci_conf_write(sc->tag, PCI_SUBSYS_ID_REG, subsysid); + + return 0; +} + +/* XXX Not clear that the following is useful. */ +static int +t3_warmreset(t3_ether_t *sc) +{ + uint32_t mode; + + /* Enable memory arbiter (9) */ + mode = READCSR(sc, R_MEM_MODE); + mode |= M_MAM_ENABLE; /* enable memory arbiter */ + WRITECSR(sc, R_MEM_MODE, mode); + + /* Clear Ethernet MAC Mode (20) */ + WRITECSR(sc, R_MAC_MODE, 0x00000000); + + return 0; +} + + +static int +t3_init_registers(t3_ether_t *sc) +{ + unsigned offset; + uint32_t dmac, mcr, mcfg; + + /* Steps 22-29 */ + + /* Clear MAC statistics block (22) */ + for (offset = A_MAC_STATS; offset < A_MAC_STATS+L_MAC_STATS; offset += 4) { + WRITEMEM(sc, offset, 0); + } + + /* Clear driver status memory region (23) */ + /* ASSERT (sizeof(t3_status_t) == L_MAC_STATUS) */ + memset((uint8_t *)sc->status, 0, sizeof(t3_status_t)); + + /* Set up PCI DMA control (24) */ + dmac = READCSR(sc, R_DMA_RW_CTRL); + dmac &= ~(M_DMAC_RDCMD | M_DMAC_WRCMD | M_DMAC_MINDMA); + dmac |= V_DMAC_RDCMD(K_PCI_MEMRD) | V_DMAC_WRCMD(K_PCI_MEMWR); + switch (sc->device) { + case K_PCI_ID_BCM5700: + case K_PCI_ID_BCM5701: + case K_PCI_ID_BCM5702: + dmac |= V_DMAC_MINDMA(0xF); /* "Recommended" */ + break; + default: + dmac |= V_DMAC_MINDMA(0x0); + break; + } + WRITECSR(sc, R_DMA_RW_CTRL, dmac); + + /* Set DMA byte swapping (25) - XXX repeat of (17) */ + mcr = READCSR(sc, R_MODE_CTRL); +#ifdef __MIPSEL + mcr &= ~M_MCTL_BSWAPDATA; + mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA; /* XXX check this */ +#endif +#ifdef __MIPSEB + mcr &= ~(M_MCTL_BSWAPCTRL | M_MCTL_BSWAPDATA); + mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA; +#endif + WRITECSR(sc, R_MODE_CTRL, mcr); + + /* Configure host rings (26) */ + mcr |= M_MCTL_HOSTBDS; + WRITECSR(sc, R_MODE_CTRL, mcr); + + /* Indicate driver ready, disable checksums (27, 28) */ + mcr |= M_MCTL_HOSTUP; + mcr |= (M_MCTL_NOTXPHSUM | M_MCTL_NORXPHSUM); + WRITECSR(sc, R_MODE_CTRL, mcr); + + /* Configure timer (29) */ + mcfg = READCSR(sc, R_MISC_CFG); + mcfg &= ~M_MCFG_PRESCALER; + mcfg |= V_MCFG_PRESCALER(66-1); /* 66 MHz */ + WRITECSR(sc, R_MISC_CFG, mcfg); + + return 0; +} + +static int +t3_init_pools(t3_ether_t *sc) +{ + uint32_t mode; + int timeout; + + /* Steps 30-36. These use "recommended" settings (p 150) */ + + /* Configure the MAC memory pool (30) */ + if (sc->device != K_PCI_ID_BCM5705) { + WRITECSR(sc, R_BMGR_MBUF_BASE, A_BUFFER_POOL); + WRITECSR(sc, R_BMGR_MBUF_LEN, L_BUFFER_POOL); + } + else { + /* Note: manual appears to recommend not even writing these (?) */ + /* WRITECSR(sc, R_BMGR_MBUF_BASE, A_RXMBUF); */ + /* WRITECSR(sc, R_BMGR_MBUF_LEN, 0x8000); */ + } + + /* Configure the MAC DMA resource pool (31) */ + WRITECSR(sc, R_BMGR_DMA_BASE, A_DMA_DESCS); + WRITECSR(sc, R_BMGR_DMA_LEN, L_DMA_DESCS); + + /* Configure the MAC memory watermarks (32) */ + WRITECSR(sc, R_BMGR_MBUF_DMA_LOW, 0x50); + WRITECSR(sc, R_BMGR_MBUF_RX_LOW, 0x20); + WRITECSR(sc, R_BMGR_MBUF_HIGH, 0x60); + + /* Configure the DMA resource watermarks (33) */ + WRITECSR(sc, R_BMGR_DMA_LOW, 5); + WRITECSR(sc, R_BMGR_DMA_HIGH, 10); + + /* Enable the buffer manager (34, 35) */ + mode = READCSR(sc, R_BMGR_MODE); + mode |= (M_BMODE_ENABLE | M_BMODE_MBUFLOWATTN); + WRITECSR(sc, R_BMGR_MODE, mode); + for (timeout = CFE_HZ/2; timeout > 0; timeout -= CFE_HZ/10) { + mode = READCSR(sc, R_BMGR_MODE); + if ((mode & M_BMODE_ENABLE) != 0) + break; + cfe_sleep(CFE_HZ/10); + } + if ((mode & M_BMODE_ENABLE) == 0) + xprintf("bcm5700: buffer manager not enabled\n"); + + /* Enable internal queues (36) */ + WRITECSR(sc, R_FTQ_RESET, 0xFFFFFFFF); + (void)READCSR(sc, R_FTQ_RESET); /* push */ + cfe_sleep(1); + WRITECSR(sc, R_FTQ_RESET, 0x00000000); + + return 0; +} + +static int +t3_init_rings(t3_ether_t *sc) +{ + unsigned rcbp; + int i; + + /* Steps 37-46 */ + + /* Initialize RCBs for Standard Receive Buffer Ring (37) */ + WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_HOST_ADDR_HIGH, 0); + WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_HOST_ADDR_LOW, PTR_TO_PCI(sc->rxp_std)); + WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_CTRL, V_RCB_MAXLEN(ETH_PKTBUF_LEN)); + WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_NIC_ADDR, A_STD_RCV_RINGS); + + /* Disable RCBs for Jumbo and Mini Receive Buffer Rings (38,39) */ + WRITECSR(sc, R_JUMBO_RCV_BD_RCB+RCB_CTRL, + RCB_FLAG_USE_EXT_RCV_BD | RCB_FLAG_RING_DISABLED); + WRITECSR(sc, R_JUMBO_RCV_BD_RCB+RCB_NIC_ADDR, A_JUMBO_RCV_RINGS); + WRITECSR(sc, R_MINI_RCV_BD_RCB+RCB_CTRL, RCB_FLAG_RING_DISABLED); + WRITECSR(sc, R_MINI_RCV_BD_RCB+RCB_NIC_ADDR, 0xe000); + + /* Set BD ring replenish thresholds (40) */ + WRITECSR(sc, R_MINI_RCV_BD_THRESH, 128); +#if T3_BRINGUP + WRITECSR(sc, R_STD_RCV_BD_THRESH, 1); +#else + WRITECSR(sc, R_STD_RCV_BD_THRESH, 25); +#endif + WRITECSR(sc, R_JUMBO_RCV_BD_THRESH, 16); + + /* Disable unused send producer rings 2-16 (41) */ + for (rcbp = A_SND_RCB(1); rcbp <= A_SND_RCB(16); rcbp += RCB_SIZE) + WRITEMEM(sc, rcbp+RCB_CTRL, RCB_FLAG_RING_DISABLED); + + /* Initialize send producer index registers (42) */ + for (i = 1; i <= TXP_MAX_RINGS; i++) { + WRITEMBOX(sc, R_SND_BD_PI(i), 0); + WRITEMBOX(sc, R_SND_BD_NIC_PI(i), 0); + } + + /* Initialize send producer ring 1 (43) */ + WRITEMEM(sc, A_SND_RCB(1)+RCB_HOST_ADDR_HIGH, 0); + WRITEMEM(sc, A_SND_RCB(1)+RCB_HOST_ADDR_LOW, PTR_TO_PCI(sc->txp_1)); + WRITEMEM(sc, A_SND_RCB(1)+RCB_CTRL, V_RCB_MAXLEN(TXP_RING_ENTRIES)); + WRITEMEM(sc, A_SND_RCB(1)+RCB_NIC_ADDR, A_SND_RINGS); + + /* Disable unused receive return rings (44) */ + for (rcbp = A_RTN_RCB(1); rcbp <= A_RTN_RCB(16); rcbp += RCB_SIZE) + WRITEMEM(sc, rcbp+RCB_CTRL, RCB_FLAG_RING_DISABLED); + + /* Initialize receive return ring 1 (45) */ + WRITEMEM(sc, A_RTN_RCB(1)+RCB_HOST_ADDR_HIGH, 0); + WRITEMEM(sc, A_RTN_RCB(1)+RCB_HOST_ADDR_LOW, PTR_TO_PCI(sc->rxr_1)); + WRITEMEM(sc, A_RTN_RCB(1)+RCB_CTRL, V_RCB_MAXLEN(sc->rxr_entries)); + WRITEMEM(sc, A_RTN_RCB(1)+RCB_NIC_ADDR, 0x0000); + + /* Initialize receive producer ring mailboxes (46) */ + WRITEMBOX(sc, R_RCV_BD_STD_PI, 0); + WRITEMBOX(sc, R_RCV_BD_JUMBO_PI, 0); + WRITEMBOX(sc, R_RCV_BD_MINI_PI, 0); + + return 0; +} + +static int +t3_configure_mac(t3_ether_t *sc) +{ + uint32_t low, high; + uint32_t seed; + int i; + + /* Steps 47-52 */ + + /* Configure the MAC unicast address (47) */ + high = (sc->hwaddr[0] << 8) | (sc->hwaddr[1]); + low = ((sc->hwaddr[2] << 24) | (sc->hwaddr[3] << 16) + | (sc->hwaddr[4] << 8) | sc->hwaddr[5]); + /* For now, use a single MAC address */ + WRITECSR(sc, R_MAC_ADDR1_HIGH, high); WRITECSR(sc, R_MAC_ADDR1_LOW, low); + WRITECSR(sc, R_MAC_ADDR2_HIGH, high); WRITECSR(sc, R_MAC_ADDR2_LOW, low); + WRITECSR(sc, R_MAC_ADDR3_HIGH, high); WRITECSR(sc, R_MAC_ADDR3_LOW, low); + WRITECSR(sc, R_MAC_ADDR4_HIGH, high); WRITECSR(sc, R_MAC_ADDR4_LOW, low); + + /* Configure the random backoff seed (48) */ + seed = 0; + for (i = 0; i < 6; i++) + seed += sc->hwaddr[i]; + seed &= 0x3FF; + WRITECSR(sc, R_TX_BACKOFF, seed); + + /* Configure the MTU (49) */ + WRITECSR(sc, R_RX_MTU, MAX_ETHER_PACK+VLAN_TAG_LEN); + + /* Configure the tx IPG (50) */ + WRITECSR(sc, R_TX_LENS, + V_TXLEN_SLOT(0x20) | V_TXLEN_IPG(0x6) | V_TXLEN_IPGCRS(0x2)); + + /* Configure the default rx return ring 1 (51) */ + WRITECSR(sc, R_RX_RULES_CFG, V_RULESCFG_DEFAULT(1)); + + /* Configure the receive lists and enable statistics (52) */ + WRITECSR(sc, R_RCV_LIST_CFG, + V_LISTCFG_GROUP(1) | V_LISTCFG_ACTIVE(1) | V_LISTCFG_BAD(1)); + /* was V_LISTCFG_DEFAULT(1) | V_LISTCFG_ACTIVE(16) | V_LISTCFG_BAD(1) */ + + return 0; +} + +static int +t3_enable_stats(t3_ether_t *sc) +{ + uint32_t ctrl; + + /* Steps 53-56 */ + + /* Enable rx stats (53,54) */ + WRITECSR(sc, R_RCV_LIST_STATS_ENB, 0xFFFFFF); + ctrl = READCSR(sc, R_RCV_LIST_STATS_CTRL); + ctrl |= M_STATS_ENABLE; + WRITECSR(sc, R_RCV_LIST_STATS_CTRL, ctrl); + + /* Enable tx stats (55,56) */ + WRITECSR(sc, R_SND_DATA_STATS_ENB, 0xFFFFFF); + ctrl = READCSR(sc, R_SND_DATA_STATS_CTRL); + ctrl |= (M_STATS_ENABLE | M_STATS_FASTUPDATE); + WRITECSR(sc, R_SND_DATA_STATS_CTRL, ctrl); + + return 0; +} + +static int +t3_init_coalescing(t3_ether_t *sc) +{ + uint32_t mode; + int timeout; + + /* Steps 57-68 */ + + /* Disable the host coalescing engine (57, 58) */ + WRITECSR(sc, R_HOST_COAL_MODE, 0); + for (timeout = CFE_HZ/2; timeout > 0; timeout -= CFE_HZ/10) { + mode = READCSR(sc, R_HOST_COAL_MODE); + if (mode == 0) + break; + cfe_sleep(CFE_HZ/10); + } + if (mode != 0) + xprintf("bcm5700: coalescing engine not disabled\n"); + + /* Set coalescing parameters (59-62) */ +#if T3_BRINGUP + WRITECSR(sc, R_RCV_COAL_TICKS, 0); + WRITECSR(sc, R_RCV_COAL_MAX_CNT, 1); +#else + WRITECSR(sc, R_RCV_COAL_TICKS, 150); + WRITECSR(sc, R_RCV_COAL_MAX_CNT, 10); +#endif + WRITECSR(sc, R_RCV_COAL_INT_TICKS, 0); + WRITECSR(sc, R_RCV_COAL_INT_CNT, 0); +#if T3_BRINGUP + WRITECSR(sc, R_SND_COAL_TICKS, 0); + WRITECSR(sc, R_SND_COAL_MAX_CNT, 1); +#else + WRITECSR(sc, R_SND_COAL_TICKS, 150); + WRITECSR(sc, R_SND_COAL_MAX_CNT, 10); +#endif + WRITECSR(sc, R_SND_COAL_INT_TICKS, 0); + WRITECSR(sc, R_SND_COAL_INT_CNT, 0); + + /* Initialize host status block address (63) */ + WRITECSR(sc, R_STATUS_HOST_ADDR, 0); + WRITECSR(sc, R_STATUS_HOST_ADDR+4, PTR_TO_PCI(sc->status)); + + /* Initialize host statistics block address (64) */ + WRITECSR(sc, R_STATS_HOST_ADDR, 0); + WRITECSR(sc, R_STATS_HOST_ADDR+4, PTR_TO_PCI(sc->stats)); + + /* Set statistics block NIC address and tick count (65, 66) */ + WRITECSR(sc, R_STATS_TICKS, 1000000); + WRITECSR(sc, R_STATS_BASE_ADDR, A_MAC_STATS); + + /* Set status block NIC address (67) */ + WRITECSR(sc, R_STATUS_BASE_ADDR, A_MAC_STATUS); + + /* Enable the host coalescing engine (68) */ + WRITECSR(sc, R_HOST_COAL_MODE, M_HCM_ENABLE); + + return 0; +} + +static int +t3_init_dma(t3_ether_t *sc) +{ + uint32_t mode; + + /* Steps 69-87 */ + + /* Enable receive BD completion, placement, and selector blocks (69-71) */ + WRITECSR(sc, R_RCV_BD_COMP_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE); + WRITECSR(sc, R_RCV_LIST_MODE, M_MODE_ENABLE); + if (sc->device != K_PCI_ID_BCM5705) { + WRITECSR(sc, R_RCV_LIST_SEL_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE); + } + + /* Enable DMA engines, enable and clear statistics (72, 73) */ + mode = READCSR(sc, R_MAC_MODE); + mode |= (M_MACM_FHDEENB | M_MACM_RDEENB | M_MACM_TDEENB | + M_MACM_RXSTATSENB | M_MACM_RXSTATSCLR | + M_MACM_TXSTATSENB | M_MACM_TXSTATSCLR); +#if T3_AUTOPOLL + mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII); +#endif + + WRITECSR(sc, R_MAC_MODE, mode); + +#if T3_AUTOPOLL + WRITECSR(sc, R_MISC_LOCAL_CTRL, M_MLCTL_INTATTN); +#endif + + /* Configure GPIOs (74) - skipped */ + + /* Clear interrupt mailbox (75) */ + WRITEMBOX(sc, R_INT_MBOX(0), 0); + + /* Enable DMA completion block (76) */ + if (sc->device != K_PCI_ID_BCM5705) { + WRITECSR(sc, R_DMA_COMP_MODE, M_MODE_ENABLE); + } + + /* Configure write and read DMA modes (77, 78) */ + WRITECSR(sc, R_WR_DMA_MODE, M_MODE_ENABLE | M_ATTN_ALL); + WRITECSR(sc, R_RD_DMA_MODE, M_MODE_ENABLE | M_ATTN_ALL); + + return 0; +} + +static int +t3_init_enable(t3_ether_t *sc) +{ + uint32_t mhc; + uint32_t pmcs; +#if T3_AUTOPOLL + uint32_t mode, mask; +#else + int i; +#endif + + /* Steps 79-97 */ + + /* Enable completion functional blocks (79-82) */ + WRITECSR(sc, R_RCV_COMP_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE); + if (sc->device != K_PCI_ID_BCM5705) { + WRITECSR(sc, R_MBUF_FREE_MODE, M_MODE_ENABLE); + } + WRITECSR(sc, R_SND_DATA_COMP_MODE, M_MODE_ENABLE); + WRITECSR(sc, R_SND_BD_COMP_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE); + + /* Enable initiator functional blocks (83-86) */ + WRITECSR(sc, R_RCV_BD_INIT_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE); + WRITECSR(sc, R_RCV_DATA_INIT_MODE, M_MODE_ENABLE | M_RCVINITMODE_RTNSIZE); + WRITECSR(sc, R_SND_DATA_MODE, M_MODE_ENABLE); + WRITECSR(sc, R_SND_BD_INIT_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE); + + /* Enable the send BD selector (87) */ + WRITECSR(sc, R_SND_BD_SEL_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE); + + /* Download firmware (88) - skipped */ + + /* Enable the MAC (89,90) */ + WRITECSR(sc, R_TX_MODE, M_MODE_ENABLE); /* optional flow control */ + WRITECSR(sc, R_RX_MODE, M_MODE_ENABLE); /* other options */ + + /* Disable auto-polling (91) */ + mii_access_init(sc); + + /* Configure power state (92) */ + pmcs = READCSR(sc, PCI_PMCSR_REG); + pmcs &= ~PCI_PMCSR_STATE_MASK; + pmcs |= PCI_PMCSR_STATE_D0; + WRITECSR(sc, PCI_PMCSR_REG, pmcs); + +#if T3_AUTOPOLL + /* Program hardware LED control (93) */ + WRITECSR(sc, R_MAC_LED_CTRL, 0x00); /* LEDs at PHY layer */ +#endif + +#if T3_AUTOPOLL + /* Ack/clear link change events */ + WRITECSR(sc, R_MAC_STATUS, M_LINKCHNG_CLR); + WRITECSR(sc, R_MI_STATUS, 0); + + /* Enable autopolling */ + mode = READCSR(sc, R_MI_MODE); + mode |= M_MIMODE_POLLING | 0x000c000; + WRITECSR(sc, R_MI_MODE, mode); + + /* Enable link state attentions */ + mask = READCSR(sc, R_MAC_EVENT_ENB); + mask |= M_EVT_LINKCHNG; + WRITECSR(sc, R_MAC_EVENT_ENB, mask); +#else + /* Initialize link (94) */ + WRITECSR(sc, R_MI_STATUS, M_MISTAT_LINKED); + + /* Start autonegotiation (95) - see t3_initlink below */ + + /* Setup multicast filters (96) */ + for (i = 0; i < 4; i++) + WRITECSR(sc, R_MAC_HASH(i), 0); +#endif /* T3_AUTOPOLL */ + + /* Enable interrupts (97) */ + mhc = READCSR(sc, R_MISC_HOST_CTRL); + mhc &= ~M_MHC_MASKPCIINT; + WRITECSR(sc, R_MISC_HOST_CTRL, mhc); + + return 0; +} + + +static void +t3_initlink(t3_ether_t *sc) +{ + uint32_t mcr; + + sc->phy_addr = mii_probe(sc); + if (sc->phy_addr < 0) { + xprintf("%s: no PHY found\n", t3_devname(sc)); + return; + } +#if T3_DEBUG + xprintf("%s: PHY addr %d\n", t3_devname(sc), sc->phy_addr); +#endif + if (1) /* XXX Support only autonegotiation for now */ + mii_autonegotiate(sc); + else + mii_set_speed(sc, ETHER_SPEED_10HDX); + + mii_enable_interrupts(sc); + + mcr = READCSR(sc, R_MODE_CTRL); + mcr |= M_MCTL_MACINT; + WRITECSR(sc, R_MODE_CTRL, mcr); + + sc->mii_polling = 0; + sc->phy_change = 0; +} + +static void +t3_shutdownlink(t3_ether_t *sc) +{ + uint32_t mcr; + + mcr = READCSR(sc, R_MODE_CTRL); + mcr &= ~M_MCTL_MACINT; + WRITECSR(sc, R_MODE_CTRL, mcr); + + WRITECSR(sc, R_MAC_EVENT_ENB, 0); + + /* The manual is fuzzy about what to do with the PHY at this + point. Empirically, resetting the 5705 PHY (but not others) + will cause it to get stuck in 10/100 MII mode. */ + if (sc->device != K_PCI_ID_BCM5705) + mii_write_register(sc, sc->phy_addr, MII_BMCR, BMCR_RESET); + + sc->mii_polling = 0; + sc->phy_change = 0; +} + + +static void +t3_hwinit(t3_ether_t *sc) +{ + if (sc->state != eth_state_on) { + + if (sc->state == eth_state_uninit) { + WRITECSR(sc, R_MEMWIN_BASE_ADDR, 0); /* Default memory window */ + t3_coldreset(sc); + } + else + t3_warmreset(sc); + + t3_init_registers(sc); + t3_init_pools(sc); + t3_init_rings(sc); + t3_configure_mac(sc); + t3_enable_stats(sc); + t3_init_coalescing(sc); + t3_init_dma(sc); + t3_init_enable(sc); +#if T3_DEBUG + dumpcsrs(sc, "end init"); +#else + (void)dumpcsrs; +#endif + + eeprom_access_init(sc); +#if T3_DEBUG + { + uint32_t eeprom[0x100/4]; + int i; + + cfe_sleep(1); + /* XXX Apparently a few reads can be required to get the + AutoAccess logic into a good state. ??? */ + for (i = 0; i < 4; i++) { + eeprom_read_range(sc, 0, 4, eeprom); + } + + eeprom_read_range(sc, 0, sizeof(eeprom), eeprom); + eeprom_dump_range("Boot Strap", eeprom, 0x00, 20); + eeprom_dump_range("Manufacturing Info", eeprom, 0x74, 140); + } +#else + (void)eeprom_read_range; + (void)eeprom_dump_range; +#endif + + t3_initlink(sc); + + sc->state = eth_state_off; + } +} + +static void +t3_hwshutdown(t3_ether_t *sc) +{ + /* Receive path shutdown */ + t3_clear(sc, R_RX_MODE, M_MODE_ENABLE); + t3_clear(sc, R_RCV_BD_INIT_MODE, M_MODE_ENABLE); + t3_clear(sc, R_RCV_LIST_MODE, M_MODE_ENABLE); + if (sc->device != K_PCI_ID_BCM5705) { + t3_clear(sc, R_RCV_LIST_SEL_MODE, M_MODE_ENABLE); + } + t3_clear(sc, R_RCV_DATA_INIT_MODE, M_MODE_ENABLE); + t3_clear(sc, R_RCV_COMP_MODE, M_MODE_ENABLE); + t3_clear(sc, R_RCV_BD_COMP_MODE, M_MODE_ENABLE); + + /* Transmit path shutdown */ + t3_clear(sc, R_SND_BD_SEL_MODE, M_MODE_ENABLE); + t3_clear(sc, R_SND_BD_INIT_MODE, M_MODE_ENABLE); + t3_clear(sc, R_SND_DATA_MODE, M_MODE_ENABLE); + t3_clear(sc, R_RD_DMA_MODE, M_MODE_ENABLE); + t3_clear(sc, R_SND_DATA_COMP_MODE, M_MODE_ENABLE); + if (sc->device != K_PCI_ID_BCM5705) { + t3_clear(sc, R_DMA_COMP_MODE, M_MODE_ENABLE); + } + t3_clear(sc, R_SND_BD_COMP_MODE, M_MODE_ENABLE); + t3_clear(sc, R_TX_MODE, M_MODE_ENABLE); + + /* Memory shutdown */ + t3_clear(sc, R_HOST_COAL_MODE, M_HCM_ENABLE); + t3_clear(sc, R_WR_DMA_MODE, M_MODE_ENABLE); + if (sc->device != K_PCI_ID_BCM5705) { + t3_clear(sc, R_MBUF_FREE_MODE, M_MODE_ENABLE); + } + WRITECSR(sc, R_FTQ_RESET, 0xFFFFFFFF); + cfe_sleep(1); + WRITECSR(sc, R_FTQ_RESET, 0x00000000); + t3_clear(sc, R_BMGR_MODE, M_BMODE_ENABLE); + t3_clear(sc, R_MEM_MODE, M_MAM_ENABLE); + + t3_shutdownlink(sc); + + WRITECSR(sc, R_MEMWIN_BASE_ADDR, 0); /* Default memory window */ + t3_coldreset(sc); + + sc->state = eth_state_uninit; +} + + +static void +t3_isr(void *arg) +{ + t3_ether_t *sc = (t3_ether_t *)arg; + volatile t3_status_t *status = sc->status; + uint32_t mac_status; + int handled; + + do { + WRITEMBOX(sc, R_INT_MBOX(0), 1); + + handled = 0; + mac_status = READCSR(sc, R_MAC_STATUS); /* force ordering */ + status->status &= ~M_STATUS_UPDATED; + + if (status->index[RI(1)].return_p != sc->rxr_1_index) { + handled = 1; + if (IPOLL) sc->rx_interrupts++; + t3_procrxring(sc); + } + + if (status->index[RI(1)].send_c != sc->txc_1_index) { + handled = 1; + if (IPOLL) sc->tx_interrupts++; + t3_proctxring(sc); + } + + if ((status->status & M_STATUS_LINKCHNG) != 0) { + handled = 1; +#if T3_AUTOPOLL + WRITECSR(sc, R_MAC_STATUS, M_LINKCHNG_CLR); +#endif + WRITECSR(sc, R_MAC_STATUS, M_EVT_MICOMPLETE); + + status->status &= ~M_STATUS_LINKCHNG; + sc->phy_change = 1; + } + + WRITEMBOX(sc, R_INT_MBOX(0), 0); + (void)READMBOX(sc, R_INT_MBOX(0)); /* push */ + +#if (!XPOLL) + if (!handled) + sc->bogus_interrupts++; +#endif + + } while ((status->status & M_STATUS_UPDATED) != 0); + + if (sc->rxp_std_index != sc->prev_rxp_std_index) { + sc->prev_rxp_std_index = sc->rxp_std_index; + WRITEMBOX(sc, R_RCV_BD_STD_PI, sc->rxp_std_index); + } +} + + +static void +t3_start(t3_ether_t *sc) +{ + t3_hwinit(sc); + + sc->intmask = 0; + +#if IPOLL + cfe_request_irq(sc->irq, t3_isr, sc, CFE_IRQ_FLAGS_SHARED, 0); + +#if T3_AUTOPOLL + sc->intmask |= M_EVT_LINKCHNG; +#else + sc->intmask |= M_EVT_LINKCHNG | M_EVT_MIINT; +#endif + WRITECSR(sc, R_MAC_EVENT_ENB, sc->intmask); +#endif + + /* Post some Rcv Producer buffers */ + sc->prev_rxp_std_index = sc->rxp_std_index; + WRITEMBOX(sc, R_RCV_BD_STD_PI, sc->rxp_std_index); + + sc->state = eth_state_on; +} + +static void +t3_stop(t3_ether_t *sc) +{ + WRITECSR(sc, R_MAC_EVENT_ENB, 0); + sc->intmask = 0; +#if IPOLL + cfe_free_irq(sc->irq, 0); +#endif + + if (sc->state == eth_state_on) { + sc->state = eth_state_off; + t3_hwshutdown(sc); + t3_reinit(sc); + } +} + + +static int t3_ether_open(cfe_devctx_t *ctx); +static int t3_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int t3_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int t3_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int t3_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int t3_ether_close(cfe_devctx_t *ctx); +static void t3_ether_poll(cfe_devctx_t *ctx, int64_t ticks); +static void t3_ether_reset(void *softc); + +const static cfe_devdisp_t t3_ether_dispatch = { + t3_ether_open, + t3_ether_read, + t3_ether_inpstat, + t3_ether_write, + t3_ether_ioctl, + t3_ether_close, + t3_ether_poll, + t3_ether_reset +}; + +cfe_driver_t bcm5700drv = { + "BCM570x Ethernet", + "eth", + CFE_DEV_NETWORK, + &t3_ether_dispatch, + t3_ether_probe +}; + + +static void +t3_delete_sc(t3_ether_t *sc) +{ + xprintf("BCM570x attach: No memory to complete probe\n"); + if (sc != NULL) { + if (sc->txp_1 != NULL) + KFREE(sc->txp_1); + if (sc->rxr_1 != NULL) + KFREE(sc->rxr_1); + if (sc->rxp_std != NULL) + KFREE(sc->rxp_std); + if (sc->stats != NULL) + KFREE(sc->stats); + if (sc->status != NULL) + KFREE((t3_ether_t *)sc->status); + KFREE(sc); + } +} + +static int +t3_ether_attach(cfe_driver_t *drv, pcitag_t tag, int index) +{ + t3_ether_t *sc; + char descr[80]; + phys_addr_t pa; + uint32_t base; + uint32_t pcictrl; + uint32_t addr; + pcireg_t device, class; + const char *devname; + int i; + + pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BITS, &pa); + base = (uint32_t)pa; + + sc = (t3_ether_t *) KMALLOC(sizeof(t3_ether_t), 0); + if (sc == NULL) { + t3_delete_sc(sc); + return 0; + } + + memset(sc, 0, sizeof(*sc)); + + sc->status = NULL; + sc->stats = NULL; + + device = pci_conf_read(tag, PCI_ID_REG); + class = pci_conf_read(tag, PCI_CLASS_REG); + sc->tag = tag; + sc->device = PCI_PRODUCT(device); + sc->revision = PCI_REVISION(class); + + sc->status = (t3_status_t *) KMALLOC(sizeof(t3_status_t), CACHE_ALIGN); + if (sc->status == NULL) { + t3_delete_sc(sc); + return 0; + } + + sc->stats = (t3_stats_t *) KMALLOC(sizeof(t3_stats_t), CACHE_ALIGN); + if (sc->stats == NULL) { + t3_delete_sc(sc); + return 0; + } + + if (sc->device == K_PCI_ID_BCM5705) + sc->rxr_entries = RXR_RING_ENTRIES_05; + else + sc->rxr_entries = RXR_RING_ENTRIES; + + sc->rxp_std = + (t3_rcv_bd_t *) KMALLOC(RXP_STD_ENTRIES*RCV_BD_SIZE, CACHE_ALIGN); + sc->rxr_1 = + (t3_rcv_bd_t *) KMALLOC(sc->rxr_entries*RCV_BD_SIZE, CACHE_ALIGN); + sc->txp_1 = + (t3_snd_bd_t *) KMALLOC(TXP_RING_ENTRIES*SND_BD_SIZE, CACHE_ALIGN); + if (sc->rxp_std == NULL || sc->rxr_1 == NULL || sc->txp_1 == NULL) { + t3_delete_sc(sc); + return 0; + } + + sc->regbase = base; + + /* NB: the relative base of memory depends on the access model */ + pcictrl = pci_conf_read(tag, R_PCI_STATE); +#if 0 /* XXX This gets spontaneously reset somehow! */ + if ((pcictrl & M_PCIS_FLATVIEW) != 0) + sc->membase = base + 0x01000000; /* Flat mode */ + else +#endif + sc->membase = base + 0x8000; /* Normal mode: 32K window */ + + sc->irq = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG) & 0xFF; + + sc->devctx = NULL; + + /* Assume on-chip firmware has initialized the MAC address. */ + addr = READCSR(sc, R_MAC_ADDR1_HIGH); + for (i = 0; i < 2; i++) + sc->hwaddr[i] = (addr >> (8*(1-i))) & 0xff; + addr = READCSR(sc, R_MAC_ADDR1_LOW); + for (i = 0; i < 4; i++) + sc->hwaddr[2+i] = (addr >> (8*(3-i))) & 0xff; + + t3_init(sc); + + sc->state = eth_state_uninit; + + switch (sc->device) { + case K_PCI_ID_BCM5700: + devname = "BCM5700"; break; + case K_PCI_ID_BCM5701: + devname = "BCM5701"; break; + case K_PCI_ID_BCM5702: + devname = "BCM5702"; break; + case K_PCI_ID_BCM5703: + devname = "BCM5703"; break; + case K_PCI_ID_BCM5705: + devname = "BCM5705"; break; + default: + devname = "BCM570x"; break; + } + xsprintf(descr, "%s Ethernet at 0x%X (%02X-%02X-%02X-%02X-%02X-%02X)", + devname, sc->regbase, + sc->hwaddr[0], sc->hwaddr[1], sc->hwaddr[2], + sc->hwaddr[3], sc->hwaddr[4], sc->hwaddr[5]); + + cfe_attach(drv, sc, NULL, descr); + return 1; +} + +static void +t3_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + int index; + int n; + + n = 0; + index = 0; + for (;;) { + pcitag_t tag; + pcireg_t device; + + if (pci_find_class(PCI_CLASS_NETWORK, index, &tag) != 0) + break; + + index++; + + device = pci_conf_read(tag, PCI_ID_REG); + if (PCI_VENDOR(device) == K_PCI_VENDOR_BROADCOM) { + switch (PCI_PRODUCT(device)) { + case K_PCI_ID_BCM5700: + case K_PCI_ID_BCM5701: + case K_PCI_ID_BCM5702: + case K_PCI_ID_BCM5703: + case K_PCI_ID_BCM5705: + t3_ether_attach(drv, tag, n); + n++; + break; + default: + break; + } + } + } +} + + +/* The functions below are called via the dispatch vector for the Tigon 3 */ + +static int +t3_ether_open(cfe_devctx_t *ctx) +{ + t3_ether_t *sc = ctx->dev_softc; + t3_stats_t *stats = sc->stats; + int i; + + if (sc->state == eth_state_on) + t3_stop(sc); + + sc->devctx = ctx; + + sc->rx_interrupts = sc->tx_interrupts = sc->bogus_interrupts = 0; + for (i = 0; i < L_MAC_STATS/sizeof(uint64_t); i++) + stats->stats[i] = 0; + + t3_start(sc); + + if (XPOLL) t3_isr(sc); + return 0; +} + +static int +t3_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + t3_ether_t *sc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + + if (XPOLL) t3_isr(sc); + + if (sc->state != eth_state_on) return -1; + + CS_ENTER(sc); + pkt = (eth_pkt_t *) q_deqnext(&(sc->rxqueue)); + CS_EXIT(sc); + + if (pkt == NULL) { + buffer->buf_retlen = 0; + return 0; + } + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + blockcopy(buffer->buf_ptr, pkt->buffer, blen); + buffer->buf_retlen = blen; + + eth_free_pkt(sc, pkt); + + if (XPOLL) t3_isr(sc); + return 0; +} + +static int +t3_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + t3_ether_t *sc = ctx->dev_softc; + + if (XPOLL) t3_isr(sc); + + if (sc->state != eth_state_on) return -1; + + /* We avoid an interlock here because the result is a hint and an + interrupt cannot turn a non-empty queue into an empty one. */ + inpstat->inp_status = (q_isempty(&(sc->rxqueue))) ? 0 : 1; + + return 0; +} + +static int +t3_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + t3_ether_t *sc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + + if (XPOLL) t3_isr(sc); + + if (sc->state != eth_state_on) return -1; + + pkt = eth_alloc_pkt(sc); + if (!pkt) return CFE_ERR_NOMEM; + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + blockcopy(pkt->buffer, buffer->buf_ptr, blen); + pkt->length = blen; + + if (t3_transmit(sc, pkt) != 0) { + eth_free_pkt(sc,pkt); + return CFE_ERR_IOERR; + } + + if (XPOLL) t3_isr(sc); + return 0; +} + +static int +t3_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + t3_ether_t *sc = ctx->dev_softc; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_ETHER_GETHWADDR: + memcpy(buffer->buf_ptr, sc->hwaddr, sizeof(sc->hwaddr)); + return 0; + + default: + return -1; + } +} + +static int +t3_ether_close(cfe_devctx_t *ctx) +{ + t3_ether_t *sc = ctx->dev_softc; + t3_stats_t *stats = sc->stats; + uint32_t inpkts, outpkts, interrupts; + int i; + + t3_stop(sc); + +#if T3_BRINGUP + for (i = 0; i < L_MAC_STATS/sizeof(uint64_t); i++) { + if (stats->stats[i] != 0) + xprintf(" stats[%d] = %8lld\n", i, stats->stats[i]); + } +#else + (void) i; +#endif + + inpkts = stats->stats[ifHCInUcastPkts] + + stats->stats[ifHCInMulticastPkts] + + stats->stats[ifHCInBroadcastPkts]; + outpkts = stats->stats[ifHCOutUcastPkts] + + stats->stats[ifHCOutMulticastPkts] + + stats->stats[ifHCOutBroadcastPkts]; + interrupts = stats->stats[nicInterrupts]; + + /* Empirically, counters on the 5705 are always zero. */ + if (sc->device != K_PCI_ID_BCM5705) { + xprintf("%s: %d sent, %d received, %d interrupts\n", + t3_devname(sc), outpkts, inpkts, interrupts); + if (IPOLL) { + xprintf(" %d rx interrupts, %d tx interrupts", + sc->rx_interrupts, sc->tx_interrupts); + if (sc->bogus_interrupts != 0) + xprintf(", %d bogus interrupts", sc->bogus_interrupts); + xprintf("\n"); + } + } + + sc->devctx = NULL; + return 0; +} + +static void +t3_ether_poll(cfe_devctx_t *ctx, int64_t ticks) +{ + t3_ether_t *sc = ctx->dev_softc; + int changed; + + if (sc->phy_change && sc->state != eth_state_uninit && !sc->mii_polling) { + uint32_t mask; + + sc->mii_polling++; + mask = READCSR(sc, R_MAC_EVENT_ENB); + WRITECSR(sc, R_MAC_EVENT_ENB, 0); + + changed = mii_poll(sc); + if (changed) { + mii_autonegotiate(sc); + } + sc->phy_change = 0; + sc->mii_polling--; + + WRITECSR(sc, R_MAC_EVENT_ENB, mask); + } +} + +static void +t3_ether_reset(void *softc) +{ + t3_ether_t *sc = (t3_ether_t *)softc; + + /* Turn off the Ethernet interface. */ + + if (sc->state == eth_state_on) + t3_stop(sc); + + sc->state = eth_state_uninit; +} diff --git a/cfe/cfe/dev/dev_bcm5821.c b/cfe/cfe/dev/dev_bcm5821.c new file mode 100644 index 0000000..3dede0f --- /dev/null +++ b/cfe/cfe/dev/dev_bcm5821.c @@ -0,0 +1,1592 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * BC5821 crypto accelerator driver File: dev_bcm5821.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* + CFE Driver plus test programs for the BCM5820 and BCM5821 crypto + coprocessor chips. + Reference: + BCM5821 Super-eCommerce Processor + Data Sheet 5821-DS105-D1 (draft, 7/26/02) + Broadcom Corp., 16215 Alton Parkway, Irvine, CA. +*/ + +/* The performance counter usage assumes a BCM11xx or BCM1250 part */ +#ifndef _SB14XX_ + +#include "sbmips.h" +#include "sb1250_defs.h" +#include "sb1250_regs.h" + +#ifndef _SB_MAKE64 +#define _SB_MAKE64(x) ((uint64_t)(x)) +#endif +#ifndef _SB_MAKEMASK1 +#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n)) +#endif + +#include "lib_types.h" +#include "lib_hssubr.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_queue.h" + +#include "addrspace.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_devfuncs.h" +#include "cfe_irq.h" + +#include "pcivar.h" +#include "pcireg.h" + +#include "bcm5821.h" + +/* The version that works by polling the CPU's Cause register doesn't + do handshakes or checks to detect merged interrupts. It currently + works when the 5821 is on the direct PCI bus but can behave + erratically when the 5821 is behind an LDT-to-PCI bridge that does + interrupt mapping and relies on EOI. */ + +extern int32_t _getcause(void); /* return value of CP0 CAUSE */ + +#define IMR_POINTER(cpu,reg) \ + ((volatile uint64_t *)(PHYS_TO_K1(A_IMR_REGISTER(cpu,reg)))) + +#define CACHE_LINE_SIZE 32 + +static void bcm5821_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +typedef struct bcm5821_state_s { + uint32_t regbase; + uint8_t irq; + pcitag_t tag; /* tag for configuration registers */ + + uint16_t device; /* chip device code */ + uint8_t revision; /* chip revision */ + +} bcm5821_state_t; + + +/* Address mapping macros */ + +/* Note that PTR_TO_PHYS only works with 32-bit addresses, but then + so does the bcm528x. */ +#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x))) +#define PHYS_TO_PTR(a) ((void *)PHYS_TO_K0(a)) + +/* For the 5821, all mappings through the PCI host bridge use match + bits mode. This works because the NORM_PCI bit in DMA Control is + clear. The 5820 does not have such a bit, so pointers to data byte + sequences use match bytes, but control blocks use match bits. */ +#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000) +#define PHYS_TO_PCI_D(a) (a) +#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF) + +#if __long64 +#define READCSR(sc,csr) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr))))) + +#define WRITECSR(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val)) +#else +#define READCSR(sc,csr) \ + (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) + +#define WRITECSR(sc,csr,val) \ + (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)), (val))) +#endif + +static void +dumpcsrs(bcm5821_state_t *sc, const char *legend) +{ + xprintf("%s:\n", legend); + xprintf("---DMA---\n"); + /* DMA control and status registers */ + xprintf("MCR1: %08X CTRL: %08X STAT: %08X ERR: %08X\n", + READCSR(sc, R_MCR1), READCSR(sc, R_DMA_CTRL), + READCSR(sc, R_DMA_STAT), READCSR(sc, R_DMA_ERR)); + xprintf("MCR2: %08X\n", READCSR(sc, R_MCR2)); + xprintf("-------------\n"); +} + + +static void +bcm5821_init(bcm5821_state_t *sc) +{ +} + +static void +bcm5821_hwinit(bcm5821_state_t *sc) +{ + uint32_t ctrl; + uint32_t status; + + ctrl = (M_DMA_CTRL_MCR1_INT_EN | M_DMA_CTRL_MCR2_INT_EN | + M_DMA_CTRL_DMAERR_EN); + if (sc->device == K_PCI_ID_BCM5820) + ctrl |= (M_DMA_CTRL_NORM_PCI | M_DMA_CTRL_LE_CRYPTO); + /* Note for 5821: M_DMA_CTRL_NORM_PCI, M_DMA_CTRL_LE_CRYPTO not set. */ +#if 0 /* Empirically, this reduces performance. */ + if (sc->device != K_PCI_ID_BCM5820) + ctrl |= M_DMA_CTRL_WR_BURST; +#endif + WRITECSR(sc, R_DMA_CTRL, ctrl); + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* reset write-to-clear bits */ + status = READCSR(sc, R_DMA_STAT); + + dumpcsrs(sc, "init"); +} + + +static void +bcm5821_start(bcm5821_state_t *sc) +{ + bcm5821_hwinit(sc); +} + +static void +bcm5821_stop(bcm5821_state_t *sc) +{ + WRITECSR(sc, R_DMA_CTRL, 0); +} + + +static int bcm5821_open(cfe_devctx_t *ctx); +static int bcm5821_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm5821_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int bcm5821_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm5821_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int bcm5821_close(cfe_devctx_t *ctx); + +const static cfe_devdisp_t bcm5821_dispatch = { + bcm5821_open, + bcm5821_read, + bcm5821_inpstat, + bcm5821_write, + bcm5821_ioctl, + bcm5821_close, + NULL, + NULL +}; + +cfe_driver_t bcm5821drv = { + "BCM582x crypto", + "crypt", + CFE_DEV_OTHER, + &bcm5821_dispatch, + bcm5821_probe +}; + + +static int +bcm5821_attach(cfe_driver_t *drv, pcitag_t tag, int index) +{ + bcm5821_state_t *sc; + char descr[80]; + phys_addr_t pa; + uint32_t base; + pcireg_t device, class; + + pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BITS, &pa); + base = (uint32_t)pa; + + sc = (bcm5821_state_t *) KMALLOC(sizeof(bcm5821_state_t),0); + if (sc == NULL) { + xprintf("BCM5821: No memory to complete probe\n"); + return 0; + } + + memset(sc, 0, sizeof(*sc)); + + sc->regbase = base; + + sc->irq = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG) & 0xFF; + + device = pci_conf_read(tag, PCI_ID_REG); + class = pci_conf_read(tag, PCI_CLASS_REG); + + sc->tag = tag; + sc->device = PCI_PRODUCT(device); + sc->revision = PCI_REVISION(class); + + bcm5821_init(sc); + + xsprintf(descr, "BCM%04X Crypto at 0x%08X", sc->device, base); + cfe_attach(drv, sc, NULL, descr); + + return 1; +} + +static void +bcm5821_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + int index; + int n; + + n = 0; + index = 0; + for (;;) { + pcitag_t tag; + pcireg_t device; + + if (pci_find_class(PCI_CLASS_PROCESSOR, index, &tag) != 0) + break; + + index++; + + device = pci_conf_read(tag, PCI_ID_REG); + if (PCI_VENDOR(device) == K_PCI_VENDOR_BROADCOM) { + if (PCI_PRODUCT(device) == K_PCI_ID_BCM5820 || + PCI_PRODUCT(device) == K_PCI_ID_BCM5821) { + bcm5821_attach(drv, tag, n); + n++; + } + } + } +} + + +/* The functions below are called via the dispatch vector for the 5821 */ + +static int +bcm5821_open(cfe_devctx_t *ctx) +{ + bcm5821_state_t *sc = ctx->dev_softc; + + bcm5821_start(sc); + return 0; +} + +static int +bcm5821_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + return -1; +} + +static int +bcm5821_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + return 0; +} + +static int +bcm5821_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + return -1; +} + +static int +bcm5821_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + return -1; +} + +static int +bcm5821_close(cfe_devctx_t *ctx) +{ + bcm5821_state_t *sc = ctx->dev_softc; + + bcm5821_stop(sc); + return 0; +} + + +/* Additional hooks for testing. */ + +static int +bcm5821_dump_cc1 (uint32_t *cc) +{ + int i; + unsigned op = G_CC_OPCODE(cc[0]); + unsigned cc_words = G_CC_LEN(cc[0])/4; + int chain_out; /* Whether the output is chained or fixed */ + + chain_out = 1; /* default */ + + switch (op) { + + case K_SSL_MAC: + xprintf("(SSL_MAC)\n"); + for (i = 0; i < SSL_MAC_CMD_WORDS; i++) + xprintf(" %2d: %08x\n", i, cc[i]); + chain_out = 0; + break; + + case K_ARC4: + xprintf("(ARCFOUR)\n"); + for (i = 0; i < 3; i++) + xprintf(" %2d: %08x\n", i, cc[i]); + for (i = 0; i < 256/4; i += 4) + xprintf(" %2d: %08x %08x %08x %08x\n", + i+3, cc[i+3], cc[i+4], cc[i+5], cc[i+6]); + break; + + case K_HASH: + xprintf("(HASH)\n"); + for (i = 0; i < 2; i++) + xprintf(" %2d: %08x\n", i, cc[i]); + chain_out = 0; + break; + + case K_TLS_HMAC: + chain_out = 0; + /* fall through */ + + default: /* NYI: K_IPSEC_3DES (5821 only), K_SSL_3DES */ + xprintf("\n"); + for (i = 0; i < cc_words; i++) + xprintf(" %2d: %08x\n", i, cc[i]); + break; + } + + return chain_out; +} + +static int +bcm5821_dump_cc2 (uint32_t *cc) +{ + int i; + unsigned op = G_CC_OPCODE(cc[0]); + unsigned cc_words = G_CC_LEN(cc[0])/4; + int chain_out; /* Whether the output is chained or fixed */ + + chain_out = 1; /* default */ + + switch (op) { + + case K_RNG_DIRECT: + xprintf(" RNG_DIRECT\n"); + chain_out = 0; + for (i = 0; i < 1; i++) + xprintf(" %2d: %08x\n", i, cc[i]); + break; + + case K_RNG_SHA1: + xprintf(" RNG_SHA1\n"); + chain_out = 0; + for (i = 0; i < 1; i++) + xprintf(" %2d: %08x\n", i, cc[i]); + break; + + default: /* NYI: K_DH_*_GEN, K_RSA_*_OP, K_DSA_*, K_MOD_* */ + xprintf(" %04x\n", op); + for (i = 0; i < cc_words; i++) + xprintf(" %2d: %08x\n", i, cc[i]); + break; + } + return chain_out; +} + +static void +bcm5821_dump_pkt (uint32_t *pkt, int port) +{ + uint32_t *cc = PHYS_TO_PTR(PCI_TO_PHYS(pkt[0])); + uint32_t *chain; + int chain_out; + int i, j; + + xprintf(" %2d: %08x ", 0, pkt[0]); + chain_out = (port == 1 ? bcm5821_dump_cc1 : bcm5821_dump_cc2)(cc); + + for (i = 1; i < PD_SIZE/4; i++) { + xprintf(" %2d: %08x\n", i, pkt[i]); + + if (pkt[i] != 0) { + switch (i) { + case 2: + chain = PHYS_TO_PTR(PCI_TO_PHYS(pkt[i])); + for (j = 0; j < CHAIN_WORDS; j++) + xprintf(" %2d: %08x\n", j, chain[j]); + break; + case 6: + if (chain_out) { + chain = PHYS_TO_PTR(PCI_TO_PHYS(pkt[i])); + for (j = 0; j < CHAIN_WORDS; j++) + xprintf(" %2d: %08x\n", j, chain[j]); + } + break; + default: + break; + } + } + } +} + +static void +bcm5821_dump_mcr (uint32_t mcr[], int port) +{ + unsigned i; + unsigned npkts = G_MCR_NUM_PACKETS(mcr[0]); + + xprintf("MCR header %08x at %p:\n", mcr[0], mcr); + for (i = 0; i < npkts; i++) { + xprintf(" packet %d:\n", i+1); + bcm5821_dump_pkt(&mcr[1 + i*(PD_SIZE/4)], port); + } +} + + +static void +bcm5821_show_pkt1 (uint32_t *pkt) +{ + uint32_t *cc = PHYS_TO_PTR(PCI_TO_PHYS(pkt[0])); + unsigned op = G_CC_OPCODE(cc[0]); + int i; + + switch (op) { + case K_SSL_MAC: + { + uint32_t *hash = PHYS_TO_PTR(PCI_TO_PHYS(pkt[6])); + xprintf("SSL_MAC hash:\n"); + xprintf(" %08x %08x %08x %08x\n", + hash[0], hash[1], hash[2], hash[3]); + xprintf(" %08x\n", hash[4]); + } + break; + case K_TLS_HMAC: + { + uint32_t *hash = PHYS_TO_PTR(PCI_TO_PHYS(pkt[7])); + xprintf("TLS_HMAC hash:\n"); + xprintf(" %08x %08x %08x %08x\n", + hash[0], hash[1], hash[2], hash[3]); + xprintf(" %08x\n", hash[4]); + } + break; + case K_ARC4: + { + uint32_t *output = PHYS_TO_PTR(PCI_TO_PHYS(pkt[5])); + uint32_t *chain = PHYS_TO_PTR(PCI_TO_PHYS(pkt[6])); + uint32_t *update = PHYS_TO_PTR(PCI_TO_PHYS(chain[0])); + + xprintf("ARCFOUR output\n"); + for (i = 0; i < 64; i += 4) + xprintf (" %08x %08x %08x %08x\n", + output[i+0], output[i+1], output[i+2], output[i+3]); + xprintf("ARCFOUR update\n"); + xprintf(" %08x\n", update[0]); + for (i = 0; i < 256/4; i += 4) + xprintf (" %08x %08x %08x %08x\n", + update[i+1], update[i+2], update[i+3], update[i+4]); + } + break; + case K_HASH: + { + uint8_t *digest = PHYS_TO_PTR(PCI_TO_PHYS(pkt[6])); + + xprintf("HASH digest "); + for (i = 0; i < 16; i++) + xprintf("%02x", digest[i]); + xprintf("\n"); + } + break; + default: + break; + } +} + +static void +bcm5821_show_pkt2 (uint32_t *pkt) +{ + uint32_t *cc = PHYS_TO_PTR(PCI_TO_PHYS(pkt[0])); + unsigned op = G_CC_OPCODE(cc[0]); + int i; + + switch (op) { + case K_RNG_DIRECT: + case K_RNG_SHA1: + { + uint32_t *output = PHYS_TO_PTR(PCI_TO_PHYS(pkt[5])); + size_t len = V_DBC_DATA_LEN(pkt[7])/sizeof(uint32_t); + + xprintf("RNG output\n"); + for (i = 0; i < len; i += 4) + xprintf (" %08x %08x %08x %08x\n", + output[i+0], output[i+1], output[i+2], output[i+3]); + } + break; + default: + break; + } +} + +static void +bcm5821_show_mcr (uint32_t mcr[], int port) +{ + unsigned i; + unsigned npkts = G_MCR_NUM_PACKETS(mcr[0]); + + xprintf("MCR at %p:\n", mcr); + for (i = 0; i < npkts; i++) { + xprintf("packet %d:\n", i+1); + if (port == 1) + bcm5821_show_pkt1(&mcr[1 + i*(PD_SIZE/4)]); + else + bcm5821_show_pkt2(&mcr[1 + i*(PD_SIZE/4)]); + } +} + + +static uint32_t * +bcm5821_alloc_hash (const uint8_t *msg, size_t msg_len, int swap) +{ + uint32_t *mcr; + uint32_t *cmd; /* always reads at least 64 bytes */ + uint8_t *message; + uint8_t *digest; + int i; + + message = KMALLOC(msg_len, CACHE_LINE_SIZE); + for (i = 0; i < msg_len; i++) + message[i] = msg[i]; + + digest = KMALLOC(16, CACHE_LINE_SIZE); + for (i = 0; i < 16; i++) + digest[i] = 0; + + mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE); + mcr[0] = V_MCR_NUM_PACKETS(1); + + cmd = KMALLOC(64, CACHE_LINE_SIZE); /* Always allocate >= 64 bytes */ + cmd[0] = V_CC_OPCODE(K_HASH) | V_CC_LEN(8); + cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5); + + mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd)); + + /* input fragment */ + mcr[2] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(message)) + : PHYS_TO_PCI(PTR_TO_PHYS(message)); + mcr[3] = 0; + mcr[4] = V_DBC_DATA_LEN(msg_len); + + mcr[5] = V_PD_PKT_LEN(msg_len); + + mcr[6] = 0; + mcr[7] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(digest)) + : PHYS_TO_PCI(PTR_TO_PHYS(digest)); + mcr[8] = 0; + + return mcr; +} + +static void +bcm5821_free_hash (uint32_t mcr[]) +{ + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[1]))); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[2]))); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[7]))); + + KFREE(mcr); +} + + +static uint32_t * +bcm5821_alloc_hmac (const char *key, int key_len, + const char *msg, int msg_len, + int swap) +{ + uint32_t *message; + uint32_t *cmd; + uint32_t *mcr; + uint32_t *hash; + int i; + + message = KMALLOC(msg_len, CACHE_LINE_SIZE); + memcpy((uint8_t *)message, msg, msg_len); + + mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE); + mcr[0] = V_MCR_NUM_PACKETS(1); + + /* packet 1 */ + + cmd = KMALLOC(TLS_HMAC_CMD_WORDS*4, CACHE_LINE_SIZE); + cmd[0] = V_CC_OPCODE(K_TLS_HMAC) | V_CC_LEN(TLS_HMAC_CMD_WORDS*4); + cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5); + + /* XXX This is not correct. The key is used to compute the inner + and outer states. */ + for (i = 2; i < 7; i++) + cmd[i] = 0x36363636; /* XXX MAC write secret */ + cmd[6] = 0x00000000; /* must be zero for SSL */ + for (i = 8; i < 13; i++) + cmd[i] = 0x5c5c5c5c; + cmd[13] = 0; /* seq num */ + cmd[14] = 1; + cmd[15] = 0x03000000 | (msg_len << 8); /* XXX type/len/rsvd */ + + mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd)); + + /* input fragment */ + mcr[2] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(message)) + : PHYS_TO_PCI(PTR_TO_PHYS(message)); + mcr[3] = 0; + mcr[4] = V_DBC_DATA_LEN(msg_len); + + mcr[5] = V_PD_PKT_LEN(msg_len); + + hash = KMALLOC(5*4, CACHE_LINE_SIZE); + for (i = 0; i < 5; i++) + hash[i] = 0; + + mcr[6] = 0; + mcr[7] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(hash)) + : PHYS_TO_PCI(PTR_TO_PHYS(hash)); + mcr[8] = 0; + + return mcr; +} + +static void +bcm5821_free_hmac (uint32_t mcr[]) +{ + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[1]))); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[2]))); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[7]))); + + KFREE(mcr); +} + + +static int test_init = 0; + +/* Timing */ + +/* For Pass 1, dedicate an SCD peformance counter to use as a counter + of ZBbus cycles. */ +#include "sb1250_scd.h" +#define ZCTR_MODULUS 0x10000000000LL + +/* The counter is a shared resource that must be reset periodically + since it doesn't roll over. Furthermore, there is a pass one bug + that makes the interrupt unreliable and the final value either all + ones or all zeros. We therefore reset the count when it exceeds + half the modulus. We also assume that intervals of interest + are much less than half the modulus and attempt to adjust for + the reset in zclk_elapsed. */ + +static void +zclk_init(uint64_t val) +{ + *((volatile uint64_t *) UNCADDR(A_SCD_PERF_CNT_0)) = val; + *((volatile uint64_t *) UNCADDR(A_SCD_PERF_CNT_CFG)) = + V_SPC_CFG_SRC0(1) | M_SPC_CFG_ENABLE; +} + +static uint64_t +zclk_get(void) +{ + uint64_t ticks; + + ticks = *((volatile uint64_t *) UNCADDR(A_SCD_PERF_CNT_0)); + if (ticks == 0 || ticks == ZCTR_MODULUS-1) { + ticks = 0; + zclk_init(ticks); + } + else if (ticks >= ZCTR_MODULUS/2) { + ticks -= ZCTR_MODULUS/2; + zclk_init(ticks); /* Ignore the fudge and lose a few ticks */ + } + return ticks; +} + +static uint64_t +zclk_elapsed(uint64_t stop, uint64_t start) +{ + return ((stop >= start) ? stop : stop + ZCTR_MODULUS/2) - start; +} + + +/* Auxiliary functions */ + +static uint32_t * +bcm5821_alloc_composite(int input_size) +{ + uint32_t *input, *output; + uint32_t *cmd; + uint32_t *chain; + uint32_t *mcr; + uint32_t *hash; + uint32_t *update; + uint8_t *arc4_state; + int i; + + input = KMALLOC(input_size, CACHE_LINE_SIZE); + for (i = 0; i < input_size; i++) + ((uint8_t *)input)[i] = i & 0xFF; + output = KMALLOC(input_size + 16, CACHE_LINE_SIZE); + for (i = 0; i < input_size + 16; i++) + ((uint8_t *)output)[i] = 0xFF; + + mcr = KMALLOC(MCR_WORDS(2)*4, CACHE_LINE_SIZE); + mcr[0] = V_MCR_NUM_PACKETS(2); + + /* packet 1 */ + + cmd = KMALLOC(SSL_MAC_CMD_WORDS*4, CACHE_LINE_SIZE); + cmd[0] = V_CC_OPCODE(K_SSL_MAC) | V_CC_LEN(SSL_MAC_CMD_WORDS*4); + cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5); + for (i = 2; i < 6; i++) + cmd[i] = 0x01020304; /* XXX MAC write secret */ + cmd[6] = 0x00000000; /* must be zero for SSL */ + for (i = 7; i < 19; i++) + cmd[i] = 0x36363636; + cmd[19] = 0; /* seq num */ + cmd[20] = 1; + cmd[21] = 0x03000000 | (input_size << 8); /* type/len/rsvd */ + + mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd)); + + /* input fragment */ + mcr[2] = PHYS_TO_PCI(PTR_TO_PHYS(input)); + mcr[3] = 0; + mcr[4] = V_DBC_DATA_LEN(input_size); + + mcr[5] = V_PD_PKT_LEN(input_size); + + hash = KMALLOC(5*4, CACHE_LINE_SIZE); + for (i = 0; i < 5; i++) + hash[i] = 0; + + mcr[6] = 0; + mcr[7] = PHYS_TO_PCI(PTR_TO_PHYS(hash)); + mcr[8] = 0; + + /* packet 2 */ + + cmd = KMALLOC(ARC4_CMD_WORDS*4, CACHE_LINE_SIZE); + cmd[0] = V_CC_OPCODE(K_ARC4) | V_CC_LEN(ARC4_CMD_WORDS*4); + cmd[1] = M_ARC4_FLAGS_WRITEBACK; + cmd[2] = 0x000100F3; + arc4_state = (uint8_t *)&cmd[3]; + for (i = 0; i < 256; i++) + arc4_state[i] = i; + + mcr[8+1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd)); + + /* input fragment */ + chain = KMALLOC(CHAIN_WORDS*4, CACHE_LINE_SIZE); + + mcr[8+2] = PHYS_TO_PCI(PTR_TO_PHYS(input)); + mcr[8+3] = PHYS_TO_PCI(PTR_TO_PHYS(chain)); + mcr[8+4] = V_DBC_DATA_LEN(input_size); + + /* MAC fragment */ + chain[0] = PHYS_TO_PCI(PTR_TO_PHYS(hash)); + chain[1] = 0; + chain[2] = V_DBC_DATA_LEN(16); + + mcr[8+5] = V_PD_PKT_LEN(input_size + 16); + + /* output fragment */ + chain = KMALLOC(CHAIN_WORDS*4, CACHE_LINE_SIZE); + + mcr[8+6] = PHYS_TO_PCI(PTR_TO_PHYS(output)); + mcr[8+7] = PHYS_TO_PCI(PTR_TO_PHYS(chain)); + mcr[8+8] = V_DBC_DATA_LEN(input_size + 16); + + update = KMALLOC(ARC4_STATE_WORDS*4, CACHE_LINE_SIZE); + for (i = 0; i < ARC4_STATE_WORDS; i++) + update[i] = 0xFFFFFFFF; + + /* output update */ + chain[0] = PHYS_TO_PCI(PTR_TO_PHYS(update)); + chain[1] = 0; + chain[2] = V_DBC_DATA_LEN(ARC4_STATE_WORDS*4); /* not actually used */ + + return mcr; +} + +static void +bcm5821_free_composite (uint32_t mcr[]) +{ + uint32_t *chain; + + /* packet 1 */ + + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[1]))); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[2]))); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[7]))); + + /* packet 2 */ + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+1]))); + /* mcr[8+2] already freed */ + chain = PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+3])); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(chain[0]))); KFREE(chain); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+6]))); + chain = PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+7])); + KFREE(PHYS_TO_PTR(PCI_TO_PHYS(chain[0]))); KFREE(chain); + + KFREE(mcr); +} + + +static void +flush_l2(void) +{ + /* Temporary hack: churn through all of L2 */ + volatile uint64_t *lomem; + uint64_t t; + int i; + + lomem = (uint64_t *)(0xFFFFFFFF80000000LL); /* kseg0 @ 0 */ + t = 0; + for (i = 0; i < (512/8)*1024; i++) + t ^= lomem[i]; +} + +#ifdef IRQ +static void +bcm5821_interrupt(void *ctx) +{ +} +#endif + + +#define POOL_SIZE 4 +#define MCR_QUEUE_DEPTH 2 + +static int +bcm5821_composite (bcm5821_state_t *sc, size_t len, int trials) +{ + uint32_t *mcr[POOL_SIZE]; + uint32_t status; + uint64_t start, stop, ticks; + uint64_t tpb, Mbs; + int i; + int next, last, run; + + for (i = 0; i < POOL_SIZE; i++) + mcr[i] = bcm5821_alloc_composite(len); + + (void)bcm5821_dump_mcr; /*bcm5821_dump_mcr(mcr[0], 1);*/ + + next = last = 0; + run = 0; + + /* Force all descriptors and buffers out of L1 */ + cfe_flushcache(CFE_CACHE_FLUSH_D); + (void)flush_l2; /* XXX for now */ + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + status = READCSR(sc, R_DMA_STAT); + + for (i = 0; i < 1000; i++) { + status = READCSR(sc, R_DMA_STAT); + if ((status & M_DMA_STAT_MCR1_FULL) == 0) + break; + cfe_sleep(1); + } + if (i == 1000) { + dumpcsrs(sc, "bcm5821: full bit never clears"); + return -1; + } + +#ifdef IRQ + /* Enable interrupt polling, but the handler is never called. */ + cfe_request_irq(sc->irq, bcm5821_interrupt, NULL, 0, 0); +#endif + + zclk_init(0); /* Time origin is arbitrary. */ + start = zclk_get(); + + /* MCR ports are double buffered. */ + for (i = 0; i < MCR_QUEUE_DEPTH; i++) { + while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0) + continue; + WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[next]))); + next = (next + 1) % POOL_SIZE; + } + + while (1) { +#ifdef IRQ + while ((_getcause() & M_CAUSE_IP2) == 0) + continue; + + status = READCSR(sc, R_DMA_STAT); + if ((status & M_DMA_STAT_MCR1_INTR) == 0) { + /* This apparently is MCR1_ALL_EMPTY, timing of which is unclear. */ + WRITECSR(sc, R_DMA_STAT, + M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR); + continue; + } + + stop = zclk_get(); + WRITECSR(sc, R_DMA_STAT, + M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR); +#else + volatile uint32_t *last_mcr = mcr[last]; + + while ((*last_mcr & M_MCR_DONE) == 0) + continue; + + stop = zclk_get(); +#endif + + run++; + if (run == trials) + break; + + while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0) + continue; + WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[next]))); + next = (next + 1) % POOL_SIZE; + + /* Clear the DONE and ERROR bits. This will bring one line of + the MCR back into L1. Flush? */ + mcr[last][0] = V_MCR_NUM_PACKETS(2); + last = (last + 1) % POOL_SIZE; + } + +#ifdef IRQ + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + cfe_free_irq(sc->irq, 0); +#endif + + ticks = zclk_elapsed(stop, start) / trials; + xprintf("bcm5821: Composite %lld ticks for %d bytes, %d packets\n", + ticks, len, trials); + /* Scaling for two decimal places. */ + tpb = (ticks*100) / len; + Mbs = (2000*100)*100 / tpb; + xprintf(" rate %lld.%02lld Mbps\n", Mbs/100, Mbs % 100); + + if (trials == 1) + { + bcm5821_show_mcr(mcr[0], 1); + } + + for (i = 0; i < POOL_SIZE; i++) + bcm5821_free_composite(mcr[i]); + + return 0; +} + + +/* The following code depends on having a separate interrupt per + device, and there are only 4 PCI interrupts. */ +#define MAX_DEVICES 4 + +struct dev_info { + bcm5821_state_t *sc; + uint64_t irq_mask; + int index[MCR_QUEUE_DEPTH]; +}; + + +#define N_DEVICES 2 + +static int +bcm5821_composite2 (bcm5821_state_t *sc0, bcm5821_state_t *sc1, + size_t len, int trials) +{ + uint32_t *mcr[POOL_SIZE]; + uint32_t ring[POOL_SIZE]; + uint32_t status; + uint64_t start, stop, ticks; + uint64_t tpb, Mbs; + int i; + int next, last; + int started, run; + int d; + struct dev_info dev[N_DEVICES]; + uint64_t masks; + bcm5821_state_t *sc; +#ifdef IRQ + volatile uint64_t *irqstat = IMR_POINTER(0, R_IMR_INTERRUPT_SOURCE_STATUS); +#endif + uint64_t pending; + + dev[0].sc = sc0; dev[1].sc = sc1; + + for (i = 0; i < POOL_SIZE; i++) + mcr[i] = bcm5821_alloc_composite(len); + for (i = 0; i < POOL_SIZE; i++) + ring[i] = i; + next = last = 0; + + (void)bcm5821_dump_mcr; /*bcm5821_dump_mcr(mcr[0], 1);*/ + + started = run = 0; + + /* Force all descriptors and buffers out of L1 */ + cfe_flushcache(CFE_CACHE_FLUSH_D); + (void)flush_l2; /* XXX for now */ + + masks = 0; + for (d = 0; d < N_DEVICES; d++) { + sc = dev[d].sc; + dev[d].irq_mask = 1LL << (sc->irq); + masks |= dev[d].irq_mask; + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + status = READCSR(sc, R_DMA_STAT); + + for (i = 0; i < 1000; i++) { + status = READCSR(sc, R_DMA_STAT); + if ((status & M_DMA_STAT_MCR1_FULL) == 0) + break; + cfe_sleep(1); + } + + if (i == 1000) { + dumpcsrs(sc, "bcm5821: full bit never clears"); + return -1; + } + +#ifdef IRQ + /* Enable interrupt polling, but the handler is never called. */ + cfe_request_irq(sc->irq, bcm5821_interrupt, NULL, 0, 0); +#endif + } + + stop = 0; /* Keep compiler happy */ + zclk_init(0); /* Time origin is arbitrary. */ + start = zclk_get(); + + for (d = 0; d < N_DEVICES; d++) { + sc = dev[d].sc; + + /* MCR ports are double buffered. */ + for (i = 0; i < 2; i++) { + int index = ring[next]; + while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0) + continue; + WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[index]))); + dev[d].index[i] = index; + next = (next + 1) % POOL_SIZE; + started++; + } + } + + while (trials == 0 || run != trials) { +#ifdef IRQ + while ((_getcause() & M_CAUSE_IP2) == 0) + continue; + + pending = *irqstat; +#else + pending = 0; + while (pending == 0) { + for (d = 0; d < N_DEVICES; d++) { + volatile uint32_t *last_mcr = mcr[dev[d].index[0]]; + + if ((*last_mcr & M_MCR_DONE) != 0) + pending |= dev[d].irq_mask; + } + } +#endif + + stop = zclk_get(); + + for (d = 0; d < N_DEVICES; d++) { + if ((dev[d].irq_mask & pending) != 0) { + sc = dev[d].sc; + +#ifdef IRQ + status = READCSR(sc, R_DMA_STAT); + if ((status & M_DMA_STAT_MCR1_INTR) == 0) { + /* Apparently MCR1_ALL_EMPTY, timing of which is unclear. */ + WRITECSR(sc, R_DMA_STAT, + M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR); + continue; + } + WRITECSR(sc, R_DMA_STAT, + M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR); +#endif + ring[last] = dev[d].index[0]; + /* Clear the DONE and ERROR bits. This will bring one line of + the MCR back into L1. Flush? */ + mcr[ring[last]][0] = V_MCR_NUM_PACKETS(2); + last = (last + 1) % POOL_SIZE; + + run++; + if (run == trials) + break; + + dev[d].index[0] = dev[d].index[1]; + if (trials == 0 || started < trials) { + int index = ring[next]; + while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0) + continue; + WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[index]))); + dev[d].index[1] = index; + next = (next + 1) % POOL_SIZE; + started++; + } + } + } + } + + for (d = 0; d < N_DEVICES; d++) { + sc = dev[d].sc; + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ +#ifdef IRQ + cfe_free_irq(sc->irq, 0); +#endif + } + + ticks = zclk_elapsed(stop, start) / trials; + xprintf("bcm5821: Composite %lld ticks for %d bytes, %d packets\n", + ticks, len, trials); + /* Scaling for two decimal places. */ + tpb = (ticks*100) / len; + Mbs = (2000*100)*100 / tpb; + xprintf(" rate %lld.%02lld Mbps\n", Mbs/100, Mbs % 100); + + for (i = 0; i < POOL_SIZE; i++) + bcm5821_free_composite(mcr[i]); + + return 0; +} + + +extern cfe_devctx_t *cfe_handle_table[]; + +int bcm5821_test (int device, int trials); +int +bcm5821_test (int device, int trials) +{ + cfe_devctx_t *ctx = cfe_handle_table[device]; + bcm5821_state_t *sc = ctx->dev_softc; + + if (!test_init) { + zclk_init(0); /* Time origin is arbitrary */ + test_init = 1; + } + + bcm5821_composite(sc, 1472, trials); + + return 0; +} + +int bcm5821_test2 (int device0, int device2, int trials); +int +bcm5821_test2 (int device0, int device1, int trials) +{ + cfe_devctx_t *ctx0 = cfe_handle_table[device0]; + cfe_devctx_t *ctx1 = cfe_handle_table[device1]; + bcm5821_state_t *sc0 = ctx0->dev_softc; + bcm5821_state_t *sc1 = ctx1->dev_softc; + + if (!test_init) { + zclk_init(0); /* Time origin is arbitrary */ + test_init = 1; + } + + bcm5821_composite2(sc0, sc1, 1472, trials); + + return 0; +} + + +static int +bcm5821_hash_md5 (bcm5821_state_t *sc, const char *msg) +{ + size_t len = strlen(msg); + uint32_t *mcr; + uint32_t status; + int i; + int swap = (sc->device == K_PCI_ID_BCM5820); + + mcr = bcm5821_alloc_hash(msg, len, swap); + + /* bcm5821_dump_mcr(mcr, 1); */ + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + status = READCSR(sc, R_DMA_STAT); + + for (i = 0; i < 1000; i++) { + status = READCSR(sc, R_DMA_STAT); + if ((status & M_DMA_STAT_MCR1_FULL) == 0) + break; + cfe_sleep(1); + } + if (i == 1000) { + dumpcsrs(sc, "bcm5821: full bit never clears"); + return -1; + } + + WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr))); + + for (i = 0; i < 1000; i++) { +#ifdef IRQ + status = READCSR(sc, R_DMA_STAT); + if ((status & M_DMA_STAT_MCR1_INTR) != 0) + break; +#else + if ((mcr[0] & M_MCR_DONE) != 0) + break; +#endif + cfe_sleep(1); + } + if (i == 1000) { + dumpcsrs(sc, "bcm5821: done bit never sets"); + /*return -1;*/ + } + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + + /* bcm5821_dump_mcr(mcr, 1); */ + + bcm5821_show_mcr(mcr, 1); + + bcm5821_free_hash(mcr); + + return 0; +} + + +static int +bcm5821_hmac_md5 (bcm5821_state_t *sc, + const uint8_t key[], size_t key_len, + const uint8_t data[], size_t data_len) +{ + uint32_t *mcr; + uint32_t status; + int i; + int swap = (sc->device == K_PCI_ID_BCM5820); + + mcr = bcm5821_alloc_hmac(key, key_len, data, data_len, swap); + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + status = READCSR(sc, R_DMA_STAT); + + for (i = 0; i < 1000; i++) { + status = READCSR(sc, R_DMA_STAT); + if ((status & M_DMA_STAT_MCR1_FULL) == 0) + break; + cfe_sleep(1); + } + if (i == 1000) { + dumpcsrs(sc, "bcm5821: full bit never clears"); + return -1; + } +#if 0 /* disable: work in progress */ + + while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0) + continue; + WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr))); + + for (i = 0; i < 1000; i++) { + if ((mcr[0] & M_MCR_DONE) != 0) + break; + cfe_sleep(1); + } + if (i == 1000) { + dumpcsrs(sc, "bcm5821: done bit never sets"); + return -1; + } + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + + bcm5821_show_mcr(mcr, 1); +#endif + + bcm5821_free_hmac(mcr); + return 0; +} + +/* Sanity check on the implementation using RFC test suites. */ + +int bcm5821_check (int device); +int +bcm5821_check (int device) +{ + static unsigned char k1[16] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }; + static unsigned char m1[] = "Hi There"; + + static unsigned char k2[] = "Jefe"; + static unsigned char m2[] = "what do ya want for nothing?"; + + static unsigned char k3[16] = { + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA + }; + static unsigned char m3[50] = { + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD + }; + + cfe_devctx_t *ctx = cfe_handle_table[device]; + bcm5821_state_t *sc = ctx->dev_softc; + + if (!test_init) { + zclk_init(0); /* Time origin is arbitrary */ + test_init = 1; + } + +#if 0 /* 5821 cannot handle 0-length fragments (see Appendix B) */ + bcm5821_hash_md5(sc, ""); +#endif + bcm5821_hash_md5(sc, "a"); + bcm5821_hash_md5(sc, "abc"); + bcm5821_hash_md5(sc, "message digest"); + bcm5821_hash_md5(sc, "abcdefghijklmnopqrstuvwxyz"); + bcm5821_hash_md5(sc, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + bcm5821_hash_md5(sc, "12345678901234567890123456789012345678901234567890123456789012345678901234567890"); + + bcm5821_hmac_md5(sc, k1, sizeof(k1), m1, strlen(m1)); + bcm5821_hmac_md5(sc, k2, strlen(k2), m2, strlen(m2)); + bcm5821_hmac_md5(sc, k3, sizeof(k3), m3, sizeof(m3)); + + return 0; +} + +/* Output of md5 test suite (md5 -x) + +MD5 test suite: +MD5 ("") = d41d8cd98f00b204e9800998ecf8427e +MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661 +MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72 +MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0 +MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b +MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f +MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a + +*/ + +/* HMAC-MD5 test suite + +Test Vectors (Trailing '\0' of a character string not included in test): + + key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b + key_len = 16 bytes + data = "Hi There" + data_len = 8 bytes + digest = 0x9294727a3638bb1c13f48ef8158bfc9d + + key = "Jefe" + data = "what do ya want for nothing?" + data_len = 28 bytes + digest = 0x750c783e6ab0b503eaa86e310a5db738 + + key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + key_len 16 bytes + data = 0xDDDDDDDDDDDDDDDDDDDD... + ..DDDDDDDDDDDDDDDDDDDD... + ..DDDDDDDDDDDDDDDDDDDD... + ..DDDDDDDDDDDDDDDDDDDD... + ..DDDDDDDDDDDDDDDDDDDD + data_len = 50 bytes + digest = 0x56be34521d144c88dbb8c733f0e8b3f6 + +*/ +#endif /* !_BCM14XX_ */ + + +#if 0 /* ---------- XXX still under construction XXX ---------- */ + +static uint32_t * +bcm5821_alloc_rng (int output_size) +{ + uint32_t *output; + uint32_t *mcr; + uint32_t *cmd; + int i; + + output = (uint32_t *)KMALLOC(output_size, CACHE_LINE_SIZE); + for (i = 0; i < output_size/sizeof(uint32_t); i++) + output[i] = 0xDEADBEEF; + + mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE); + mcr[0] = V_MCR_NUM_PACKETS(1); + + cmd = KMALLOC(16, CACHE_LINE_SIZE); /* Always allocate >= 64 bytes */ + cmd[0] = V_CC_OPCODE(K_RNG_DIRECT) | V_CC_LEN(4); + + mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd)); + + /* input fragment */ + mcr[2] = 0; + mcr[3] = 0; + mcr[4] = V_DBC_DATA_LEN(0); + + mcr[5] = V_PD_PKT_LEN(output_size); + + /* output fragment */ + mcr[6] = PHYS_TO_PCI(PTR_TO_PHYS(output)); + mcr[7] = 0; + mcr[8] = V_DBC_DATA_LEN(sizeof(output)); + + return mcr; +} + + +static uint32_t * +bcm5821_alloc_ssl_mac (int msg_size) +{ + uint32_t *message; + uint32_t *cmd; + uint32_t *mcr; + uint32_t *hash; + int i; + + message = KMALLOC(msg_size, CACHE_LINE_SIZE); + for (i = 0; i < msg_size; i++) + ((uint8_t *)message)[i] = i & 0xFF; /* was 0xDEADBEEF */ + + mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE); + mcr[0] = V_MCR_NUM_PACKETS(1); + + /* packet 1 */ + + cmd = KMALLOC(SSL_MAC_CMD_WORDS*4, CACHE_LINE_SIZE); + cmd[0] = V_CC_OPCODE(K_SSL_MAC) | V_CC_LEN(SSL_MAC_CMD_WORDS*4); + cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5); + for (i = 2; i < 6; i++) + cmd[i] = 0x01020304; /* XXX MAC write secret */ + cmd[6] = 0x00000000; /* must be zero for SSL */ + for (i = 7; i < 19; i++) + cmd[i] = 0x36363636; + cmd[19] = 0; /* seq num */ + cmd[20] = 1; + cmd[21] = 0x03000000 | (msg_size << 8); /* type/len/rsvd */ + + mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd)); + + /* input fragment */ + mcr[2] = PHYS_TO_PCI(PTR_TO_PHYS(message)); + mcr[3] = 0; + mcr[4] = V_DBC_DATA_LEN(msg_size); + + mcr[5] = V_PD_PKT_LEN(msg_size); + + hash = KMALLOC(5*4, CACHE_LINE_SIZE); + for (i = 0; i < 5; i++) + hash[i] = 0; + + mcr[6] = 0; + mcr[7] = PHYS_TO_PCI(PTR_TO_PHYS(hash)); + mcr[8] = 0; + + return mcr; +} + +static uint32_t * +bcm5821_alloc_arc4 (int input_size) +{ + uint32_t *mcr; + uint32_t cmd[3 + 256/4]; + uint32_t input[64], output[64]; + uint32_t chain[3]; + uint32_t update[1 + 256/4]; + uint32_t status; + uint8_t *arc4_state; + int i; + + xprintf("\nARC4\n"); + + status = READCSR(sc, R_DMA_STAT); + WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */ + status = READCSR(sc, R_DMA_STAT); + + for (i = 0; i < 64; i++) +#if 0 + input[i] = (i << 24) | ((i+1) << 16) | ((i+2) << 8) | (i+3); +#else + input[i] = 0x5555AAAA; +#endif + for (i = 0; i < 64; i++) + output[i] = 0xDEADBEEF; + for (i = 0; i < 1 + 256/4; i++) + update[i] = 0xFEEDFACE; + + cmd[0] = V_CC_OPCODE(K_ARC4) | V_CC_LEN(sizeof(cmd)); + cmd[1] = M_ARC4_FLAGS_WRITEBACK; +#if 0 + cmd[2] = 0x000100F3; +#else + cmd[2] = 0x00000000; +#endif + arc4_state = (uint8_t *)&cmd[3]; + for (i = 0; i < 256; i++) + arc4_state[i] = i; + + mcr[0] = V_MCR_NUM_PACKETS(1); + + /* packet 1 */ + mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd)); + + /* input fragment */ + mcr[2] = PHYS_TO_PCI(PTR_TO_PHYS(input)); + mcr[3] = 0; + mcr[4] = V_DBC_DATA_LEN(sizeof(input)); + + mcr[5] = V_PD_PKT_LEN(sizeof(input)); + + /* output fragment */ + mcr[6] = PHYS_TO_PCI(PTR_TO_PHYS(output)); + mcr[7] = PHYS_TO_PCI(PTR_TO_PHYS(chain)); + mcr[8] = V_DBC_DATA_LEN(sizeof(output)); + + /* output update */ + chain[0] = PHYS_TO_PCI(PTR_TO_PHYS(update)); + chain[1] = 0; + chain[2] = V_DBC_DATA_LEN(sizeof(update)); /* not actually used */ + + return mcr; +} +#endif /* 0 */ diff --git a/cfe/cfe/dev/dev_dc21143.c b/cfe/cfe/dev/dev_dc21143.c new file mode 100644 index 0000000..f133cbb --- /dev/null +++ b/cfe/cfe/dev/dev_dc21143.c @@ -0,0 +1,2388 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * DC2114x Ethernet Driver File: dev_dc21143.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" + +#ifndef _SB_MAKE64 +#define _SB_MAKE64(x) ((uint64_t)(x)) +#endif +#ifndef _SB_MAKEMASK1 +#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n)) +#endif + +#include "lib_types.h" +#include "lib_hssubr.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_queue.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_irq.h" + +#include "pcivar.h" +#include "pcireg.h" + +#include "dc21143.h" +#include "mii.h" + +/* This is a driver for specific configurations of the DC21041, + DC21140A and DC21143, not a generic Tulip driver. The prefix + "tulip_" is used to indicate generic Tulip functions, while + "dc21041_", "dc21140_" or "dc21143_" indicates functions specific + to a chip variant. + + The 21041 driver assumes a 10BT HD interface, since autonegotiation + is known to be broken in the early revisons of that chip. Example + cards come from DEC. + + The 21140 driver assumes that the PHY uses a standard MII interface + for both 100BT and 10BT. Example cards come from DEC (National DP83840 + Twister PHY) and Netgear (Level One PHY). + + The 21143 driver assumes that the PHY uses the SYM ("5 wire") interface + for 100BT with pass-through for 10BT. Example cards come from DEC + (MicroLinear ML6694 PHY) and Znyx (Kendin KS8761 PHY). There is no + support for MII or AUI interfaces. + + This SB1250 version takes advantage of DMA coherence and uses + "preserve bit lanes" addresses for all accesses that cross the + ZBbus-PCI bridge. */ + +#ifndef TULIP_DEBUG +#define TULIP_DEBUG 0 +#endif + +#ifndef TULIP_TUNE +#define TULIP_TUNE 1 +#endif + +#define ENET_ADDR_LEN 6 /* size of an ethernet address */ +#define MAX_ETHER_PACK 1518 /* max size of a packet */ +#define CRC_SIZE 4 /* size of CRC field */ + +/* The following must be a multiple of 4. In late versions of the + tulip, the rx DMA engine also apparently writes beyond 1520 bytes + for received packets > 1516 bytes (WriteInvalidate only?). */ +#define ETH_BUFFER_SIZE 1536 + +typedef struct eth_pkt_s { + queue_t next; + void *devctx; + unsigned char *buffer; + unsigned int flags; + int length; + /* packet data goes here, should always be longword aligned */ +} eth_pkt_t; + +/* packet flags */ +#define ETH_TX_SETUP 1 + +static void +show_packet(eth_pkt_t *pkt) +{ + int i; + int n = (pkt->length < 32 ? pkt->length : 32); + + xprintf("[%4d]:", pkt->length); + for (i = 0; i < n; i++) { + if (i % 4 == 0) + xprintf(" "); + xprintf("%02x", pkt->buffer[i]); + } + xprintf("\n"); +} + + +/* Descriptor structures */ + +typedef struct rx_dscr { + uint32_t rxd_flags; + uint32_t rxd_bufsize; + uint32_t rxd_bufaddr1; + uint32_t rxd_bufaddr2; +} rx_dscr; + +typedef struct tx_dscr { + uint32_t txd_flags; + uint32_t txd_bufsize; + uint32_t txd_bufaddr1; + uint32_t txd_bufaddr2; +} tx_dscr; + +/* CAM structure */ + +typedef union { + struct { + uint32_t physical[CAM_PERFECT_ENTRIES][3]; + } p; + struct { + uint32_t hash[32]; + uint32_t mbz[7]; + uint32_t physical[3]; + } h; +} tulip_cam; + + +typedef enum { + eth_state_uninit, + eth_state_setup, + eth_state_off, + eth_state_on, + eth_state_broken +} eth_state_t; + +#define ETH_PKTPOOL_SIZE 20 +#define ETH_PKTBUF_SIZE (sizeof(eth_pkt_t) + ((ETH_BUFFER_SIZE+7)&~7)) + +typedef struct tulip_softc { + uint32_t membase; + uint8_t irq; /* interrupt mapping (not currently used) */ + pcitag_t tag; /* tag for configuration registers */ + + uint8_t hwaddr[ENET_ADDR_LEN]; + uint16_t device; /* chip device code */ + uint8_t revision; /* chip revision and step (Table 3-7) */ + + /* current state */ + eth_state_t state; + int bus_errors; + + /* These fields are the chip startup values. */ +// uint16_t media; /* media type */ + uint32_t opmode; /* operating mode */ + uint32_t intmask; /* interrupt mask */ + + /* This field is set before calling dc2114x_hwinit */ + int linkspeed; /* encoding from cfe_ioctl */ + + /* Packet free list */ + queue_t freelist; + uint8_t *pktpool; + queue_t rxqueue; + + /* The descriptor tables */ + uint8_t *rxdscrmem; /* receive descriptors */ + uint8_t *txdscrmem; /* transmit descriptors */ + + eth_pkt_t **rxdscrinfo; + eth_pkt_t **txdscrinfo; + + /* These fields keep track of where we are in tx/rx processing */ + volatile rx_dscr *rxdscr_start; /* beginning of ring */ + volatile rx_dscr *rxdscr_end; /* end of ring */ + volatile rx_dscr *rxdscr_remove; /* next one we expect tulip to use */ + volatile rx_dscr *rxdscr_add; /* next place to put a buffer */ + int rxdscr_onring; + + volatile tx_dscr *txdscr_start; /* beginning of ring */ + volatile tx_dscr *txdscr_end; /* end of ring */ + volatile tx_dscr *txdscr_remove; /* next one we will use for tx */ + volatile tx_dscr *txdscr_add; /* next place to put a buffer */ + + /* These fields describe the PHY */ + int mii_addr; + +} tulip_softc; + + +/* Driver parameterization */ + +#define MAXRXDSCR 16 +#define MAXTXDSCR 16 +#define MINRXRING 8 + +#define MEDIA_UNKNOWN 0 +#define MEDIA_AUI 1 +#define MEDIA_BNC 2 +#define MEDIA_UTP_FULL_DUPLEX 3 +#define MEDIA_UTP_NO_LINK_TEST 4 +#define MEDIA_UTP 5 + +/* Prototypes */ + +static void tulip_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +/* Address mapping macros */ + +/* Note that PHYSADDR only works with 32-bit addresses, but the + so does the Tulip. */ +#define PHYSADDR(sc,x) (K0_TO_PHYS((uintptr_t)(x))) + +#define PCIADDR(a,b) ((uint32_t) (b)) +#define PCIADDRX(a,b) ((uint32_t) (b) | 0x20000000) +#define PCI_TO_CPU(a) (a) + +#if __long64 +#define READCSR(sc,csr) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr))))) + +#define WRITECSR(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr)))) = (val)) + +#else +#define READCSR(sc,csr) \ + (hs_read32(PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr)))) + +#define WRITECSR(sc,csr,val) \ + (hs_write32(PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr)), \ + (val))) + +#endif + + +#define RESET_ADAPTER(sc) \ + { \ + WRITECSR((sc), R_CSR_BUSMODE, M_CSR0_SWRESET); \ + cfe_sleep(CFE_HZ/10); \ + } + + +/* Debugging */ + +static void +dumpstat(tulip_softc *sc) +{ + xprintf("-- CSR 5 = %08X CSR 6 = %08x\n", + READCSR(sc, R_CSR_STATUS), READCSR(sc, R_CSR_OPMODE)); +} + +static void +dumpcsrs(tulip_softc *sc) +{ + int idx; + + xprintf("-------------\n"); + for (idx = 0; idx < 16; idx++) { + xprintf("CSR %2d = %08X\n", idx, READCSR(sc, idx*8)); + } + xprintf("-------------\n"); +} + + +/* Packet management */ + +/* ********************************************************************* + * ETH_ALLOC_PKT(s) + * + * Allocate a packet from the free list. + * + * Input parameters: + * s - eth structure + * + * Return value: + * pointer to packet structure, or NULL if none available + ********************************************************************* */ +#define ETHPKT_ALIGN ((uintptr_t) 4) + +static eth_pkt_t * +eth_alloc_pkt(tulip_softc *s) +{ + uintptr_t addr; + eth_pkt_t *pkt; + + pkt = (eth_pkt_t *) q_deqnext(&s->freelist); + if (!pkt) return NULL; + + addr = (uintptr_t) (pkt+1); + if (addr & (ETHPKT_ALIGN-1)) { + addr = (addr + ETHPKT_ALIGN) & ~(ETHPKT_ALIGN-1); + } + + pkt->buffer = (uint8_t *) addr; + pkt->length = ETH_BUFFER_SIZE; + pkt->flags = 0; + + return pkt; +} + + +/* ********************************************************************* + * ETH_FREE_PKT(s,pkt) + * + * Return a packet to the free list + * + * Input parameters: + * s - sbmac structure + * pkt - packet to return + * + * Return value: + * nothing + ********************************************************************* */ +static void +eth_free_pkt(tulip_softc *s, eth_pkt_t *pkt) +{ + q_enqueue(&s->freelist, &pkt->next); +} + + +/* ********************************************************************* + * ETH_INITFREELIST(s) + * + * Initialize the buffer free list for this mac. The memory + * allocated to the free list is carved up and placed on a linked + * list of buffers for use by the mac. + * + * Input parameters: + * s - eth structure + * + * Return value: + * nothing + ********************************************************************* */ +static void +eth_initfreelist(tulip_softc *s) +{ + int idx; + unsigned char *ptr; + eth_pkt_t *pkt; + + q_init(&s->freelist); + + ptr = s->pktpool; + for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) { + pkt = (eth_pkt_t *) ptr; + eth_free_pkt(s, pkt); + ptr += ETH_PKTBUF_SIZE; + } +} + + +/* Descriptor ring management */ + +static int +tulip_add_rcvbuf(tulip_softc *sc, eth_pkt_t *pkt) +{ + volatile rx_dscr *rxd; + volatile rx_dscr *nextrxd; + int idx; + uint32_t flags = 0; + + rxd = sc->rxdscr_add; + + /* Figure out where the next descriptor will go */ + nextrxd = rxd+1; + if (nextrxd == sc->rxdscr_end) { + nextrxd = sc->rxdscr_start; + flags = M_RDES1_ENDOFRING; + } + + /* + * If the next one is the same as our remove pointer, + * the ring is considered full. (it actually has room for + * one more, but we reserve the remove == add case for "empty") + */ + if (nextrxd == sc->rxdscr_remove) return -1; + + /* Save this packet pointer. */ + idx = rxd - sc->rxdscr_start; + sc->rxdscrinfo[idx] = pkt; + + rxd->rxd_bufsize = V_RDES1_BUF1SIZE(ETH_BUFFER_SIZE) | flags; + rxd->rxd_bufaddr1 = PCIADDRX(sc, PHYSADDR(sc, pkt->buffer)); + rxd->rxd_bufaddr2 = 0; + rxd->rxd_flags = M_RDES0_OWNADAP; + + /* success, advance the pointer */ + sc->rxdscr_add = nextrxd; + sc->rxdscr_onring++; + + return 0; +} + +static void +tulip_fillrxring(tulip_softc *sc) +{ + eth_pkt_t *pkt; + + while (sc->rxdscr_onring < MINRXRING) { + pkt = eth_alloc_pkt(sc); + if (pkt == NULL) { + /* could not allocate a buffer */ + break; + } + if (tulip_add_rcvbuf(sc, pkt) != 0) { + /* could not add buffer to ring */ + eth_free_pkt(sc, pkt); + break; + } + } +} + + +/* ********************************************************************* + * TULIP_RX_CALLBACK(sc, pkt) + * + * Receive callback routine. This routine is invoked when a + * buffer queued for receives is filled. In this simple driver, + * all we do is add the packet to a per-MAC queue for later + * processing, and try to put a new packet in the place of the one + * that was removed from the queue. + * + * Input parameters: + * sc - interface + * ptk - packet context (sbeth_pkt structure) + * + * Return value: + * nothing + ********************************************************************* */ +static void +tulip_rx_callback(tulip_softc *sc, eth_pkt_t *pkt) +{ + if (TULIP_DEBUG) show_packet(pkt); /* debug */ + + q_enqueue(&sc->rxqueue, &pkt->next); + + tulip_fillrxring(sc); +} + + +static void +tulip_procrxring(tulip_softc *sc) +{ + volatile rx_dscr *rxd; + eth_pkt_t *pkt; + eth_pkt_t *newpkt; + int idx; + uint32_t flags; + + for (;;) { + rxd = (volatile rx_dscr *) sc->rxdscr_remove; + idx = rxd - sc->rxdscr_start; + + flags = rxd->rxd_flags; + + if (flags & M_RDES0_OWNADAP) { + /* end of ring, no more packets */ + break; + } + + pkt = sc->rxdscrinfo[idx]; + + /* Drop error packets */ + if (flags & M_RDES0_ERRORSUM) { + xprintf("DC2114x: rx error %04X\n", flags & 0xFFFF); + tulip_add_rcvbuf(sc, pkt); + goto next; + } + + /* Pass up the packet */ + pkt->length = G_RDES0_FRAMELEN(flags) - CRC_SIZE; + tulip_rx_callback(sc, pkt); + + /* put a buffer back on the ring to replace this one */ + newpkt = eth_alloc_pkt(sc); + if (newpkt) tulip_add_rcvbuf(sc, newpkt); + +next: + /* update the pointer, accounting for buffer wrap. */ + rxd++; + if (rxd == sc->rxdscr_end) + rxd = sc->rxdscr_start; + + sc->rxdscr_remove = (rx_dscr *) rxd; + sc->rxdscr_onring--; + } +} + + +static int +tulip_add_txbuf(tulip_softc *sc, eth_pkt_t *pkt) +{ + volatile tx_dscr *txd; + volatile tx_dscr *nexttxd; + int idx; + uint32_t bufsize = 0; + + txd = sc->txdscr_add; + + /* Figure out where the next descriptor will go */ + nexttxd = (txd+1); + if (nexttxd == sc->txdscr_end) { + nexttxd = sc->txdscr_start; + bufsize = M_TDES1_ENDOFRING; + } + + /* If the next one is the same as our remove pointer, + the ring is considered full. (it actually has room for + one more, but we reserve the remove == add case for "empty") */ + + if (nexttxd == sc->txdscr_remove) return -1; + + /* Save this packet pointer. */ + idx = txd - sc->txdscr_start; + sc->txdscrinfo[idx] = pkt; + + bufsize |= V_TDES1_BUF1SIZE(pkt->length) | + M_TDES1_FIRSTSEG | M_TDES1_LASTSEG | M_TDES1_INTERRUPT; + if (pkt->flags & ETH_TX_SETUP) { + /* For a setup packet, FIRSTSEG and LASTSEG should be clear (!) */ + bufsize ^= M_TDES1_SETUP | M_TDES1_FIRSTSEG | M_TDES1_LASTSEG; + } + txd->txd_bufsize = bufsize; + txd->txd_bufaddr1 = PCIADDRX(sc, PHYSADDR(sc, pkt->buffer)); + txd->txd_bufaddr2 = 0; + txd->txd_flags = M_TDES0_OWNADAP; + + /* success, advance the pointer */ + sc->txdscr_add = nexttxd; + + return 0; +} + + +static int +tulip_transmit(tulip_softc *sc,eth_pkt_t *pkt) +{ + tulip_add_txbuf(sc, pkt); + + WRITECSR(sc, R_CSR_TXPOLL, 1); + return 0; +} + + +static void +tulip_proctxring(tulip_softc *sc) +{ + volatile tx_dscr *txd; + eth_pkt_t *pkt; + int idx; + uint32_t flags; + + for (;;) { + txd = (volatile tx_dscr *) sc->txdscr_remove; + idx = txd - sc->txdscr_start; + + flags = txd->txd_flags; + + if (txd == sc->txdscr_add) { + /* ring is empty, no buffers to process */ + break; + } + + if (flags & M_RDES0_OWNADAP) { + /* Reached a packet still being transmitted */ + break; + } + + /* Check for a completed setup packet */ + pkt = sc->txdscrinfo[idx]; + if (pkt->flags & ETH_TX_SETUP) { + if (sc->state == eth_state_setup) { + /* check flag bits */ + sc->state = eth_state_on; + } + pkt->flags &=~ ETH_TX_SETUP; + } + + /* Just free the packet */ + eth_free_pkt(sc, pkt); + + /* update the pointer, accounting for buffer wrap. */ + txd++; + if (txd == sc->txdscr_end) + txd = sc->txdscr_start; + + sc->txdscr_remove = (tx_dscr *) txd; + } +} + + +static void +tulip_initrings(tulip_softc *sc) +{ + volatile tx_dscr *txd; + volatile rx_dscr *rxd; + + /* Claim ownership of all transmit descriptors */ + + for (txd = sc->txdscr_start; txd != sc->txdscr_end; txd++) + txd->txd_flags = 0; + for (rxd = sc->rxdscr_start; rxd != sc->rxdscr_end; rxd++) + rxd->rxd_flags = 0; + + /* Init the ring pointers */ + + sc->txdscr_add = sc->txdscr_remove = sc->txdscr_start; + sc->rxdscr_add = sc->rxdscr_remove = sc->rxdscr_start; + sc->rxdscr_onring = 0; + + /* Add stuff to the receive ring */ + + tulip_fillrxring(sc); +} + + +static int +tulip_init(tulip_softc *sc) +{ + /* Allocate descriptor rings and lookaside lists */ + sc->rxdscrmem = KMALLOC(MAXRXDSCR*sizeof(rx_dscr),sizeof(rx_dscr)); + sc->txdscrmem = KMALLOC(MAXTXDSCR*sizeof(tx_dscr),sizeof(tx_dscr)); + sc->rxdscrinfo = KMALLOC(MAXRXDSCR*sizeof(eth_pkt_t *),sizeof(eth_pkt_t)); + sc->txdscrinfo = KMALLOC(MAXTXDSCR*sizeof(eth_pkt_t *),sizeof(eth_pkt_t)); + + /* Allocate buffer pool */ + sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, 0); + eth_initfreelist(sc); + q_init(&sc->rxqueue); + + /* Fill in pointers to the rings */ + sc->rxdscr_start = (rx_dscr *) (sc->rxdscrmem); + sc->rxdscr_end = sc->rxdscr_start + MAXRXDSCR; + sc->rxdscr_add = sc->rxdscr_start; + sc->rxdscr_remove = sc->rxdscr_start; + sc->rxdscr_onring = 0; + + sc->txdscr_start = (tx_dscr *) (sc->txdscrmem); + sc->txdscr_end = sc->txdscr_start + MAXTXDSCR; + sc->txdscr_add = sc->txdscr_start; + sc->txdscr_remove = sc->txdscr_start; + + tulip_initrings(sc); + + return 0; +} + + +static void +tulip_resetrings(tulip_softc *sc) +{ + volatile tx_dscr *txd; + volatile rx_dscr *rxd; + int idx; + + /* Free already-sent descriptors and buffers */ + tulip_proctxring(sc); + + /* Free any pending but unsent */ + txd = (volatile tx_dscr *) sc->txdscr_remove; + while (txd != sc->txdscr_add) { + idx = txd - sc->txdscr_start; + eth_free_pkt(sc, sc->txdscrinfo[idx]); + txd->txd_flags &=~ M_TDES0_OWNADAP; + + txd++; + if (txd == sc->txdscr_end) + txd = sc->txdscr_start; + } + sc->txdscr_add = sc->txdscr_remove; + + /* Discard any received packets as well as all free buffers */ + rxd = (volatile rx_dscr *) sc->rxdscr_remove; + while (rxd != sc->rxdscr_add) { + idx = rxd - sc->rxdscr_start; + eth_free_pkt(sc, sc->rxdscrinfo[idx]); + rxd->rxd_flags &=~ M_RDES0_OWNADAP; + + rxd++; + if (rxd == sc->rxdscr_end) + rxd = sc->rxdscr_start; + sc->rxdscr_onring--; + } + + /* Reestablish the initial state. */ + tulip_initrings(sc); +} + + +/* CRCs */ + +#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */ + +static uint32_t +tulip_crc32(const uint8_t *databuf, unsigned int datalen) +{ + unsigned int idx, bit, data; + uint32_t crc; + + crc = 0xFFFFFFFFUL; + for (idx = 0; idx < datalen; idx++) + for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0); + return crc; +} + +#define tulip_mchash(mca) (tulip_crc32((mca), 6) & 0x1FF) + + +/* Serial ROM access */ + +/**************************************************************************** + * tulip_spin(sc, ns) + * + * Spin for a short interval (nominally in nanoseconds) + * + * Input Parameters: ns - minimum required nsec. + * + * The delay loop uses uncached PCI reads, each of which requires + * at least 3 PCI bus clocks (45 ns at 66 MHz) to complete. The + * actual delay will be longer (much longer if preempted). + ***************************************************************************/ + +#define PCI_MIN_DELAY 45 + +static void +tulip_spin(tulip_softc *sc, long nanoseconds) +{ + long delay; + volatile uint32_t t; + + for (delay = nanoseconds; delay > 0; delay -= PCI_MIN_DELAY) + t = READCSR(sc, R_CSR_BUSMODE); +} + + +/* + * Delays below are chosen to meet specs for NS93C64 (slow M variant). + * Current parts are faster. + * Reference: NS Memory Data Book, 1994 + */ + +#define SROM_SIZE 128 +#define SROM_MAX_CYCLES 32 + +#define SROM_CMD_BITS 3 +#define SROM_ADDR_BITS 6 + +#define K_SROM_READ_CMD 06 +#define K_SROM_WRITE_CMD 05 + +#define SROM_ADDR_OFFSET 0x14 +#define SROM_CRC_OFFSET (SROM_SIZE-2) + + +static void +srom_idle_state(tulip_softc *sc) +{ + uint32_t csr9; + unsigned int i; + + csr9 = READCSR(sc, R_CSR_ROM_MII); + + csr9 |= M_CSR9_SROMCHIPSEL; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 100); /* CS setup (Tcss=100) */ + + /* Run the clock through the maximum number of pending read cycles */ + for (i = 0; i < SROM_MAX_CYCLES*2; i++) { + csr9 ^= M_CSR9_SROMCLOCK; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 1000); /* SK period (Fsk=0.5MHz) */ + } + + /* Deassert SROM Chip Select */ + csr9 &=~ M_CSR9_SROMCHIPSEL; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 50); /* CS recovery (Tsks=50) */ +} + +static void +srom_send_command_bit(tulip_softc *sc, unsigned int data) +{ + uint32_t csr9; + + csr9 = READCSR(sc, R_CSR_ROM_MII); + + /* Place the data bit on the bus */ + if (data == 1) + csr9 |= M_CSR9_SROMDATAIN; + else + csr9 &=~ M_CSR9_SROMDATAIN; + + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 360); /* setup: Tdis=200 */ + + /* Now clock the data into the SROM */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK); + tulip_spin(sc, 900); /* clock high, Tskh=500 */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 450); /* clock low, Tskl=250 */ + + /* Now clear the data bit */ + csr9 &=~ M_CSR9_SROMDATAIN; /* data invalid, Tidh=20 for SK^ */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 270); /* min cycle, 1/Fsk=2000 */ +} + +static uint16_t +srom_read_bit(tulip_softc *sc) +{ + uint32_t csr9; + + csr9 = READCSR(sc, R_CSR_ROM_MII); + + /* Generate a clock cycle before doing a read */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK); /* rising edge */ + tulip_spin(sc, 1000); /* clock high, Tskh=500, Tpd=1000 */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); /* falling edge */ + tulip_spin(sc, 1000); /* clock low, 1/Fsk=2000 */ + + csr9 = READCSR(sc, R_CSR_ROM_MII); + return ((csr9 & M_CSR9_SROMDATAOUT) != 0 ? 1 : 0); +} + +#define CMD_BIT_MASK (1 << (SROM_CMD_BITS+SROM_ADDR_BITS-1)) + +static uint16_t +srom_read_word(tulip_softc *sc, unsigned int index) +{ + uint16_t command, word; + uint32_t csr9; + unsigned int i; + + csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_SROMCHIPSEL; + + /* Assert the SROM CS line */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 100); /* CS setup, Tcss = 100 */ + + /* Send the read command to the SROM */ + command = (K_SROM_READ_CMD << SROM_ADDR_BITS) | index; + for (i = 0; i < SROM_CMD_BITS+SROM_ADDR_BITS; i++) { + srom_send_command_bit(sc, (command & CMD_BIT_MASK) != 0 ? 1 : 0); + command <<= 1; + } + + /* Now read the bits from the SROM (MSB first) */ + word = 0; + for (i = 0; i < 16; ++i) { + word <<= 1; + word |= srom_read_bit(sc); + } + + /* Clear the SROM CS Line, CS hold, Tcsh = 0 */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 &~ M_CSR9_SROMCHIPSEL); + + return word; +} + + +/**************************************************************************** + * srom_calc_crc() + * + * Calculate the CRC of the SROM and return it. We compute the + * CRC per Appendix A of the 21140A ROM/external register data + * sheet (EC-QPQWA-TE). + ***************************************************************************/ + +static uint16_t +srom_calc_crc(tulip_softc *sc, uint8_t srom[], int length) +{ + uint32_t crc = tulip_crc32(srom, length) ^ 0xffffffff; + + return (uint16_t)(crc & 0xffff); +} + +/**************************************************************************** + * srom_read_all(sc, uint8_t dest) + * + * Read the entire SROM into the srom array + * + * Input parameters: + * sc - tulip state + ***************************************************************************/ + +#define STORED_CRC(rom) \ + ((rom)[SROM_CRC_OFFSET] | ((rom)[SROM_CRC_OFFSET+1] << 8)) + +static int +srom_read_all(tulip_softc *sc, uint8_t dest[]) +{ + int i; + uint16_t crc, temp; + + WRITECSR(sc, R_CSR_ROM_MII, M_CSR9_SERROMSEL|M_CSR9_ROMREAD); + + srom_idle_state(sc); + + for (i = 0; i < SROM_SIZE/2; i++) { + temp = srom_read_word(sc, i); + dest[2*i] = temp & 0xff; + dest[2*i+1] =temp >> 8; + } + + WRITECSR(sc, R_CSR_ROM_MII, 0); /* CS hold, Tcsh=0 */ + + crc = srom_calc_crc(sc, dest, SROM_CRC_OFFSET); + if (crc != STORED_CRC(dest)) { + crc = srom_calc_crc(sc, dest, 94); /* "alternative" */ + if (crc != STORED_CRC(dest)) { + xprintf("DC2114x: Invalid SROM CRC, calc %04x, stored %04x\n", + crc, STORED_CRC(dest)); + return 0/*-1*/; + } + } + return 0; +} + +static int +srom_read_addr(tulip_softc *sc, uint8_t buf[]) +{ + uint8_t srom[SROM_SIZE]; + + if (srom_read_all(sc, srom) == 0) { + memcpy(buf, &srom[SROM_ADDR_OFFSET], ENET_ADDR_LEN); + return 0; + } + + return -1; +} + + +/**************************************************************************** + * MII access utility routines + ***************************************************************************/ + +/* MII clock limited to 2.5 MHz, transactions end with MDIO tristated */ + +static void +mii_write_bits(tulip_softc *sc, uint32_t data, unsigned int count) +{ + uint32_t csr9; + uint32_t bitmask; + + csr9 = READCSR(sc, R_CSR_ROM_MII) &~ (M_CSR9_MDC | M_CSR9_MIIMODE); + + for (bitmask = 1 << (count-1); bitmask != 0; bitmask >>= 1) { + csr9 &=~ M_CSR9_MDO; + if ((data & bitmask) != 0) csr9 |= M_CSR9_MDO; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + + tulip_spin(sc, 2000); /* setup */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC); + tulip_spin(sc, 2000); /* hold */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + } +} + +static void +mii_turnaround(tulip_softc *sc) +{ + uint32_t csr9; + + csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_MIIMODE; + + /* stop driving data */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 2000); /* setup */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC); + tulip_spin(sc, 2000); /* clock high */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + + /* read back and check for 0 here? */ +} + +/**************************************************************************** + * mii_read_register + * + * This routine reads a register from the PHY chip using the MII + * serial management interface. + * + * Input parameters: + * index - index of register to read (0-31) + * + * Return value: + * word read from register + ***************************************************************************/ + +static uint16_t +mii_read_register(tulip_softc *sc, unsigned int index) +{ + /* Send the command and address to the PHY. The sequence is + a synchronization sequence (32 1 bits) + a "start" command (2 bits) + a "read" command (2 bits) + the PHY addr (5 bits) + the register index (5 bits) + */ + uint32_t csr9; + uint16_t word; + int i; + + mii_write_bits(sc, 0xff, 8); + mii_write_bits(sc, 0xffffffff, 32); + mii_write_bits(sc, MII_COMMAND_START, 2); + mii_write_bits(sc, MII_COMMAND_READ, 2); + mii_write_bits(sc, sc->mii_addr /* XXX sc->phy.index */, 5); + mii_write_bits(sc, index, 5); + + mii_turnaround(sc); + + csr9 = (READCSR(sc, R_CSR_ROM_MII) &~ M_CSR9_MDC) | M_CSR9_MIIMODE; + word = 0; + + for (i = 0; i < 16; i++) { + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 2000); /* clock width low */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC); + tulip_spin(sc, 2000); /* clock width high */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 1000); /* output delay */ + word <<= 1; + if ((READCSR(sc, R_CSR_ROM_MII) & M_CSR9_MDI) != 0) + word |= 0x0001; + } + + return word; + + /* reset to output mode? */ +} + +/**************************************************************************** + * mii_write_register + * + * This routine writes a register in the PHY chip using the MII + * serial management interface. + * + * Input parameters: + * index - index of register to write (0-31) + * value - word to write + ***************************************************************************/ + +static void +mii_write_register(tulip_softc *sc, unsigned int index, uint16_t value) +{ + mii_write_bits(sc, 0xff, 8); + mii_write_bits(sc, 0xffffffff, 32); + mii_write_bits(sc, MII_COMMAND_START, 2); + mii_write_bits(sc, MII_COMMAND_WRITE, 2); + mii_write_bits(sc, sc->mii_addr /* XXX sc->phy.index */, 5); + mii_write_bits(sc, index, 5); + mii_write_bits(sc, MII_COMMAND_ACK, 2); + mii_write_bits(sc, value, 16); + + /* reset to input mode? */ +} + + +static int +mii_probe(tulip_softc *sc) +{ + int i; + uint16_t id1, id2; + + for (i = 0; i < 32; i++) { + sc->mii_addr = i; + id1 = mii_read_register(sc, MII_PHYIDR1); + id2 = mii_read_register(sc, MII_PHYIDR2); + if ((id1 != 0xffff || id2 != 0xffff) && + (id1 != 0x0000 || id2 != 0x0000)) { + return 0; + } + } + return -1; +} + +#if 0 +static void +mii_dump(tulip_softc *sc) +{ + int i; + uint16_t r; + + for (i = 0; i <=6; ++i) { + r = mii_read_register(sc, i); + if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r); + } + for (i = 21; i <= 25; ++i) { + r = mii_read_register(sc, i); + if (r != 0) printf("MII_REG%02x: %04x\n", i, r); + } +} +#else +#define mii_dump(sc) +#endif + + +#if 0 +static void +tulip_getaddr(tulip_softc *sc, uint8_t *buf) +{ + memcpy(buf, sc->hwaddr, ENET_ADDR_LEN); +} +#endif + + +/* Chip specific code */ + +static void +dc21143_set_speed(tulip_softc *sc, int speed) +{ + uint32_t opmode = 0; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + + switch (speed) { + case ETHER_SPEED_AUTO: + break; + case ETHER_SPEED_10HDX: + default: + WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_HD); + WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE); + opmode = M_CSR6_SPEED_10; + break; + case ETHER_SPEED_10FDX: + WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_FD); + WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE); + opmode = M_CSR6_SPEED_10 | M_CSR6_FULLDUPLEX; + break; + case ETHER_SPEED_100HDX: + WRITECSR(sc, R_CSR_SIAMODE1, 0); + WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE); + opmode = M_CSR6_SPEED_100; + break; + case ETHER_SPEED_100FDX: + WRITECSR(sc, R_CSR_SIAMODE1, 0); + WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE); + opmode = M_CSR6_SPEED_100 | M_CSR6_FULLDUPLEX; + break; + } + + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); + + opmode |= M_CSR6_MBO; +#if TULIP_TUNE + opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72); +#else + opmode |= M_CSR6_STOREFWD; +#endif + WRITECSR(sc, R_CSR_OPMODE, opmode); +} + +static void +dc21143_autonegotiate(tulip_softc *sc) +{ + uint32_t opmode; + uint32_t tempword; + int count; + int linkspeed; + + linkspeed = ETHER_SPEED_UNKNOWN; + + /* Program the media setup into the CSRs. */ + /* reset SIA */ + WRITECSR(sc, R_CSR_SIAMODE0, 0); + + /* set to speed_10, fullduplex to start_nway */ + opmode = + M_CSR6_SPEED_10 | + M_CSR6_FULLDUPLEX | + M_CSR6_MBO; + WRITECSR(sc, R_CSR_OPMODE, opmode); + + /* Choose advertised capabilities */ + tempword = + M_CSR14_100BASETHALFDUP | + M_CSR14_100BASETFULLDUP | + M_CSR14_HALFDUPLEX10BASET; + WRITECSR(sc, R_CSR_SIAMODE1, tempword); + + /* Enable autonegotiation */ + tempword |= M_CSR14_AUTONEGOTIATE | 0xffff; + WRITECSR(sc, R_CSR_SIAMODE1, tempword); + WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE); + WRITECSR(sc, R_CSR_OPMODE, opmode); + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); + + /* STATE check nway, poll until a valid 10/100mbs signal seen */ + WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS); /* try to clear this... */ + + /* (Re)start negotiation */ + tempword = READCSR(sc, R_CSR_SIASTATUS); + tempword &=~ M_CSR12_AUTONEGARBIT; + tempword |= V_CSR12_AUTONEGARBIT(0x1); + + for (count = 0; count <= 130; count++) { + tempword = READCSR(sc, R_CSR_STATUS); + if (tempword & M_CSR5_LINKPASS) + break; + cfe_sleep(CFE_HZ/100); + } + + if (count > 130) + xprintf("DC21143: Link autonegotiation failed\n"); + + /* STATE configure nway, check to see if any abilities common to us. + If they do, set to highest mode, if not, we will see if the partner + will do 100mb or 10mb - then set it */ + + tempword = READCSR(sc, R_CSR_SIASTATUS); + /* clear the autonegogiate complete bit */ + WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS); + + if (tempword & M_CSR12_LINKPARTNEG) { + /* A link partner was negogiated... */ + + xprintf("DC21143: Negotiated "); + if (tempword & 0x01000000) { /* 100FD */ + xprintf("100Mb/s FDX"); + linkspeed = ETHER_SPEED_100FDX; + } + else if (tempword & 0x00800000) { /* 100HD */ + xprintf("100Mb/s HDX"); + linkspeed = ETHER_SPEED_100HDX; + } + else if (tempword & 0x00400000) { /* 10FD */ + xprintf("10Mb/s FDX"); + linkspeed = ETHER_SPEED_10FDX; + } + else if (tempword & 0x00200000) { /* 10HD */ + xprintf("10Mb/s HDX"); + linkspeed = ETHER_SPEED_10HDX; + } + xprintf("\n"); + } + else { + /* no link partner negotiation */ + /* disable link for 1.3 seconds to break any existing connections */ + + /* xprintf("Disabling link, setting to 10mb half duplex\n"); */ + dc21143_set_speed(sc, ETHER_SPEED_10HDX); + cfe_sleep(CFE_HZ/8); + + tempword = READCSR(sc, R_CSR_SIASTATUS); + + if ((tempword & 0x02) == 0) { + /* 100 mb signal present set to 100mb */ + xprintf("No link partner... setting to 100mb/s HDX\n"); + linkspeed = ETHER_SPEED_100HDX; + } + else if ((tempword & 0x04) == 0) { + /* 10 mb signal present */ + xprintf("No link partner... setting to 10mb/s HDX\n"); + linkspeed = ETHER_SPEED_10HDX; + } + else { + /* couldn't determine line speed, so set to 10mbs */ + xprintf("Unknown; defaulting to 10Mb/s HDX\n"); + linkspeed = ETHER_SPEED_10HDX; + } + } + + dc21143_set_speed(sc, linkspeed); +} + +static void +dc21143_set_loopback(tulip_softc *sc, int mode) +{ + uint32_t v; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + if (mode == ETHER_LOOPBACK_EXT) { + /* deal with CSRs 13-15 */ + } + cfe_sleep(CFE_HZ/10); /* check this */ + + /* Update the SIA registers */ + v = READCSR(sc, R_CSR_SIAMODE0); + WRITECSR(sc, R_CSR_SIAMODE0, v &~ 0xFFFF); + v = READCSR(sc, R_CSR_SIAMODE1); + WRITECSR(sc, R_CSR_SIAMODE1, v &~ 0xFFFF); + v = READCSR(sc, R_CSR_SIAMODE2); + WRITECSR(sc, R_CSR_SIAMODE2, v | 0xC000); /* WC of HCKR, RMP */ + WRITECSR(sc, R_CSR_SIAMODE2, (v &~ 0xFFFF) | M_CSR15_GP_AUIBNC); + + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); +} + +static void +dc21143_hwinit(tulip_softc *sc) +{ + uint32_t v; + uint32_t csr6word, csr14word; + + /* CSR0 - bus mode */ + WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_CONFIG_GEPS_LEDS); +#if TULIP_TUNE + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + M_CSR0_READMULTENAB | M_CSR0_READLINEENAB | + M_CSR0_WRITEINVALENAB | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#else + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN128) | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#endif +#ifdef __MIPSEB + v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */ +#endif + WRITECSR(sc, R_CSR_BUSMODE, v); + + /* CSR6 - operation mode */ + v = M_CSR6_PORTSEL | +#if TULIP_TUNE + V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) | +#else + M_CSR6_STOREFWD | +#endif + M_CSR6_MBO | + M_CSR6_PCSFUNC | + M_CSR6_SCRAMMODE; + WRITECSR(sc, R_CSR_OPMODE, v); + + /* About to muck the SIA, reset it.(?) */ + /* WRITECSR(sc, R_CSR_SIASTATUS, 1); */ + + /* Must shut off all transmit/receive in order to attempt to + achieve Full Duplex */ + csr6word = READCSR(sc, R_CSR_OPMODE); + WRITECSR(sc, R_CSR_OPMODE, csr6word &~ (M_CSR6_TXSTART | M_CSR6_RXSTART)); + csr6word = READCSR(sc, R_CSR_OPMODE); + + WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start))); + WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start))); + + if (sc->linkspeed == ETHER_SPEED_AUTO) { + dc21143_autonegotiate(sc); + } + else { + /* disable autonegotiate so we can set full duplex to on */ + WRITECSR(sc, R_CSR_SIAMODE0, 0); + csr14word = READCSR(sc, R_CSR_SIAMODE1); + csr14word &=~ M_CSR14_AUTONEGOTIATE; + WRITECSR(sc, R_CSR_SIAMODE1, csr14word); + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); + + dc21143_set_speed(sc, sc->linkspeed); + } +} + + +static void +dc21140_set_speed(tulip_softc *sc, int speed, int autoneg) +{ + uint16_t control; + uint16_t pcr; + uint32_t opmode = 0; + + pcr = mii_read_register(sc, 0x17); + pcr |= (0x400|0x100|0x40|0x20); + mii_write_register(sc, 0x17, pcr); + + control = mii_read_register(sc, MII_BMCR); + + if (!autoneg) { + control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + control &=~ (BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX); + } + + switch (speed) { + case ETHER_SPEED_10HDX: + default: + opmode = M_CSR6_SPEED_10_MII; + break; + case ETHER_SPEED_10FDX: + control |= BMCR_DUPLEX; + opmode = M_CSR6_SPEED_10_MII | M_CSR6_FULLDUPLEX; + break; + case ETHER_SPEED_100HDX: + control |= BMCR_SPEED100; + opmode = M_CSR6_SPEED_100_MII; + break; + case ETHER_SPEED_100FDX: + control |= BMCR_SPEED100 | BMCR_DUPLEX ; + opmode = M_CSR6_SPEED_100_MII | M_CSR6_FULLDUPLEX; + break; + } + + if (!autoneg) + mii_write_register(sc, MII_BMCR, control); + + opmode |= M_CSR6_MBO; +#if TULIP_TUNE + opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72); +#else + opmode |= M_CSR6_STOREFWD; +#endif + WRITECSR(sc, R_CSR_OPMODE, opmode); +#if 0 + xprintf("setspeed PHY\n"); mii_dump(sc); +#endif +} + +static void +dc21140_autonegotiate(tulip_softc *sc) +{ + uint16_t control, status, cap; + unsigned int timeout; + int linkspeed; + int autoneg; + + linkspeed = ETHER_SPEED_UNKNOWN; + + /* Read twice to clear latching bits */ + status = mii_read_register(sc, MII_BMSR); + status = mii_read_register(sc, MII_BMSR); +#if 0 + xprintf("query PHY\n"); mii_dump(sc); +#endif + + if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) == + (BMSR_AUTONEG | BMSR_LINKSTAT)) + control = mii_read_register(sc, MII_BMCR); + else { + /* reset the PHY */ + mii_write_register(sc, MII_BMCR, BMCR_RESET); + timeout = 3000; + for (;;) { + control = mii_read_register(sc, MII_BMCR); + if ((control && BMCR_RESET) == 0) break; + cfe_sleep(CFE_HZ/2); + timeout -= 500; + if (timeout <= 0) break; + } + if ((control & BMCR_RESET) != 0) { + xprintf("DC21140: PHY reset failed\n"); + return; + } + + status = mii_read_register(sc, MII_BMSR); + cap = ((status >> 6) & (ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD)) + | PSB_802_3; + mii_write_register(sc, MII_ANAR, cap); + control |= (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + + timeout = 3000; + for (;;) { + status = mii_read_register(sc, MII_BMSR); + if ((status & BMSR_ANCOMPLETE) != 0) break; + cfe_sleep(CFE_HZ/2); + timeout -= 500; + if (timeout <= 0) break; + } +#if 0 + xprintf("done PHY\n"); mii_dump(sc); +#endif + } + + if ((status & BMSR_ANCOMPLETE) != 0) { + /* A link partner was negogiated... */ + + uint16_t remote = mii_read_register(sc, MII_ANLPAR); + + autoneg = 1; + xprintf("DC21140: Negotiated "); + if ((remote & ANLPAR_TXFD) != 0) { + xprintf("100Mb/s FDX"); + linkspeed = ETHER_SPEED_100FDX; + } + else if ((remote & ANLPAR_TXHD) != 0) { + xprintf("100Mb/s HDX"); + linkspeed = ETHER_SPEED_100HDX; + } + else if ((remote & ANLPAR_10FD) != 0) { + xprintf("10Mb/s FDX"); + linkspeed = ETHER_SPEED_10FDX; + } + else if ((remote & ANLPAR_10HD) != 0) { + xprintf("10Mb/s HDX"); + linkspeed = ETHER_SPEED_10HDX; + } + xprintf("\n"); + } + else { + /* no link partner negotiation */ + + autoneg = 0; + xprintf("DC21140: MII negotiation failed, assuming 10BT\n"); + control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + linkspeed = ETHER_SPEED_10HDX; + } + + if ((status & BMSR_LINKSTAT) == 0) + mii_write_register(sc, MII_BMCR, control); + dc21140_set_speed(sc, linkspeed, autoneg); + + status = mii_read_register(sc, MII_BMSR); /* clear latching bits */ +#if 0 + xprintf("final PHY\n"); mii_dump(sc); +#endif +} + +static void +dc21140_set_loopback(tulip_softc *sc, int mode) +{ + if (mode == ETHER_LOOPBACK_EXT) + xprintf("DC21140: external loopback mode NYI\n"); +} + +static void +dc21140_hwinit(tulip_softc *sc) +{ + uint32_t v; + uint32_t csr6word; + + /* The following assume GP port bits wired per the DEC reference design. + XXX Interpret the srom initialization strings instead */ + WRITECSR(sc, R_CSR_GENPORT, M_CSR12_CONTROL | 0x1F); + WRITECSR(sc, R_CSR_GENPORT, 0); /* release PHY reset */ + + /* Select MII interface */ + WRITECSR(sc, R_CSR_OPMODE, M_CSR6_PORTSEL); + RESET_ADAPTER(sc); + + mii_probe(sc); + + /* CSR0 - bus mode */ +#if TULIP_TUNE + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + M_CSR0_READMULTENAB | M_CSR0_READLINEENAB | + M_CSR0_WRITEINVALENAB | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#else + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN128) | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#endif +#ifdef __MIPSEB + v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */ +#endif + WRITECSR(sc, R_CSR_BUSMODE, v); + + /* CSR6 - operation mode */ + v = M_CSR6_PORTSEL | +#if TULIP_TUNE + V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) | +#else + M_CSR6_STOREFWD | +#endif + M_CSR6_MBO; + WRITECSR(sc, R_CSR_OPMODE, v); + + /* Must shut off all transmit/receive in order to attempt to + achieve Full Duplex */ + csr6word = READCSR(sc, R_CSR_OPMODE); + WRITECSR(sc, R_CSR_OPMODE, csr6word &~ (M_CSR6_TXSTART | M_CSR6_RXSTART)); + csr6word = READCSR(sc, R_CSR_OPMODE); + + WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start))); + WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start))); + + if (sc->linkspeed == ETHER_SPEED_AUTO) { + dc21140_autonegotiate(sc); + } + else { + dc21140_set_speed(sc, sc->linkspeed, 0); + } +} + + +static void +dc21041_set_loopback(tulip_softc *sc, int mode) +{ + uint32_t v; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + if (mode == ETHER_LOOPBACK_EXT) { + /* deal with CSRs 13-15 */ + } + cfe_sleep(CFE_HZ/10); /* check this */ + + /* Update the SIA registers */ + v = READCSR(sc, R_CSR_SIAMODE0); + WRITECSR(sc, R_CSR_SIAMODE0, v &~ 0xFFFF); + WRITECSR(sc, R_CSR_SIAMODE1, 0x7A3F); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0008); + + WRITECSR(sc, R_CSR_SIAMODE0, 0xEF01); +} + +static void +dc21041_hwinit(tulip_softc *sc) +{ + uint32_t v; + uint32_t opmode; + + /* CSR0 - bus mode */ + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN128) | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#ifdef __MIPSEB + v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */ +#endif + WRITECSR(sc, R_CSR_BUSMODE, v); + + /* set initial interrupt mask here? */ + + WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start))); + WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start))); + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + + /* For now, always force 10BT, HDX */ + WRITECSR(sc, R_CSR_SIAMODE1, 0x7F3F); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0008); + opmode = M_CSR6_SPEED_10; + + WRITECSR(sc, R_CSR_SIAMODE0, 0xEF01); + cfe_sleep(CFE_HZ/10); + + opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72); + WRITECSR(sc, R_CSR_OPMODE, opmode); +} + + +static void +tulip_hwinit(tulip_softc *sc) +{ + if (sc->state == eth_state_uninit) { + RESET_ADAPTER(sc); + sc->state = eth_state_off; + sc->bus_errors = 0; + + switch (sc->device) { + case K_PCI_ID_DC21041: + dc21041_hwinit(sc); + break; + case K_PCI_ID_DC21140: + dc21140_hwinit(sc); + break; + case K_PCI_ID_DC21143: + dc21143_hwinit(sc); + break; + default: + break; + } + } +} + + +static void +tulip_isr(tulip_softc *sc) +{ + uint32_t status; + uint32_t csr5; + + for (;;) { + + /* Read the interrupt status. */ + csr5 = READCSR(sc, R_CSR_STATUS); +// status &= sc->intmask; /* keep only the bits we like. */ + status = csr5 & ( + M_CSR5_RXINT | M_CSR5_RXBUFUNAVAIL | + M_CSR5_TXINT | M_CSR5_TXUNDERFLOW | + M_CSR5_FATALBUSERROR); + + /* if there are no more interrupts, leave now. */ + if (status == 0) break; + + /* Clear the pending interrupt. */ + WRITECSR(sc, R_CSR_STATUS, status); + + /* Now, test each unmasked bit in the interrupt register and + handle each interrupt type appropriately. */ + + if (status & M_CSR5_FATALBUSERROR) { + xprintf("DC21143: bus error %02x\n", G_CSR5_ERRORBITS(csr5)); + dumpstat(sc); + sc->bus_errors++; + if (sc->bus_errors >= 2) { + dumpcsrs(sc); + RESET_ADAPTER(sc); + sc->state = eth_state_off; + sc->bus_errors = 0; + } + } + + if (status & M_CSR5_RXINT) { + tulip_procrxring(sc); + } + + if (status & M_CSR5_TXINT) { + tulip_proctxring(sc); + } + + if (status & (M_CSR5_TXUNDERFLOW | M_CSR5_RXBUFUNAVAIL)) { + if (status & M_CSR5_TXUNDERFLOW) { + xprintf("DC21143: tx underrun, %08x\n", csr5); + /* Try to restart */ + WRITECSR(sc, R_CSR_TXPOLL, 1); + } + if (status & M_CSR5_RXBUFUNAVAIL) { + /* Try to restart */ + WRITECSR(sc, R_CSR_RXPOLL, 1); + } + } + } +} + + +static void +tulip_start(tulip_softc *sc) +{ + uint32_t opmode; + int idx; + tulip_cam *cam; + eth_pkt_t *pkt; + + tulip_hwinit(sc); + + WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start))); + WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start))); + + opmode = READCSR(sc, R_CSR_OPMODE); + opmode &=~ M_CSR6_OPMODE; /* no loopback */ + opmode |= (M_CSR6_TXSTART | M_CSR6_RXSTART); + + sc->intmask = 0; + WRITECSR(sc, R_CSR_INTMASK, 0); /* no interrupts */ + WRITECSR(sc, R_CSR_OPMODE, opmode); + + pkt = eth_alloc_pkt(sc); + if (pkt) { + pkt->length = CAM_SETUP_BUFFER_SIZE; + cam = (tulip_cam *) pkt->buffer; + +#ifdef __MIPSEB + cam->p.physical[0][0] = (((uint32_t) sc->hwaddr[0] << 8) | + (uint32_t) sc->hwaddr[1]) << 16; + cam->p.physical[0][1] = (((uint32_t) sc->hwaddr[2] << 8) | + (uint32_t) sc->hwaddr[3]) << 16; + cam->p.physical[0][2] = (((uint32_t) sc->hwaddr[4] << 8) | + (uint32_t) sc->hwaddr[5]) << 16; + for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) { + cam->p.physical[idx][0] = 0xFFFF0000; + cam->p.physical[idx][1] = 0xFFFF0000; + cam->p.physical[idx][2] = 0xFFFF0000; + } +#else + cam->p.physical[0][0] = ((uint32_t) sc->hwaddr[0]) | + (((uint32_t) sc->hwaddr[1]) << 8); + cam->p.physical[0][1] = ((uint32_t) sc->hwaddr[2]) | + (((uint32_t) sc->hwaddr[3]) << 8); + cam->p.physical[0][2] = ((uint32_t) sc->hwaddr[4]) | + (((uint32_t) sc->hwaddr[5]) << 8); + for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) { + cam->p.physical[idx][0] = 0x0000FFFF; + cam->p.physical[idx][1] = 0x0000FFFF; + cam->p.physical[idx][2] = 0x0000FFFF; + } +#endif + + pkt->flags |= ETH_TX_SETUP; + if (tulip_transmit(sc, pkt) != 0) { + xprintf("DC21143: failed setup\n"); + dumpstat(sc); + eth_free_pkt(sc, pkt); + return; + } + sc->state = eth_state_setup; + } +} + +static void +tulip_stop(tulip_softc *sc) +{ + uint32_t opmode; + uint32_t status; + int count; + + WRITECSR(sc, R_CSR_INTMASK, 0); + sc->intmask = 0; + + opmode = READCSR(sc, R_CSR_OPMODE); + opmode &=~ (M_CSR6_TXSTART | M_CSR6_RXSTART); + WRITECSR(sc, R_CSR_OPMODE, opmode); + + /* wait for any DMA activity to terminate */ + for (count = 0; count <= 130; count++) { + status = READCSR(sc, R_CSR_STATUS); + if ((status & (M_CSR5_RXPROCSTATE | M_CSR5_TXPROCSTATE)) == 0) + break; + cfe_sleep(CFE_HZ/10); + } + if (count > 130) { + xprintf("DC21143: idle state not achieved\n"); + dumpstat(sc); + } +} + + +static void +tulip_start_loopback(tulip_softc *sc, int mode) +{ + uint32_t opmode; + + opmode = READCSR(sc, R_CSR_OPMODE); + + switch (sc->device) { + case K_PCI_ID_DC21041: + dc21041_set_loopback(sc, mode); + break; + case K_PCI_ID_DC21140: + dc21140_set_loopback(sc, mode); + break; + case K_PCI_ID_DC21143: + dc21143_set_loopback(sc, mode); + break; + default: + break; + } + cfe_sleep(CFE_HZ/10); + + WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start))); + WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start))); + + sc->intmask = 0; /* no interrupts */ + WRITECSR(sc, R_CSR_INTMASK, 0); + + opmode &=~ (M_CSR6_OPMODE | M_CSR6_FULLDUPLEX); + opmode |= M_CSR6_PORTSEL; + if (mode == ETHER_LOOPBACK_EXT) + opmode |= M_CSR6_EXTLOOPBACK; + else + opmode |= M_CSR6_INTLOOPBACK; + opmode |= M_CSR6_TXSTART | M_CSR6_RXSTART; + WRITECSR(sc, R_CSR_OPMODE, opmode); +} + + +/* ********************************************************************* + * ETH_PARSE_XDIGIT(c) + * + * Parse a hex digit, returning its value + * + * Input parameters: + * c - character + * + * Return value: + * hex value, or -1 if invalid + ********************************************************************* */ +static int +eth_parse_xdigit(char c) +{ + int digit; + + if ((c >= '0') && (c <= '9')) digit = c - '0'; + else if ((c >= 'a') && (c <= 'f')) digit = c - 'a' + 10; + else if ((c >= 'A') && (c <= 'F')) digit = c - 'A' + 10; + else digit = -1; + + return digit; +} + +/* ********************************************************************* + * ETH_PARSE_HWADDR(str,hwaddr) + * + * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte + * Ethernet address. + * + * Input parameters: + * str - string + * hwaddr - pointer to hardware address + * + * Return value: + * 0 if ok, else -1 + ********************************************************************* */ +static int +eth_parse_hwaddr(char *str, uint8_t *hwaddr) +{ + int digit1, digit2; + int idx = ENET_ADDR_LEN; + + while (*str && (idx > 0)) { + digit1 = eth_parse_xdigit(*str); + if (digit1 < 0) return -1; + str++; + if (!*str) return -1; + + if ((*str == ':') || (*str == '-')) { + digit2 = digit1; + digit1 = 0; + } + else { + digit2 = eth_parse_xdigit(*str); + if (digit2 < 0) return -1; + str++; + } + + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + + if ((*str == ':') || (*str == '-')) + str++; + } + return 0; +} + +/* ********************************************************************* + * ETH_INCR_HWADDR(hwaddr,incr) + * + * Increment a 6-byte Ethernet hardware address, with carries + * + * Input parameters: + * hwaddr - pointer to hardware address + * incr - desired increment + * + * Return value: + * none + ********************************************************************* */ +static void +eth_incr_hwaddr(uint8_t *hwaddr, unsigned incr) +{ + int idx; + int carry; + + idx = 5; + carry = incr; + while (idx >= 0 && carry != 0) { + unsigned sum = hwaddr[idx] + carry; + + hwaddr[idx] = sum & 0xff; + carry = sum >> 8; + idx--; + } +} + + +/* ********************************************************************* + * Declarations for CFE Device Driver Interface routines + ********************************************************************* */ + +static int tulip_ether_open(cfe_devctx_t *ctx); +static int tulip_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tulip_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int tulip_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tulip_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tulip_ether_close(cfe_devctx_t *ctx); + +/* ********************************************************************* + * CFE Device Driver dispatch structure + ********************************************************************* */ + +const static cfe_devdisp_t tulip_ether_dispatch = { + tulip_ether_open, + tulip_ether_read, + tulip_ether_inpstat, + tulip_ether_write, + tulip_ether_ioctl, + tulip_ether_close, + NULL, + NULL +}; + +/* ********************************************************************* + * CFE Device Driver descriptor + ********************************************************************* */ + +const cfe_driver_t dc21143drv = { + "DC2114x Ethernet", + "eth", + CFE_DEV_NETWORK, + &tulip_ether_dispatch, + tulip_ether_probe +}; + + +static int +tulip_ether_attach(cfe_driver_t *drv, + pcitag_t tag, int index, uint8_t hwaddr[], int host) +{ + tulip_softc *softc; + uint32_t device; + uint32_t class; + uint32_t reg; + phys_addr_t pa; + char descr[100]; + uint8_t romaddr[ENET_ADDR_LEN]; +#if 0 /* temporary */ + int i; + uint8_t srom[SROM_SIZE]; +#endif + + device = pci_conf_read(tag, R_CFG_CFID); + + class = pci_conf_read(tag, R_CFG_CFRV); + + reg = pci_conf_read(tag, R_CFG_CPMS); + + reg = pci_conf_read(tag, R_CFG_CFDD); + pci_conf_write(tag, R_CFG_CFDD, 0); + reg = pci_conf_read(tag, R_CFG_CFDD); + +#if 1 + /* Use memory space for the CSRs */ + pci_map_mem(tag, R_CFG_CBMA, PCI_MATCH_BITS, &pa); +#else + /* Use i/o space for the CSRs */ + pci_map_io(tag, R_CFG_CBIO, PCI_MATCH_BITS, &pa); +#endif + + softc = (tulip_softc *) KMALLOC(sizeof(tulip_softc), 0); + if (softc == NULL) { + xprintf("DC2114x: No memory to complete probe\n"); + return 0; + } + + memset(softc, 0, sizeof(*softc)); + + softc->membase = (uint32_t)pa; + + /* If we are in Host mode, we can receive interrupts. Otherwise, + we can see the CSRs but our CPU will not get interrupts. */ + if (host) + softc->irq = pci_conf_read(tag, R_CFG_CFIT) & 0xFF; + else + softc->irq = 0xFF; + + softc->tag = tag; + softc->device = PCI_PRODUCT(device); + softc->revision = PCI_REVISION(class); +#if 1 + softc->linkspeed = ETHER_SPEED_AUTO; /* select autonegotiation */ +#else + softc->linkspeed = ETHER_SPEED_100HDX; /* 100 Mbps, full duplex */ +#endif + memcpy(softc->hwaddr, hwaddr, ENET_ADDR_LEN); + + tulip_init(softc); + + /* Prefer address in srom */ + if (srom_read_addr(softc, romaddr) == 0) + memcpy(softc->hwaddr, romaddr, ENET_ADDR_LEN); + + softc->state = eth_state_uninit; + + xsprintf(descr, "%s at 0x%X (%02x-%02x-%02x-%02x-%02x-%02x)", + drv->drv_description, softc->membase, + softc->hwaddr[0], softc->hwaddr[1], softc->hwaddr[2], + softc->hwaddr[3], softc->hwaddr[4], softc->hwaddr[5]); + cfe_attach(drv, softc, NULL, descr); + return 1; +} + + +/* ********************************************************************* + * TULIP_ETHER_PROBE(drv,probe_a,probe_b,probe_ptr) + * + * Probe and install drivers for all DC2114x Ethernet controllers. + * For each, creates a context structure and attaches to the + * specified MAC devices. + * + * Input parameters: + * drv - driver descriptor + * probe_a - not used + * probe_b - not used + * probe_ptr - string pointer to hardware address for the first + * MAC, in the form xx:xx:xx:xx:xx:xx + * + * Return value: + * nothing + ********************************************************************* */ +static void +tulip_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + int index; + int n; + uint8_t hwaddr[ENET_ADDR_LEN]; + + if (probe_ptr) + eth_parse_hwaddr((char *) probe_ptr, hwaddr); + else { + /* use default address 40-00-00-10-11-11 */ + hwaddr[0] = 0x40; hwaddr[1] = 0x00; + hwaddr[2] = 0x00; hwaddr[3] = 0x10; + hwaddr[4] = 0x11; hwaddr[5] = 0x11; + } + + n = 0; + index = 0; + for (;;) { + pcitag_t tag; + pcireg_t device; + + if (pci_find_class(PCI_CLASS_NETWORK, index, &tag) != 0) + break; + + index++; + + device = pci_conf_read(tag, R_CFG_CFID); + if (PCI_VENDOR(device) != K_PCI_VENDOR_DEC) + continue; + switch (PCI_PRODUCT(device)) { + case K_PCI_ID_DC21041: + break; + case K_PCI_ID_DC21140: + break; + case K_PCI_ID_DC21143: + break; + default: + continue; + } + + tulip_ether_attach(drv, tag, index, hwaddr, 1); + + n++; + eth_incr_hwaddr(hwaddr, 1); + } +} + + +/* The functions below are called via the dispatch vector for the 2114x. */ + +/* ********************************************************************* + * TULIP_ETHER_OPEN(ctx) + * + * Open the Ethernet device. The MAC is reset, initialized, and + * prepared to receive and send packets. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_open(cfe_devctx_t *ctx) +{ + tulip_softc *softc = ctx->dev_softc; + + if (softc->state == eth_state_on) + tulip_stop(softc); + + tulip_start(softc); + softc->state = eth_state_on; + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_READ(ctx,buffer) + * + * Read a packet from the Ethernet device. If no packets are + * available, the read will succeed but return 0 bytes. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tulip_softc *softc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + + if (softc->state != eth_state_on) return -1; + + tulip_isr(softc); + + pkt = (eth_pkt_t *) q_deqnext(&(softc->rxqueue)); + + if (pkt == NULL) { + buffer->buf_retlen = 0; + return 0; + } + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + memcpy(buffer->buf_ptr, pkt->buffer, blen); + buffer->buf_retlen = blen; + + eth_free_pkt(softc,pkt); + tulip_fillrxring(softc); + tulip_isr(softc); + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_INPSTAT(ctx,inpstat) + * + * Check for received packets on the Ethernet device + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * inpstat - pointer to input status structure + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + tulip_softc *softc = ctx->dev_softc; + + if (softc->state != eth_state_on) return -1; + + tulip_isr(softc); + + inpstat->inp_status = (q_isempty(&(softc->rxqueue))) ? 0 : 1; + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_WRITE(ctx,buffer) + * + * Write a packet to the Ethernet device. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tulip_softc *softc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + + if (softc->state != eth_state_on) return -1; + + pkt = eth_alloc_pkt(softc); + if (!pkt) return -1; + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + memcpy(pkt->buffer, buffer->buf_ptr, blen); + pkt->length = blen; + + tulip_isr(softc); + + if (tulip_transmit(softc, pkt) != 0) { + eth_free_pkt(softc,pkt); + return -1; + } + + tulip_isr(softc); + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_IOCTL(ctx,buffer) + * + * Do device-specific I/O control operations for the device + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tulip_softc *softc = ctx->dev_softc; + int mode; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_ETHER_GETHWADDR: + memcpy(buffer->buf_ptr, softc->hwaddr, sizeof(softc->hwaddr)); + return 0; + + case IOCTL_ETHER_SETHWADDR: + return -1; /* need to do this carefully */ + + /* XXX IOCTLs to set speed, etc.? */ + + case IOCTL_ETHER_GETLOOPBACK: + *((int *) buffer) = 0; /* XXX place holder */ + return 0; + + case IOCTL_ETHER_SETLOOPBACK: + tulip_stop(softc); + tulip_resetrings(softc); + mode = *((int *) buffer->buf_ptr); + if (mode == ETHER_LOOPBACK_INT || mode == ETHER_LOOPBACK_EXT) { + tulip_start_loopback(softc, mode); + } + else if (mode == ETHER_LOOPBACK_OFF) { + tulip_start(softc); + } + softc->state = eth_state_on; + return 0; + + default: + return -1; + } +} + +/* ********************************************************************* + * TULIP_ETHER_CLOSE(ctx) + * + * Close the Ethernet device. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_close(cfe_devctx_t *ctx) +{ + tulip_softc *softc = ctx->dev_softc; + + tulip_stop(softc); + softc->state = eth_state_off; + + /* resynchronize descriptor rings */ + tulip_resetrings(softc); + + return 0; +} diff --git a/cfe/cfe/dev/dev_dp83815.c b/cfe/cfe/dev/dev_dp83815.c new file mode 100644 index 0000000..b9fb644 --- /dev/null +++ b/cfe/cfe/dev/dev_dp83815.c @@ -0,0 +1,2290 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NS DP83815 Ethernet Driver File: dev_dp83815.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" + +#ifndef _SB_MAKE64 +#define _SB_MAKE64(x) ((uint64_t)(x)) +#endif +#ifndef _SB_MAKEMASK1 +#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n)) +#endif + +#include "lib_types.h" +#include "lib_hssubr.h" +#include "lib_malloc.h" +#include "lib_string.h" +#define blockcopy memcpy +#include "lib_printf.h" +#include "lib_queue.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_error.h" +#include "cfe_irq.h" + +#include "pcivar.h" +#include "pcireg.h" + +#include "dp83815.h" +#include "mii.h" + +/* This is a driver for the National Semiconductor DP83815 (MacPhyter) + 10/100 MAC with integrated PHY. + + The current version has been developed for the Netgear FA311 and + FA312 NICs. These include an EEPROM with automatically loaded + setup information that includes station address filtering. + Operation without such an EEPROM has not been tested. + + This SB1250 version takes advantage of DMA coherence and uses + "preserve bit lanes" addresses for all accesses that cross the + ZBbus-PCI bridge. */ + +#ifndef MACPHYTER_DEBUG +#define MACPHYTER_DEBUG 0 +#endif +#ifndef MACPHYTER_TEST +#define MACPHYTER_TEST 0 +#endif + +/* Set IPOLL to drive processing through the pseudo-interrupt + dispatcher. Set XPOLL to drive processing by an external polling + agent. Setting both is ok. */ + +#ifndef IPOLL +#define IPOLL 0 +#endif +#ifndef XPOLL +#define XPOLL 1 +#endif + +#define ENET_ADDR_LEN 6 /* size of an ethernet address */ +#define MIN_ETHER_PACK 64 /* min size of a packet */ +#define MAX_ETHER_PACK 1518 /* max size of a packet */ +#define CRC_SIZE 4 /* size of CRC field */ + +/* Packet buffers. For the DP83815, an rx packet must be aligned to a + 32-bit word boundary, and we would like it aligned to a cache line + boundary for performance. Also, the buffers "should" be allocated + in 32 byte multiples (5.3.2). */ + +#define ETH_PKTBUF_LEN (((MAX_ETHER_PACK+31)/32)*32) + +#if __long64 +typedef struct eth_pkt_s { + queue_t next; /* 16 */ + uint8_t *buffer; /* 8 */ + uint32_t flags; /* 4 */ + int32_t length; /* 4 */ + uint8_t data[ETH_PKTBUF_LEN]; +} eth_pkt_t; +#else +typedef struct eth_pkt_s { + queue_t next; /* 8 */ + uint8_t *buffer; /* 4 */ + uint32_t flags; /* 4 */ + int32_t length; /* 4 */ + uint32_t unused[3]; /* 12 */ + uint8_t data[ETH_PKTBUF_LEN]; +} eth_pkt_t; +#endif + +#define CACHE_ALIGN 32 +#define ETH_PKTBUF_LINES ((sizeof(eth_pkt_t) + (CACHE_ALIGN-1))/CACHE_ALIGN) +#define ETH_PKTBUF_SIZE (ETH_PKTBUF_LINES*CACHE_ALIGN) +#define ETH_PKTBUF_OFFSET (offsetof(eth_pkt_t, data)) + +#define ETH_PKT_BASE(data) ((eth_pkt_t *)((data) - ETH_PKTBUF_OFFSET)) + +/* packet flags */ +#define ETH_TX_SETUP 1 /* assumes Perfect Filtering format */ + +static void +show_packet(char c, eth_pkt_t *pkt) +{ + int i; + int n = (pkt->length < 32 ? pkt->length : 32); + + xprintf("%c[%4d]:", c, pkt->length); + for (i = 0; i < n; i++) { + if (i % 4 == 0) + xprintf(" "); + xprintf("%02x", pkt->buffer[i]); + } + xprintf("\n"); +} + + +/* Descriptor structures. NOTE: To avoid having descriptors straddle + cache lines, we append a pad word, ignored by DMA, to each. */ + +typedef struct rx_dscr { + pci_addr_t rxd_link; + uint32_t rxd_cmdsts; + pci_addr_t rxd_bufptr; + uint32_t rxd_pad; +} rx_dscr; + +typedef struct tx_dscr { + pci_addr_t txd_link; + uint32_t txd_cmdsts; + pci_addr_t txd_bufptr; + uint32_t txd_pad; +} tx_dscr; + + +/* Driver data structures */ + +typedef enum { + eth_state_uninit, + eth_state_off, + eth_state_on, + eth_state_broken +} eth_state_t; + +#define ETH_PKTPOOL_SIZE 32 + +typedef struct dp83815_softc { + uint32_t membase; + uint8_t irq; /* interrupt mapping (used if IPOLL) */ + pcitag_t tag; /* tag for configuration registers */ + + uint8_t hwaddr[ENET_ADDR_LEN]; + uint16_t device; /* chip device code */ + uint8_t revision; /* chip revision and step */ + + eth_state_t state; /* current state */ + uint32_t intmask; /* interrupt mask */ + + /* These fields are set before calling dp83815_hwinit */ + int linkspeed; /* encodings from cfe_ioctl */ + int loopback; + + /* Packet free list */ + queue_t freelist; + uint8_t *pktpool; + queue_t rxqueue; + + /* The descriptor tables */ + uint8_t *rxdscrmem; /* receive descriptors */ + uint8_t *txdscrmem; /* transmit descriptors */ + + /* These fields keep track of where we are in tx/rx processing */ + volatile rx_dscr *rxdscr_start; /* beginning of ring */ + volatile rx_dscr *rxdscr_end; /* end of ring */ + volatile rx_dscr *rxdscr_remove; /* next one we expect DMA to use */ + volatile rx_dscr *rxdscr_add; /* next place to put a buffer */ + int rxdscr_onring; + + volatile tx_dscr *txdscr_start; /* beginning of ring */ + volatile tx_dscr *txdscr_end; /* end of ring */ + volatile tx_dscr *txdscr_remove; /* next one we will use for tx */ + volatile tx_dscr *txdscr_add; /* next place to put a buffer */ + + cfe_devctx_t *devctx; + + /* These fields describe the PHY */ + int phy_addr; + int phy_check; + uint32_t phy_status; + + /* Statistics */ + uint32_t inpkts; + uint32_t outpkts; + uint32_t interrupts; + uint32_t rx_interrupts; + uint32_t tx_interrupts; + uint32_t bus_errors; +} dp83815_softc; + + +/* Entry to and exit from critical sections (currently relative to + interrupts only, not SMP) */ + +#if CFG_INTERRUPTS +#define CS_ENTER(sc) cfe_disable_irq(sc->irq) +#define CS_EXIT(sc) cfe_enable_irq(sc->irq) +#else +#define CS_ENTER(sc) ((void)0) +#define CS_EXIT(sc) ((void)0) +#endif + + +/* Driver parameterization */ + +#define MAXRXDSCR 32 +#define MAXTXDSCR 32 +#define MINRXRING 8 + + +/* Prototypes */ + +static void dp83815_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +/* Address mapping macros */ + +/* Note that PTR_TO_PHYS only works with 32-bit addresses, but then + so does the dp83815. */ +#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x))) +#define PHYS_TO_PTR(a) ((uint8_t *)PHYS_TO_K0(a)) + +/* All mappings through the PCI host bridge use match bits mode. */ +#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000) +#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF) + +#define PCI_TO_PTR(a) (PHYS_TO_PTR(PCI_TO_PHYS(a))) +#define PTR_TO_PCI(x) (PHYS_TO_PCI(PTR_TO_PHYS(x))) + +#if __long64 +#define READCSR(sc,csr) \ + (*((volatile uint32_t *) (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr))))) + +#define WRITECSR(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))) = (val)) + +#else +#define READCSR(sc,csr) \ + (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))) + +#define WRITECSR(sc,csr,val) \ + (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)), (val))) + +#endif + +#define RESET_ADAPTER(sc) \ + { \ + /* XXX */ \ + } + + +/* Debugging */ + +static void +dumpstat(dp83815_softc *sc) +{ + xprintf("-- CR = %08X CFG = %08x\n", + READCSR(sc, R_CR), READCSR(sc, R_CFG)); +} + +static void +dumpcsrs(dp83815_softc *sc) +{ + int reg; + + xprintf("-------------\n"); + for (reg = 0; reg < R_MIBC; reg += 4) { + xprintf("CSR %02X = %08X\n", reg, READCSR(sc, reg)); + } + xprintf("-------------\n"); +} + + +/* Packet management */ + +/* ********************************************************************* + * ETH_ALLOC_PKT(sc) + * + * Allocate a packet from the free list. + * + * Input parameters: + * sc - eth structure + * + * Return value: + * pointer to packet structure, or NULL if none available + ********************************************************************* */ +static eth_pkt_t * +eth_alloc_pkt(dp83815_softc *sc) +{ + eth_pkt_t *pkt; + + CS_ENTER(sc); + pkt = (eth_pkt_t *) q_deqnext(&sc->freelist); + CS_EXIT(sc); + if (!pkt) return NULL; + + pkt->buffer = pkt->data; + pkt->length = ETH_PKTBUF_LEN; + pkt->flags = 0; + + return pkt; +} + + +/* ********************************************************************* + * ETH_FREE_PKT(sc,pkt) + * + * Return a packet to the free list + * + * Input parameters: + * sc - sbmac structure + * pkt - packet to return + * + * Return value: + * nothing + ********************************************************************* */ +static void +eth_free_pkt(dp83815_softc *sc, eth_pkt_t *pkt) +{ + CS_ENTER(sc); + q_enqueue(&sc->freelist, &pkt->next); + CS_EXIT(sc); +} + + +/* ********************************************************************* + * ETH_INITFREELIST(sc) + * + * Initialize the buffer free list for this mac. The memory + * allocated to the free list is carved up and placed on a linked + * list of buffers for use by the mac. + * + * Input parameters: + * sc - eth structure + * + * Return value: + * nothing + ********************************************************************* */ +static void +eth_initfreelist(dp83815_softc *sc) +{ + int idx; + uint8_t *ptr; + eth_pkt_t *pkt; + + q_init(&sc->freelist); + + ptr = sc->pktpool; + for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) { + pkt = (eth_pkt_t *) ptr; + eth_free_pkt(sc, pkt); + ptr += ETH_PKTBUF_SIZE; + } +} + + +/* Utilities */ + +static const char * +dp83815_devname(dp83815_softc *sc) +{ + return (sc->devctx != NULL ? cfe_device_name(sc->devctx) : "eth?"); +} + + +/* Descriptor ring management */ + +static int +dp83815_add_rcvbuf(dp83815_softc *sc, eth_pkt_t *pkt) +{ + volatile rx_dscr *rxd; + volatile rx_dscr *nextrxd; + + rxd = sc->rxdscr_add; + + /* Figure out where the next descriptor will go */ + nextrxd = rxd+1; + if (nextrxd == sc->rxdscr_end) { + nextrxd = sc->rxdscr_start; + } + + /* + * If the next one is the same as our remove pointer, + * the ring is considered full. (it actually has room for + * one more, but we reserve the remove == add case for "empty") + */ + if (nextrxd == sc->rxdscr_remove) return -1; + + rxd->rxd_bufptr = PTR_TO_PCI(pkt->buffer); + rxd->rxd_cmdsts = M_DES1_INTR | V_DES1_SIZE(ETH_PKTBUF_LEN); + + /* success, advance the pointer */ + sc->rxdscr_add = nextrxd; + CS_ENTER(sc); + sc->rxdscr_onring++; + CS_EXIT(sc); + + return 0; +} + +static void +dp83815_fillrxring(dp83815_softc *sc) +{ + eth_pkt_t *pkt; + + while (1) { + CS_ENTER(sc); + if (sc->rxdscr_onring >= MINRXRING) { + CS_EXIT(sc); + break; + } + CS_EXIT(sc); + pkt = eth_alloc_pkt(sc); + if (pkt == NULL) { + /* could not allocate a buffer */ + break; + } + if (dp83815_add_rcvbuf(sc, pkt) != 0) { + /* could not add buffer to ring */ + eth_free_pkt(sc, pkt); + break; + } + } +} + + +/* ********************************************************************* + * DP83815_RX_CALLBACK(sc, pkt) + * + * Receive callback routine. This routine is invoked when a + * buffer queued for receives is filled. In this simple driver, + * all we do is add the packet to a per-MAC queue for later + * processing, and try to put a new packet in the place of the one + * that was removed from the queue. + * + * Input parameters: + * sc - interface + * ptk - packet context (eth_pkt structure) + * + * Return value: + * nothing + ********************************************************************* */ +static void +dp83815_rx_callback(dp83815_softc *sc, eth_pkt_t *pkt) +{ + if (MACPHYTER_DEBUG) show_packet('>', pkt); /* debug */ + + CS_ENTER(sc); + q_enqueue(&sc->rxqueue, &pkt->next); + CS_EXIT(sc); + sc->inpkts++; + + dp83815_fillrxring(sc); +} + + +static void +dp83815_procrxring(dp83815_softc *sc) +{ + volatile rx_dscr *rxd; + eth_pkt_t *pkt; + eth_pkt_t *newpkt; + uint32_t cmdsts; + + for (;;) { + rxd = (volatile rx_dscr *) sc->rxdscr_remove; + + cmdsts = rxd->rxd_cmdsts; + if ((cmdsts & M_DES1_OWN) == 0) { + /* end of ring, no more packets */ + break; + } + + pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufptr)); + pkt->length = G_DES1_SIZE(cmdsts) - CRC_SIZE; + + /* Drop error packets */ + if (cmdsts & M_DES1_RX_ERRORS) { +#if MACPHYTER_DEBUG + if (pkt->length >= MIN_ETHER_PACK - CRC_SIZE) + xprintf("%s: rx error %08X\n", dp83815_devname(sc), cmdsts); +#endif + dp83815_add_rcvbuf(sc, pkt); + goto next; + } + + /* Pass up the packet */ + dp83815_rx_callback(sc, pkt); + + /* put a buffer back on the ring to replace this one */ + newpkt = eth_alloc_pkt(sc); + if (newpkt) dp83815_add_rcvbuf(sc, newpkt); + +next: + /* update the pointer, accounting for buffer wrap. */ + rxd++; + if (rxd == sc->rxdscr_end) + rxd = sc->rxdscr_start; + + sc->rxdscr_remove = (rx_dscr *) rxd; + CS_ENTER(sc); + sc->rxdscr_onring--; + CS_EXIT(sc); + } +} + + +static int +dp83815_add_txbuf(dp83815_softc *sc, eth_pkt_t *pkt) +{ + volatile tx_dscr *txd; + volatile tx_dscr *nexttxd; + + txd = sc->txdscr_add; + + /* Figure out where the next descriptor will go */ + nexttxd = (txd+1); + if (nexttxd == sc->txdscr_end) { + nexttxd = sc->txdscr_start; + } + + /* If the next one is the same as our remove pointer, + the ring is considered full. (it actually has room for + one more, but we reserve the remove == add case for "empty") */ + + if (nexttxd == sc->txdscr_remove) return -1; + + txd->txd_bufptr = PTR_TO_PCI(pkt->buffer); + txd->txd_cmdsts = M_DES1_INTR | M_DES1_OWN | V_DES1_SIZE(pkt->length); + + /* success, advance the pointer */ + sc->txdscr_add = nexttxd; + + return 0; +} + + +static int +dp83815_transmit(dp83815_softc *sc,eth_pkt_t *pkt) +{ + int rv; + + if (MACPHYTER_DEBUG) show_packet('<', pkt); /* debug */ + + rv = dp83815_add_txbuf(sc, pkt); + sc->outpkts++; + + WRITECSR(sc, R_CR, M_CR_TXE | M_CR_RXE); + return rv; +} + + +static void +dp83815_proctxring(dp83815_softc *sc) +{ + volatile tx_dscr *txd; + eth_pkt_t *pkt; + uint32_t cmdsts; + + for (;;) { + txd = (volatile tx_dscr *) sc->txdscr_remove; + + if (txd == sc->txdscr_add) { + /* ring is empty, no buffers to process */ + break; + } + + cmdsts = txd->txd_cmdsts; + if (cmdsts & M_DES1_OWN) { + /* Reached a packet still being transmitted */ + break; + } + + /* Just free the packet */ + pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufptr)); + eth_free_pkt(sc, pkt); + + /* update the pointer, accounting for buffer wrap. */ + txd++; + if (txd == sc->txdscr_end) + txd = sc->txdscr_start; + + sc->txdscr_remove = (tx_dscr *) txd; + } +} + + +static void +dp83815_initrings(dp83815_softc *sc) +{ + volatile tx_dscr *txd, *txn; + volatile rx_dscr *rxd, *rxn; + + /* Claim ownership of all descriptors for the driver */ + + for (txd = sc->txdscr_start; txd != sc->txdscr_end; txd++) { + txn = txd + 1; + if (txn == sc->txdscr_end) txn = sc->txdscr_start; + txd->txd_link = PTR_TO_PCI(txn); + txd->txd_cmdsts = 0; + txd->txd_pad = 0; + } + for (rxd = sc->rxdscr_start; rxd != sc->rxdscr_end; rxd++) { + rxn = rxd + 1; + if (rxn == sc->rxdscr_end) rxn = sc->rxdscr_start; + rxd->rxd_link = PTR_TO_PCI(rxn); + rxd->rxd_cmdsts = M_DES1_OWN; + rxd->rxd_pad = 0; + } + + /* Init the ring pointers */ + + sc->txdscr_add = sc->txdscr_remove = sc->txdscr_start; + sc->rxdscr_add = sc->rxdscr_remove = sc->rxdscr_start; + sc->rxdscr_onring = 0; + + /* Add stuff to the receive ring */ + + dp83815_fillrxring(sc); +} + + +static int +dp83815_init(dp83815_softc *sc) +{ + /* Allocate descriptor rings */ + sc->rxdscrmem = KMALLOC(MAXRXDSCR*sizeof(rx_dscr), sizeof(rx_dscr)); + sc->txdscrmem = KMALLOC(MAXTXDSCR*sizeof(tx_dscr), sizeof(tx_dscr)); + + /* Allocate buffer pool */ + sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, CACHE_ALIGN); + eth_initfreelist(sc); + q_init(&sc->rxqueue); + + /* Fill in pointers to the rings */ + sc->rxdscr_start = (rx_dscr *) (sc->rxdscrmem); + sc->rxdscr_end = sc->rxdscr_start + MAXRXDSCR; + sc->rxdscr_add = sc->rxdscr_start; + sc->rxdscr_remove = sc->rxdscr_start; + sc->rxdscr_onring = 0; + + sc->txdscr_start = (tx_dscr *) (sc->txdscrmem); + sc->txdscr_end = sc->txdscr_start + MAXTXDSCR; + sc->txdscr_add = sc->txdscr_start; + sc->txdscr_remove = sc->txdscr_start; + + dp83815_initrings(sc); + + return 0; +} + + +static void +dp83815_resetrings(dp83815_softc *sc) +{ + volatile tx_dscr *txd; + volatile rx_dscr *rxd; + eth_pkt_t *pkt; + + /* Free already-sent descriptors and buffers */ + dp83815_proctxring(sc); + + /* Free any pending but unsent */ + txd = (volatile tx_dscr *) sc->txdscr_remove; + while (txd != sc->txdscr_add) { + txd->txd_cmdsts &=~ M_DES1_OWN; + pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufptr)); + eth_free_pkt(sc, pkt); + + txd++; + if (txd == sc->txdscr_end) + txd = sc->txdscr_start; + } + sc->txdscr_add = sc->txdscr_remove; + + /* Discard any received packets as well as all free buffers */ + rxd = (volatile rx_dscr *) sc->rxdscr_remove; + while (rxd != sc->rxdscr_add) { + rxd->rxd_cmdsts |= M_DES1_OWN; + pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufptr)); + eth_free_pkt(sc, pkt); + + rxd++; + if (rxd == sc->rxdscr_end) + rxd = sc->rxdscr_start; + CS_ENTER(sc); + sc->rxdscr_onring--; + CS_EXIT(sc); + } + + /* Reestablish the initial state. */ + dp83815_initrings(sc); +} + + +#if 0 /* XXX Multicast filtering not yet implemented. */ +/* CRCs */ + +#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */ + +static uint32_t +dp83815_crc32(const uint8_t *databuf, unsigned int datalen) +{ + unsigned int idx, bit, data; + uint32_t crc; + + crc = 0xFFFFFFFFUL; + for (idx = 0; idx < datalen; idx++) + for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0); + return crc; +} + +#define dp83815_mchash(mca) (dp83815_crc32((mca), 6) & 0x1FF) +#endif + + +#if MACPHYTER_TEST +/* EEPROM access */ + +/* Current NICs use the EEPROM auto-load feature and there is no need + for explicit EEPROM access. The following routines are included + for future applications and have been tested (Netgear FA311). */ + +/**************************************************************************** + * dp83815_spin(sc, ns) + * + * Spin for a short interval (nominally in nanoseconds) + * + * Input Parameters: ns - minimum required nsec. + * + * The delay loop uses uncached PCI reads, each of which requires + * at least 3 PCI bus clocks (45 ns at 66 MHz) to complete. The + * actual delay will be longer (much longer if preempted). + ***************************************************************************/ + +#define PCI_MIN_DELAY 45 + +static void +dp83815_spin(dp83815_softc *sc, long nanoseconds) +{ + long delay; + volatile uint32_t t; + + for (delay = nanoseconds; delay > 0; delay -= PCI_MIN_DELAY) + t = READCSR(sc, R_SRR); +} + + +/* + * The recommended EEPROM is the NM9306. + * Delays below are chosen to meet specs for NS93C64 (slow M variant). + * Current parts are faster. + * Reference: NS Memory Data Book, 1994 + */ + +#define EEPROM_SIZE (2*0x0C) +#define EEPROM_MAX_CYCLES 32 + +#define EEPROM_CMD_BITS 3 +#define EEPROM_ADDR_BITS 6 + +#define K_EEPROM_READ_CMD 06 +#define K_EEPROM_WRITE_CMD 05 + +#define EEPROM_CRC_INDEX (EEPROM_SIZE-2) + +#define EEPROM_WORD(rom,offset) ((rom)[offset] | ((rom)[offset+1] << 8)) + +static void +eeprom_idle_state(dp83815_softc *sc) +{ + uint32_t ctrl; + unsigned int i; + + ctrl = READCSR(sc, R_MEAR); + + ctrl |= M_MEAR_EESEL; + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 100); /* CS setup (Tcss=100) */ + + /* Run the clock through the maximum number of pending read cycles */ + for (i = 0; i < EEPROM_MAX_CYCLES*2; i++) { + ctrl ^= M_MEAR_EECLK; + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 1000); /* SK period (Fsk=0.5MHz) */ + } + + /* Deassert EEPROM Chip Select */ + ctrl &=~ M_MEAR_EESEL; + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 50); /* CS recovery (Tsks=50) */ +} + +static void +eeprom_send_command_bit(dp83815_softc *sc, unsigned int data) +{ + uint32_t ctrl; + + ctrl = READCSR(sc, R_MEAR); + + /* Place the data bit on the bus */ + if (data == 1) + ctrl |= M_MEAR_EEDI; + else + ctrl &=~ M_MEAR_EEDI; + + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 360); /* setup: Tdis=200 */ + + /* Now clock the data into the EEPROM */ + WRITECSR(sc, R_MEAR, ctrl | M_MEAR_EECLK); + dp83815_spin(sc, 900); /* clock high, Tskh=500 */ + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 450); /* clock low, Tskl=250 */ + + /* Now clear the data bit */ + ctrl &=~ M_MEAR_EEDI; /* data invalid, Tidh=20 for SK^ */ + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 270); /* min cycle, 1/Fsk=2000 */ +} + +static uint16_t +eeprom_read_bit(dp83815_softc *sc) +{ + uint32_t ctrl; + + ctrl = READCSR(sc, R_MEAR); + + /* Generate a clock cycle before doing a read */ + WRITECSR(sc, R_MEAR, ctrl | M_MEAR_EECLK); /* rising edge */ + dp83815_spin(sc, 1000); /* clock high, Tskh=500, Tpd=1000 */ + WRITECSR(sc, R_MEAR, ctrl); /* falling edge */ + dp83815_spin(sc, 1000); /* clock low, 1/Fsk=2000 */ + + ctrl = READCSR(sc, R_MEAR); + return ((ctrl & M_MEAR_EEDO) != 0 ? 1 : 0); +} + +#define CMD_BIT_MASK (1 << (EEPROM_CMD_BITS+EEPROM_ADDR_BITS-1)) + +static uint16_t +eeprom_read_word(dp83815_softc *sc, unsigned int index) +{ + uint16_t command, word; + uint32_t ctrl; + unsigned int i; + + ctrl = READCSR(sc, R_MEAR) | M_MEAR_EESEL; + + /* Assert the EEPROM CS line */ + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 100); /* CS setup, Tcss = 100 */ + + /* Send the read command to the EEPROM */ + command = (K_EEPROM_READ_CMD << EEPROM_ADDR_BITS) | index; + for (i = 0; i < EEPROM_CMD_BITS+EEPROM_ADDR_BITS; i++) { + eeprom_send_command_bit(sc, (command & CMD_BIT_MASK) != 0 ? 1 : 0); + command <<= 1; + } + + /* Now read the bits from the EEPROM (MSB first) */ + word = 0; + for (i = 0; i < 16; ++i) { + word <<= 1; + word |= eeprom_read_bit(sc); + } + + /* Clear the EEPROM CS Line, CS hold, Tcsh = 0 */ + WRITECSR(sc, R_MEAR, ctrl &~ M_MEAR_EESEL); + + return word; +} + + +/**************************************************************************** + * eeprom_checksum() + * + * Calculate the checksum of the EEPROM and return it. See Section + * 4.2.4 for the algorithm. + ***************************************************************************/ + +static uint16_t +eeprom_checksum(const uint8_t rom[]) +{ + uint16_t sum; + int i; + + sum = 0; + for (i = 0; i < EEPROM_SIZE-1; i++) + sum += rom[i]; + sum ^= 0xFF; + return (((sum + 1) & 0xFF) << 8) | 0x55; +} + + +/**************************************************************************** + * eeprom_read_all(sc, uint8_t dest) + * + * Read the entire EEPROM into the srom array + * + * Input parameters: + * sc - dp83815 state + ***************************************************************************/ + +static int +eeprom_read_all(dp83815_softc *sc, uint8_t dest[]) +{ + int i; + uint16_t cksum, temp; + + WRITECSR(sc, R_MEAR, M_MEAR_EESEL); + + eeprom_idle_state(sc); + + for (i = 0; i < EEPROM_SIZE/2; i++) { + temp = eeprom_read_word(sc, i); + dest[2*i] = temp & 0xFF; + dest[2*i+1] = temp >> 8; + } + + WRITECSR(sc, R_MEAR, 0); /* CS hold, Tcsh=0 */ + + cksum = eeprom_checksum(dest);; + if (cksum != EEPROM_WORD(dest, EEPROM_CRC_INDEX)) { + xprintf("%s: Invalid EEPROM CHECKSUM, calc %04x, stored %04x\n", + dp83815_devname(sc), + cksum, EEPROM_WORD(dest, EEPROM_CRC_INDEX)); + return 0/*-1*/; + } + return 0; +} + +static int +eeprom_read_addr(const uint8_t rom[], uint8_t buf[]) +{ + uint16_t s; + unsigned offset, mask; + int i, j; + + if (eeprom_checksum(rom) != EEPROM_WORD(rom, EEPROM_SIZE-2)) + return -1; + + s = 0; + offset = 2*6; mask = 0x1; + i = j = 0; + do { + s >>= 1; + if ((EEPROM_WORD(rom, offset) & mask) != 0) s |= 0x8000; + mask >>= 1; + if (mask == 0) { + offset +=2; mask = 0x8000; + } + i++; + if (i % 16 == 0) { + buf[j++] = s & 0xFF; + buf[j++] = s >> 8; + s = 0; + } + } while (i < ENET_ADDR_LEN*8); + + return 0; +} +#endif /* MACPHYTER_TEST */ + +#if 0 +static void +eeprom_dump(uint8_t srom[]) +{ + int i; + + xprintf("DP83815: EEPROM data:"); + for (i = 0; i < EEPROM_SIZE; i++) { + if (i % 16 == 0) + xprintf("\n %02x: ", i); + xprintf(" %02x", srom[i]); + } + xprintf("\n"); +} +#else +#define eeprom_dump(srom) +#endif + + +static int +dp83815_get_pm_addr(dp83815_softc *sc, uint8_t buf[]) +{ + uint32_t rfcr; + unsigned rfaddr; + unsigned i; + uint32_t rfdata; + + rfcr = READCSR(sc, R_RFCR); + rfaddr = K_RFCR_PMATCH_ADDR; + + for (i = 0; i < ENET_ADDR_LEN/2; i++) { + rfcr &=~ M_RFCR_RFADDR; + rfcr |= V_RFCR_RFADDR(rfaddr); + WRITECSR(sc, R_RFCR, rfcr); + rfdata = READCSR(sc, R_RFDR); + buf[2*i] = rfdata & 0xFF; + buf[2*i+1] = (rfdata >> 8) & 0xFF; + rfaddr += 2; + } + + return 0; +} + + +#if MACPHYTER_TEST +/* MII access */ + +/* Current NICs use the internal PHY, which can be accessed more + simply via internal registers. The following routines are + primarily for management access to an external PHY and are retained + for future applications. They have been tested on a Netgear FA311. */ + +/**************************************************************************** + * MII access utility routines + ***************************************************************************/ + +/* MII clock limited to 2.5 MHz (DP83815 allows 25 MHz), transactions + end with MDIO tristated */ + +static void +mii_write_bits(dp83815_softc *sc, uint32_t data, unsigned int count) +{ + uint32_t ctrl; + uint32_t bitmask; + + ctrl = READCSR(sc, R_MEAR) & ~M_MEAR_MDC; + ctrl |= M_MEAR_MDDIR; + + for (bitmask = 1 << (count-1); bitmask != 0; bitmask >>= 1) { + ctrl &=~ M_MEAR_MDIO; + if ((data & bitmask) != 0) ctrl |= M_MEAR_MDIO; + WRITECSR(sc, R_MEAR, ctrl); + + dp83815_spin(sc, 2000); /* setup */ + WRITECSR(sc, R_MEAR, ctrl | M_MEAR_MDC); + dp83815_spin(sc, 2000); /* hold */ + WRITECSR(sc, R_MEAR, ctrl); + } +} + +static void +mii_turnaround(dp83815_softc *sc) +{ + uint32_t ctrl; + + ctrl = READCSR(sc, R_MEAR) &~ M_MEAR_MDDIR; + + /* stop driving data */ + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 2000); /* setup */ + WRITECSR(sc, R_MEAR, ctrl | M_MEAR_MDC); + dp83815_spin(sc, 2000); /* clock high */ + WRITECSR(sc, R_MEAR, ctrl); + + /* read back and check for 0 here? */ +} + +/**************************************************************************** + * mii_read_register + * + * This routine reads a register from the PHY chip using the MII + * serial management interface. + * + * Input parameters: + * index - index of register to read (0-31) + * + * Return value: + * word read from register + ***************************************************************************/ + +static uint16_t +mii_read_register(dp83815_softc *sc, unsigned int index) +{ + /* Send the command and address to the PHY. The sequence is + a synchronization sequence (32 1 bits) + a "start" command (2 bits) + a "read" command (2 bits) + the PHY addr (5 bits) + the register index (5 bits) + */ + uint32_t ctrl; + uint16_t word; + int i; + + mii_write_bits(sc, 0xFF, 8); + mii_write_bits(sc, 0xFFFFFFFF, 32); + mii_write_bits(sc, MII_COMMAND_START, 2); + mii_write_bits(sc, MII_COMMAND_READ, 2); + mii_write_bits(sc, sc->phy_addr, 5); + mii_write_bits(sc, index, 5); + + mii_turnaround(sc); + + ctrl = READCSR(sc, R_MEAR) &~ (M_MEAR_MDC | M_MEAR_MDDIR); + word = 0; + + for (i = 0; i < 16; i++) { + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 2000); /* clock width low */ + WRITECSR(sc, R_MEAR, ctrl | M_MEAR_MDC); + dp83815_spin(sc, 2000); /* clock width high */ + WRITECSR(sc, R_MEAR, ctrl); + dp83815_spin(sc, 1000); /* output delay */ + word <<= 1; + if ((READCSR(sc, R_MEAR) & M_MEAR_MDIO) != 0) + word |= 0x0001; + } + + return word; + + /* reset to output mode? */ +} + +/**************************************************************************** + * mii_write_register + * + * This routine writes a register in the PHY chip using the MII + * serial management interface. + * + * Input parameters: + * index - index of register to write (0-31) + * value - word to write + ***************************************************************************/ + +static void +mii_write_register(dp83815_softc *sc, unsigned int index, uint16_t value) +{ + mii_write_bits(sc, 0xFF, 8); + mii_write_bits(sc, 0xFFFFFFFF, 32); + mii_write_bits(sc, MII_COMMAND_START, 2); + mii_write_bits(sc, MII_COMMAND_WRITE, 2); + mii_write_bits(sc, sc->phy_addr, 5); + mii_write_bits(sc, index, 5); + mii_write_bits(sc, MII_COMMAND_ACK, 2); + mii_write_bits(sc, value, 16); + + /* reset to input mode? */ +} + + +static int +mii_probe(dp83815_softc *sc) +{ + int i; + uint16_t id1, id2; + + /* Empirically, bit-banged access will return register 0 of the + integrated PHY for all registers of all unpopulated PHY + addresses. */ + for (i = 0; i < 32; i++) { + sc->phy_addr = i; + id1 = mii_read_register(sc, MII_PHYIDR1); + id2 = mii_read_register(sc, MII_PHYIDR2); + if ((id1 != 0x0000 && id1 != 0xFFFF) || + (id2 != 0x0000 && id2 != 0xFFFF)) { + if (id1 != id2) return 0; + } + } + return -1; +} + +#if 0 +#define OUI_NAT_SEMI 0x080017 +#define IDR_NAT_SEMI 0x080017 /* NSC does not bit-reverse each byte */ +#define PART_83815 0x02 + +static void +mii_dump(dp83815_softc *sc, const char *label) +{ + int i; + uint16_t r; + uint32_t idr, part; + + xprintf("%s\n", label); + idr = 0; + for (i = 0; i <= 6; ++i) { + r = mii_read_register(sc, i); + xprintf("MII_REG%02x: %04x\n", i, r); + if (i == MII_PHYIDR1) { + idr |= r << 6; + } + else if (i == MII_PHYIDR2) { + idr |= (r >> 10) & 0x3F; + part = (r >> 4) & 0x3F; + } + } + if (idr == IDR_NAT_SEMI && part == PART_83815) { + r = mii_read_register(sc, 7); + xprintf("MII_REG%02x: %04x\n", i, r); + for (i = 0x10; i <= 0x16; ++i) { + r = mii_read_register(sc, i); + xprintf("MII_REG%02x: %04x\n", i, r); + } + for (i = 0x19; i <= 0x1A; ++i) { + r = mii_read_register(sc, i); + xprintf("MII_REG%02x: %04x\n", i, r); + } + } +} +#else +#define mii_dump(sc,label) +#endif + + +/* The following functions are suitable for explicit MII access. */ + +static void +mii_set_speed(dp83815_softc *sc, int speed) +{ + uint16_t control; + + control = mii_read_register(sc, MII_BMCR); + + control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + control &=~ (BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX); + + switch (speed) { + case ETHER_SPEED_10HDX: + default: + break; + case ETHER_SPEED_10FDX: + control |= BMCR_DUPLEX; + break; + case ETHER_SPEED_100HDX: + control |= BMCR_SPEED100; + break; + case ETHER_SPEED_100FDX: + control |= BMCR_SPEED100 | BMCR_DUPLEX ; + break; + } + + mii_write_register(sc, MII_BMCR, control); +} + +static void +mii_autonegotiate(dp83815_softc *sc) +{ + uint16_t control, status, cap; + int timeout; + int linkspeed; + + linkspeed = ETHER_SPEED_UNKNOWN; + + /* Read twice to clear latching bits */ + status = mii_read_register(sc, MII_BMSR); + status = mii_read_register(sc, MII_BMSR); + mii_dump(sc, "query PHY"); + + if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) == + (BMSR_AUTONEG | BMSR_LINKSTAT)) + control = mii_read_register(sc, MII_BMCR); + else { + /* reset the PHY */ + mii_write_register(sc, MII_BMCR, BMCR_RESET); + timeout = 3*CFE_HZ; + for (;;) { + control = mii_read_register(sc, MII_BMCR); + if ((control && BMCR_RESET) == 0 || timeout <= 0) + break; + cfe_sleep(CFE_HZ/2); + timeout -= CFE_HZ/2; + } + if ((control & BMCR_RESET) != 0) { + xprintf("%s: PHY reset failed\n", dp83815_devname(sc)); + return; + } + + status = mii_read_register(sc, MII_BMSR); + cap = ((status >> 6) & (ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD)) + | PSB_802_3; + mii_write_register(sc, MII_ANAR, cap); + control |= (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + + timeout = 3*CFE_HZ; + for (;;) { + status = mii_read_register(sc, MII_BMSR); + if ((status & BMSR_ANCOMPLETE) != 0 || timeout <= 0) + break; + cfe_sleep(CFE_HZ/2); + timeout -= CFE_HZ/2; + } + mii_dump(sc, "done PHY"); + } + + xprintf("%s: Link speed: ", dp83815_devname(sc)); + if ((status & BMSR_ANCOMPLETE) != 0) { + /* A link partner was negogiated... */ + + uint16_t remote = mii_read_register(sc, MII_ANLPAR); + + if ((remote & ANLPAR_TXFD) != 0) { + xprintf("100BaseT FDX\n"); + linkspeed = ETHER_SPEED_100FDX; + } + else if ((remote & ANLPAR_TXHD) != 0) { + xprintf("100BaseT HDX\n"); + linkspeed = ETHER_SPEED_100HDX; + } + else if ((remote & ANLPAR_10FD) != 0) { + xprintf("10BaseT FDX\n"); + linkspeed = ETHER_SPEED_10FDX; + } + else if ((remote & ANLPAR_10HD) != 0) { + xprintf("10BaseT HDX\n"); + linkspeed = ETHER_SPEED_10HDX; + } + } + else { + /* no link partner negotiation */ + control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + xprintf("10BaseT HDX (assumed)\n"); + linkspeed = ETHER_SPEED_10HDX; + if ((status & BMSR_LINKSTAT) == 0) + mii_write_register(sc, MII_BMCR, control); + mii_set_speed(sc, linkspeed); + } + + status = mii_read_register(sc, MII_BMSR); /* clear latching bits */ + mii_dump(sc, "final PHY"); +} +#endif /* MACPHYTER_TEST */ + + +static void +dp83815_phyupdate(dp83815_softc *sc, uint32_t status) +{ + xprintf("%s: Link speed: ", dp83815_devname(sc)); + if ((status & M_CFG_LNKSTS) != 0) { + switch (status & (M_CFG_SPEED100 | M_CFG_FDUP)) { + case (M_CFG_SPEED100 | M_CFG_FDUP): + sc->linkspeed = ETHER_SPEED_100FDX; + xprintf("100BaseT FDX\n"); + break; + case (M_CFG_SPEED100): + sc->linkspeed = ETHER_SPEED_100HDX; + xprintf("100BaseT HDX\n"); + break; + case (M_CFG_FDUP): + sc->linkspeed = ETHER_SPEED_10FDX; + xprintf("10BaseT FDX\n"); + break; + default: + sc->linkspeed = ETHER_SPEED_10HDX; + xprintf("10BaseT HDX\n"); + break; + } + if ((status & M_CFG_SPEED100) != 0) { + uint32_t t; + + /* This is a reputed fix that improves 100BT rx + performance on short cables with "a small number" + of DP83815 chips. It comes from Bruce at NatSemi + via the Soekris support web page (see appended + note). */ + + WRITECSR(sc, R_PGSEL, 0x0001); + (void)READCSR(sc, R_PGSEL); /* push */ + t = READCSR(sc, R_DSPCFG); + WRITECSR(sc, R_DSPCFG, (t & 0xFFF) | 0x1000); + cfe_sleep(1); + t = READCSR(sc, R_TSTDAT) & 0xFF; + if ((t & 0x0080) == 0 || ((t > 0x00D8) && (t <= 0x00FF))) { + WRITECSR(sc, R_TSTDAT, 0x00E8); + t = READCSR(sc, R_DSPCFG); + WRITECSR(sc, R_DSPCFG, t | 0x0020); + } + WRITECSR(sc, R_PGSEL, 0); + } + if ((status & M_CFG_FDUP) != (sc->phy_status & M_CFG_FDUP)) { + uint32_t txcfg; + + txcfg = READCSR(sc, R_TXCFG); + if (status & M_CFG_FDUP) + txcfg |= M_TXCFG_CSI; + else + txcfg &= ~M_TXCFG_CSI; + WRITECSR(sc, R_RXCFG, txcfg); + } + } + else { + xprintf("Unknown\n"); + } + + sc->phy_status = status; +} + +static void +dp83815_hwinit(dp83815_softc *sc) +{ + if (sc->state == eth_state_uninit) { + uint32_t cfg; + uint32_t txcfg, rxcfg; + uint32_t ready; + int timeout; + + /* RESET_ADAPTER(sc); */ + sc->state = eth_state_off; + sc->bus_errors = 0; + + cfg = READCSR(sc, R_CFG); + cfg |= M_CFG_BEM; /* We will use match bits */ + WRITECSR(sc, R_CFG, cfg); + + sc->phy_status = 0; + dp83815_phyupdate(sc, cfg & M_CFG_LNKSUMMARY); + + txcfg = READCSR(sc, R_TXCFG); + txcfg |= M_TXCFG_ATP; + /* XXX fix up FLTH, DRTH? */ + WRITECSR(sc, R_TXCFG, txcfg); + + rxcfg = READCSR(sc, R_RXCFG); + /* Set an aggressive rx drain threshhold of 16 (2*8) bytes */ + rxcfg &= ~M_RXCFG_DRTH; + rxcfg |= V_RXCFG_DRTH(2); + WRITECSR(sc, R_RXCFG, rxcfg); + +#if MACPHYTER_TEST + { + uint8_t srom[EEPROM_SIZE]; + uint8_t addr[ENET_ADDR_LEN]; + + eeprom_read_all(sc, srom); + eeprom_dump(srom); + xprintf(" checksum %04x\n", eeprom_checksum(srom)); + if (eeprom_read_addr(srom, addr) == 0) + xprintf(" addr: %02x-%02x-%02x-%02x-%02x-%02x\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + + mii_probe(sc); + xprintf("MII address %02x\n", sc->phy_addr); + mii_dump(sc, "DP83815 PHY:"); + (void)mii_autonegotiate; + } +#endif /* MACPHYTER_TEST */ + + /* XXX fix up rx filtering here. We are relying on the EEPROM. */ + + /* XXX This is inappropriate on a restart. */ + timeout = 2*CFE_HZ; + ready = 0; + for (;;) { + ready |= READCSR(sc, R_ISR); + if ((ready & (M_INT_TXRCMP | M_INT_RXRCMP)) + == (M_INT_TXRCMP | M_INT_RXRCMP) || timeout <= 0) + break; + cfe_sleep(CFE_HZ/10); + timeout -= CFE_HZ/10; + } + if ((ready & M_INT_TXRCMP) == 0) + xprintf("%s: tx reset failed\n", dp83815_devname(sc)); + if ((ready & M_INT_RXRCMP) == 0) + xprintf("%s: rx reset failed\n", dp83815_devname(sc)); + } +} + +static void +dp83815_setspeed(dp83815_softc *sc, int speed) +{ + /* XXX Not yet implemented - autonegotiation only. */ +} + +static void +dp83815_setloopback(dp83815_softc *sc, int mode) +{ + /* XXX Not yet implemented. */ +} + + +static void +dp83815_isr(void *arg) +{ + dp83815_softc *sc = (dp83815_softc *)arg; + uint32_t status; + uint32_t isr; + +#if IPOLL + sc->interrupts++; +#endif + + for (;;) { + + /* Read (and clear) the interrupt status. */ + isr = READCSR(sc, R_ISR); + status = isr & sc->intmask; + + /* if there are no more interrupts, leave now. */ + if (status == 0) break; + + /* Now, test each unmasked bit in the interrupt register and + handle each interrupt type appropriately. */ + + if (status & (M_INT_RTABT | M_INT_RMABT)) { + WRITECSR(sc, R_IER, 0); + + xprintf("%s: bus error\n", dp83815_devname(sc)); + dumpstat(sc); + sc->bus_errors++; + if (sc->bus_errors >= 2) { + dumpcsrs(sc); + RESET_ADAPTER(sc); + sc->state = eth_state_off; + sc->bus_errors = 0; + } +#if IPOLL + else + WRITECSR(sc, R_IMR, sc->intmask); +#endif + } + + if (status & M_INT_RXDESC) { +#if IPOLL + sc->rx_interrupts++; +#endif + dp83815_procrxring(sc); + } + + if (status & M_INT_TXDESC) { +#if IPOLL + sc->tx_interrupts++; +#endif + dp83815_proctxring(sc); + } + + if (status & (M_INT_TXURN | M_INT_RXORN)) { + if (status & M_INT_TXURN) { + xprintf("%s: tx underrun, %08x\n", dp83815_devname(sc), isr); + /* XXX Try to restart */ + } + if (status & M_INT_RXORN) { + xprintf("%s: tx overrun, %08x\n", dp83815_devname(sc), isr); + /* XXX Try to restart */ + } + } + + if (status & M_INT_PHY) { + sc->intmask &= ~ M_INT_PHY; + WRITECSR(sc, R_IMR, sc->intmask); + (void)READCSR(sc, R_MISR); /* Clear at PHY */ + sc->phy_check = 1; + } + + } +} + +static void +dp83815_checkphy(dp83815_softc *sc) +{ + uint32_t cfg; + uint32_t status; + + (void)READCSR(sc, R_MISR); /* Clear at PHY */ + cfg = READCSR(sc, R_CFG); + status = cfg & M_CFG_LNKSUMMARY; + if (status != sc->phy_status) { + /* XXX Can we really do the phy update with active rx and tx? */ + dp83815_phyupdate(sc, status); + } + + sc->intmask |= M_INT_PHY; + WRITECSR(sc, R_IMR, sc->intmask); +} + + +static void +dp83815_start(dp83815_softc *sc) +{ + dp83815_hwinit(sc); + + /* Set up loopback here */ + + sc->intmask = 0; + WRITECSR(sc, R_IER, 0); /* no interrupts */ + WRITECSR(sc, R_IMR, 0); + (void)READCSR(sc, R_ISR); /* clear any pending */ + + sc->phy_status = READCSR(sc, R_CFG) & M_CFG_LNKSUMMARY; + sc->phy_check = 0; + + sc->intmask = M_INT_RXDESC | M_INT_TXDESC; + sc->intmask |= M_INT_RTABT | M_INT_RMABT | M_INT_RXORN | M_INT_TXURN; + sc->intmask |= M_INT_PHY; + +#if IPOLL + cfe_request_irq(sc->irq, dp83815_isr, sc, CFE_IRQ_FLAGS_SHARED, 0); + WRITECSR(sc, R_IMR, sc->intmask); + WRITECSR(sc, R_IER, M_IER_IE); +#endif + + (void)READCSR(sc, R_MISR); /* clear any pending */ + WRITECSR(sc, R_MISR, MISR_MSKJAB | MISR_MSKRF | MISR_MSKFHF | MISR_MSKRHF); + WRITECSR(sc, R_MICR, MICR_INTEN); + + WRITECSR(sc, R_TXDP, PTR_TO_PCI(sc->txdscr_start)); + WRITECSR(sc, R_RXDP, PTR_TO_PCI(sc->rxdscr_start)); + + WRITECSR(sc, R_MIBC, M_MIBC_ACLR); /* zero hw MIB counters */ + + WRITECSR(sc, R_CR, M_CR_TXE | M_CR_RXE); + sc->state = eth_state_on; +} + +static void +dp83815_stop(dp83815_softc *sc) +{ + uint32_t status; + int count; + + /* Make sure that no further interrutps will be processed. */ + sc->intmask = 0; + WRITECSR(sc, R_IER, 0); + WRITECSR(sc, R_IMR, 0); + +#if IPOLL + (void)READCSR(sc, R_IER); /* Push */ + cfe_free_irq(sc->irq, 0); +#endif + + WRITECSR(sc, R_CR, M_CR_TXD | M_CR_RXD); + + /* wait for any DMA activity to terminate */ + for (count = 0; count <= 13; count++) { + status = READCSR(sc, R_CR); + if ((status & (M_CR_TXE | M_CR_RXE)) == 0) + break; + cfe_sleep(CFE_HZ/10); + } + if (count > 13) { + xprintf("%s: idle state not achieved\n", dp83815_devname(sc)); + dumpstat(sc); + RESET_ADAPTER(sc); + sc->state = eth_state_uninit; +#if 1 + sc->linkspeed = ETHER_SPEED_AUTO; +#endif + } +#if 0 /* XXX Not yet implemented. */ + else if (sc->loopback != ETHER_LOOPBACK_OFF) { + dp83815_setloopback(sc, ETHER_LOOPBACK_OFF); + } +#endif + + (void)READCSR(sc, R_ISR); /* Clear any stragglers. */ +} + + +/* ********************************************************************* + * ETH_PARSE_XDIGIT(c) + * + * Parse a hex digit, returning its value + * + * Input parameters: + * c - character + * + * Return value: + * hex value, or -1 if invalid + ********************************************************************* */ +static int +eth_parse_xdigit(char c) +{ + int digit; + + if ((c >= '0') && (c <= '9')) digit = c - '0'; + else if ((c >= 'a') && (c <= 'f')) digit = c - 'a' + 10; + else if ((c >= 'A') && (c <= 'F')) digit = c - 'A' + 10; + else digit = -1; + + return digit; +} + +/* ********************************************************************* + * ETH_PARSE_HWADDR(str,hwaddr) + * + * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte + * Ethernet address. + * + * Input parameters: + * str - string + * hwaddr - pointer to hardware address + * + * Return value: + * 0 if ok, else -1 + ********************************************************************* */ +static int +eth_parse_hwaddr(char *str, uint8_t *hwaddr) +{ + int digit1, digit2; + int idx = ENET_ADDR_LEN; + + while (*str && (idx > 0)) { + digit1 = eth_parse_xdigit(*str); + if (digit1 < 0) return -1; + str++; + if (!*str) return -1; + + if ((*str == ':') || (*str == '-')) { + digit2 = digit1; + digit1 = 0; + } + else { + digit2 = eth_parse_xdigit(*str); + if (digit2 < 0) return -1; + str++; + } + + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + + if ((*str == ':') || (*str == '-')) + str++; + } + return 0; +} + +/* ********************************************************************* + * ETH_INCR_HWADDR(hwaddr,incr) + * + * Increment a 6-byte Ethernet hardware address, with carries + * + * Input parameters: + * hwaddr - pointer to hardware address + * incr - desired increment + * + * Return value: + * none + ********************************************************************* */ +static void +eth_incr_hwaddr(uint8_t *hwaddr, unsigned incr) +{ + int idx; + int carry; + + idx = 5; + carry = incr; + while (idx >= 0 && carry != 0) { + unsigned sum = hwaddr[idx] + carry; + + hwaddr[idx] = sum & 0xFF; + carry = sum >> 8; + idx--; + } +} + + +/* ********************************************************************* + * Declarations for CFE Device Driver Interface routines + ********************************************************************* */ + +static int dp83815_ether_open(cfe_devctx_t *ctx); +static int dp83815_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int dp83815_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int dp83815_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int dp83815_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int dp83815_ether_close(cfe_devctx_t *ctx); +static void dp83815_ether_poll(cfe_devctx_t *ctx, int64_t ticks); +static void dp83815_ether_reset(void *softc); + +/* ********************************************************************* + * CFE Device Driver dispatch structure + ********************************************************************* */ + +const static cfe_devdisp_t dp83815_ether_dispatch = { + dp83815_ether_open, + dp83815_ether_read, + dp83815_ether_inpstat, + dp83815_ether_write, + dp83815_ether_ioctl, + dp83815_ether_close, + dp83815_ether_poll, + dp83815_ether_reset +}; + +/* ********************************************************************* + * CFE Device Driver descriptor + ********************************************************************* */ + +const cfe_driver_t dp83815drv = { + "DP83815 Ethernet", + "eth", + CFE_DEV_NETWORK, + &dp83815_ether_dispatch, + dp83815_ether_probe +}; + + +static int +dp83815_ether_attach(cfe_driver_t *drv, + pcitag_t tag, int index, uint8_t hwaddr[]) +{ + dp83815_softc *sc; + uint32_t device; + uint32_t class; + phys_addr_t pa; + uint8_t promaddr[ENET_ADDR_LEN]; + char descr[100]; + uint32_t srr; + + device = pci_conf_read(tag, R_CFGID); + class = pci_conf_read(tag, R_CFGRID); + +#if 1 + /* Use memory space for the CSRs */ + pci_map_mem(tag, R_CFGMA, PCI_MATCH_BITS, &pa); +#else + /* Use i/o space for the CSRs */ + pci_map_io(tag, R_CFGIOA, PCI_MATCH_BITS, &pa); +#endif + + sc = (dp83815_softc *) KMALLOC(sizeof(dp83815_softc), 0); + + if (sc == NULL) { + xprintf("DP83815: No memory to complete probe\n"); + return 0; + } + memset(sc, 0, sizeof(*sc)); + + sc->membase = (uint32_t)pa; + sc->irq = pci_conf_read(tag, R_CFGINT) & 0xFF; + sc->tag = tag; + sc->device = PCI_PRODUCT(device); + sc->revision = PCI_REVISION(class); + sc->devctx = NULL; + +#if 1 + sc->linkspeed = ETHER_SPEED_AUTO; /* select autonegotiation */ +#else + sc->linkspeed = ETHER_SPEED_100FDX; /* 100 Mbps, full duplex */ +#endif + sc->loopback = ETHER_LOOPBACK_OFF; + memcpy(sc->hwaddr, hwaddr, ENET_ADDR_LEN); + + srr = READCSR(sc, R_SRR); +#if 0 + /* The NS data sheet recommends the following for "optimal + performance" of CVNG parts. Tested on a sample of one CVNG + part on an NS "Macphyter Demo II" eval board, it seemed to + produce slightly less reliable initial behavior. */ + if (G_SRR_REV(srr) == K_REV_CVNG) { + /* Update PHY DSP registers per data sheet. */ + WRITECSR(sc, R_PGSEL, 0x0001); + (void)READCSR(sc, R_PGSEL); /* push */ + WRITECSR(sc, R_PMDCSR, 0x189C); + WRITECSR(sc, R_TSTDAT, 0x0000); + WRITECSR(sc, R_DSPCFG, 0x5040); + WRITECSR(sc, R_SDCFG, 0x008C); + } +#endif + + dp83815_init(sc); + + /* Prefer the address in EEPROM. This will be read into the + PMATCH register upon power up. Unfortunately, how to test for + completion of the auto-load (but see PTSCR_EELOAD_EN). */ + if (dp83815_get_pm_addr(sc, promaddr) == 0) { + memcpy(sc->hwaddr, promaddr, ENET_ADDR_LEN); + } + + sc->state = eth_state_uninit; + + xsprintf(descr, "%s at 0x%X (%02x-%02x-%02x-%02x-%02x-%02x)", + drv->drv_description, sc->membase, + sc->hwaddr[0], sc->hwaddr[1], sc->hwaddr[2], + sc->hwaddr[3], sc->hwaddr[4], sc->hwaddr[5]); + + cfe_attach(drv, sc, NULL, descr); + return 1; +} + + +/* ********************************************************************* + * DP83815_ETHER_PROBE(drv,probe_a,probe_b,probe_ptr) + * + * Probe and install drivers for all dp83815 Ethernet controllers. + * For each, create a context structure and attach to the + * specified network device. + * + * Input parameters: + * drv - driver descriptor + * probe_a - not used + * probe_b - not used + * probe_ptr - string pointer to hardware address for the first + * MAC, in the form xx:xx:xx:xx:xx:xx + * + * Return value: + * nothing + ********************************************************************* */ +static void +dp83815_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + int n; + uint8_t hwaddr[ENET_ADDR_LEN]; + + if (probe_ptr) + eth_parse_hwaddr((char *) probe_ptr, hwaddr); + else { + /* use default address 02-00-00-10-0B-00 */ + hwaddr[0] = 0x02; hwaddr[1] = 0x00; hwaddr[2] = 0x00; + hwaddr[3] = 0x10; hwaddr[4] = 0x0B; hwaddr[5] = 0x00; + } + + n = 0; + for (;;) { + pcitag_t tag; + + if (pci_find_device(K_PCI_VENDOR_NSC, K_PCI_ID_DP83815, n, &tag) != 0) + break; + dp83815_ether_attach(drv, tag, n, hwaddr); + n++; + eth_incr_hwaddr(hwaddr, 1); + } +} + + +/* The functions below are called via the dispatch vector for the 83815. */ + +/* ********************************************************************* + * DP83815_ETHER_OPEN(ctx) + * + * Open the Ethernet device. The MAC is reset, initialized, and + * prepared to receive and send packets. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +dp83815_ether_open(cfe_devctx_t *ctx) +{ + dp83815_softc *sc = ctx->dev_softc; + + if (sc->state == eth_state_on) + dp83815_stop(sc); + + sc->devctx = ctx; + + sc->inpkts = sc->outpkts = 0; + sc->interrupts = 0; + sc->rx_interrupts = sc->tx_interrupts = 0; + + dp83815_start(sc); + +#if XPOLL + dp83815_isr(sc); +#endif + + return 0; +} + +/* ********************************************************************* + * DP83815_ETHER_READ(ctx,buffer) + * + * Read a packet from the Ethernet device. If no packets are + * available, the read will succeed but return 0 bytes. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +dp83815_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + dp83815_softc *sc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + +#if XPOLL + dp83815_isr(sc); +#endif + + if (sc->state != eth_state_on) return -1; + + CS_ENTER(sc); + pkt = (eth_pkt_t *) q_deqnext(&(sc->rxqueue)); + CS_EXIT(sc); + + if (pkt == NULL) { + buffer->buf_retlen = 0; + return 0; + } + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + blockcopy(buffer->buf_ptr, pkt->buffer, blen); + buffer->buf_retlen = blen; + + eth_free_pkt(sc, pkt); + dp83815_fillrxring(sc); + +#if XPOLL + dp83815_isr(sc); +#endif + + return 0; +} + +/* ********************************************************************* + * DP83815_ETHER_INPSTAT(ctx,inpstat) + * + * Check for received packets on the Ethernet device + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * inpstat - pointer to input status structure + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +dp83815_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + dp83815_softc *sc = ctx->dev_softc; + +#if XPOLL + dp83815_isr(sc); +#endif + + if (sc->state != eth_state_on) return -1; + + /* We avoid an interlock here because the result is a hint and an + interrupt cannot turn a non-empty queue into an empty one. */ + inpstat->inp_status = (q_isempty(&(sc->rxqueue))) ? 0 : 1; + + return 0; +} + +/* ********************************************************************* + * DP83815_ETHER_WRITE(ctx,buffer) + * + * Write a packet to the Ethernet device. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +dp83815_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + dp83815_softc *sc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + +#if XPOLL + dp83815_isr(sc); +#endif + + if (sc->state != eth_state_on) return -1; + + pkt = eth_alloc_pkt(sc); + if (!pkt) return CFE_ERR_NOMEM; + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + blockcopy(pkt->buffer, buffer->buf_ptr, blen); + pkt->length = blen; + + if (dp83815_transmit(sc, pkt) != 0) { + eth_free_pkt(sc,pkt); + return CFE_ERR_IOERR; + } + +#if XPOLL + dp83815_isr(sc); +#endif + + return 0; +} + +/* ********************************************************************* + * DP83815_ETHER_IOCTL(ctx,buffer) + * + * Do device-specific I/O control operations for the device + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +dp83815_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + dp83815_softc *sc = ctx->dev_softc; + int *argp; + int mode; + int speed; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_ETHER_GETHWADDR: + memcpy(buffer->buf_ptr, sc->hwaddr, sizeof(sc->hwaddr)); + return 0; + + case IOCTL_ETHER_SETHWADDR: + return -1; /* not supported */ + + case IOCTL_ETHER_GETSPEED: + argp = (int *) buffer->buf_ptr; + *argp = sc->linkspeed; + return 0; + + case IOCTL_ETHER_SETSPEED: + dp83815_stop(sc); + dp83815_resetrings(sc); + speed = *((int *) buffer->buf_ptr); + dp83815_setspeed(sc, speed); + dp83815_start(sc); + sc->state = eth_state_on; + return 0; + + case IOCTL_ETHER_GETLINK: + argp = (int *) buffer->buf_ptr; + *argp = sc->linkspeed; + return 0; + + case IOCTL_ETHER_GETLOOPBACK: + *((int *) buffer) = sc->loopback; + return 0; + + case IOCTL_ETHER_SETLOOPBACK: + dp83815_stop(sc); + dp83815_resetrings(sc); + mode = *((int *) buffer->buf_ptr); + sc->loopback = ETHER_LOOPBACK_OFF; /* default */ + if (mode == ETHER_LOOPBACK_INT || mode == ETHER_LOOPBACK_EXT) { + dp83815_setloopback(sc, mode); + } + dp83815_start(sc); + sc->state = eth_state_on; + return 0; + + default: + return -1; + } +} + +/* ********************************************************************* + * DP83815_ETHER_CLOSE(ctx) + * + * Close the Ethernet device. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +dp83815_ether_close(cfe_devctx_t *ctx) +{ + dp83815_softc *sc = ctx->dev_softc; + + sc->state = eth_state_off; + dp83815_stop(sc); + + /* resynchronize descriptor rings */ + dp83815_resetrings(sc); + + xprintf("%s: %d sent, %d received, %d interrupts\n", + dp83815_devname(sc), sc->outpkts, sc->inpkts, sc->interrupts); + xprintf(" %d rx interrupts, %d tx interrupts\n", + sc->rx_interrupts, sc->tx_interrupts); + + sc->devctx = NULL; + return 0; +} + + +/* ********************************************************************* + * DP83815_ETHER_POLL(ctx,ticks) + * + * TBD + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * ticks- current time in ticks + * + * Return value: + * nothing + ********************************************************************* */ + +static void +dp83815_ether_poll(cfe_devctx_t *ctx, int64_t ticks) +{ + dp83815_softc *sc = ctx->dev_softc; + + if (sc->phy_check) { + sc->phy_check = 0; + dp83815_checkphy(sc); + } +} + + +/* ********************************************************************* + * DP83815_ETHER_RESET(softc) + * + * This routine is called when CFE is restarted after a + * program exits. We can clean up pending I/Os here. + * + * Input parameters: + * softc - pointer to dp83815_softc + * + * Return value: + * nothing + ********************************************************************* */ + +static void +dp83815_ether_reset(void *softc) +{ + dp83815_softc *sc = (dp83815_softc *)softc; + + /* Turn off the Ethernet interface. */ + + /* RESET_ADAPTER(sc); */ + + sc->state = eth_state_uninit; +} diff --git a/cfe/cfe/dev/dev_ds17887clock.c b/cfe/cfe/dev/dev_ds17887clock.c new file mode 100644 index 0000000..2ee82a3 --- /dev/null +++ b/cfe/cfe/dev/dev_ds17887clock.c @@ -0,0 +1,422 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * DS17887-3 RTC driver File: dev_sb1250_ds17887clock.c + * + * This module contains a CFE driver for a DS17887-3 generic bus + * real-time-clock. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" + +#include "lib_physio.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* + * Register bits + */ + +#define DS17887REGA_UIP 0x80 /* Update-in-progress */ +#define DS17887REGA_DV2 0x40 /* Countdown chain */ +#define DS17887REGA_DV1 0x20 /* Oscillator enable */ +#define DS17887REGA_DV0 0x10 /* Bank Select */ +#define DS17887REGA_RS3 0x08 /* Rate-selection bits */ +#define DS17887REGA_RS2 0x04 +#define DS17887REGA_RS1 0x02 +#define DS17887REGA_RS0 0x01 + +#define DS17887REGB_SET 0x80 /* Set bit */ +#define DS17887REGB_PIE 0x40 /* Periodic Interrupt Enable */ +#define DS17887REGB_AIE 0x20 /* Alarm Interrupt Enable */ +#define DS17887REGB_UIE 0x10 /* Update-ended Interrupt Enable */ +#define DS17887REGB_SQWE 0x08 /* Square-wave Enable */ +#define DS17887REGB_DM 0x04 /* Data Mode (binary) */ +#define DS17887REGB_24 0x02 /* 24-hour mode control bit */ +#define DS17887REGB_DSE 0x01 /* Daylight Savings Enable */ + +#define DS17887REGC_IRQF 0x80 /* Interrupt request flag */ +#define DS17887REGC_PF 0x40 /* Periodic interrupt flag */ +#define DS17887REGC_AF 0x20 /* Alarm interrupt flag */ +#define DS17887REGC_UF 0x10 /* Update ended interrupt flag */ + +#define DS17887REGD_VRT 0x80 /* Valid RAM and time */ + +/* + * Register numbers + */ + +#define DS17887REG_SC 0x00 /* seconds */ +#define DS17887REG_SCA 0x01 /* seconds alarm */ +#define DS17887REG_MN 0x02 /* minutes */ +#define DS17887REG_MNA 0x03 /* minutes alarm */ +#define DS17887REG_HR 0x04 /* hours */ +#define DS17887REG_HRA 0x05 /* hours alarm */ +#define DS17887REG_DW 0x06 /* day of week */ +#define DS17887REG_DM 0x07 /* day of month */ +#define DS17887REG_MO 0x08 /* month */ +#define DS17887REG_YR 0x09 /* year */ +#define DS17887REG_A 0x0A /* register A */ +#define DS17887REG_B 0x0B /* register B */ +#define DS17887REG_C 0x0C /* register C */ +#define DS17887REG_D 0x0D /* register D */ + +#define DS17887REG_CE 0x48 /* century (bank 1 only) */ + +#define BCD(x) (((x) % 10) + (((x) / 10) << 4)) +#define SET_TIME 0x00 +#define SET_DATE 0x01 + +#define WRITECSR(p,v) phys_write8((p),(v)) +#define READCSR(p) phys_read8((p)) + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + +static void ds17887_clock_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +static int ds17887_clock_open(cfe_devctx_t *ctx); +static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int ds17887_clock_close(cfe_devctx_t *ctx); + + +/* ********************************************************************* + * Device dispatch + ********************************************************************* */ + +const static cfe_devdisp_t ds17887_clock_dispatch = { + ds17887_clock_open, + ds17887_clock_read, + ds17887_clock_inpstat, + ds17887_clock_write, + ds17887_clock_ioctl, + ds17887_clock_close, + NULL, + NULL +}; + +const cfe_driver_t ds17887_clock = { + "DS17887 RTC", + "clock", + CFE_DEV_CLOCK, + &ds17887_clock_dispatch, + ds17887_clock_probe +}; + + +/* ********************************************************************* + * Structures + ********************************************************************* */ +typedef struct ds17887_clock_s { + physaddr_t clock_base; +} ds17887_clock_t; + +/* ********************************************************************* + * ds17887_clock_probe(drv,a,b,ptr) + * + * Probe routine for this driver. This routine creates the + * local device context and attaches it to the driver list + * within CFE. + * + * Input parameters: + * drv - driver handle + * a,b - probe hints (longs) + * ptr - probe hint (pointer) + * + * Return value: + * nothing + ********************************************************************* */ + +static void ds17887_clock_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + ds17887_clock_t *softc; + char descr[80]; + + softc = (ds17887_clock_t *) KMALLOC(sizeof(ds17887_clock_t),0); + + /* + * Probe_a is the clock base address + * Probe_b is unused. + * Probe_ptr is unused. + */ + + softc->clock_base = probe_a; + + xsprintf(descr,"%s at 0x%X", + drv->drv_description,(uint32_t)probe_a); + cfe_attach(drv,softc,NULL,descr); + +} + +/* ********************************************************************* + * ds17887_clock_open(ctx) + * + * Open this device. For the DS17887, we do a quick test + * read to be sure the device is out there. + * + * Input parameters: + * ctx - device context (can obtain our softc here) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int ds17887_clock_open(cfe_devctx_t *ctx) +{ + ds17887_clock_t *softc = ctx->dev_softc; + uint8_t byte; + physaddr_t clockbase; + + clockbase = softc->clock_base; + + /* Make sure battery is still good and RTC valid */ + if ( !(READCSR(clockbase+DS17887REG_D) & DS17887REGD_VRT) ) { + printf("Warning: Battery has failed. Clock setting is not accurate.\n"); + } + + /* Switch to bank 1. Mainly for century byte */ + byte = (uint8_t) (READCSR(clockbase+DS17887REG_A) & 0xFF); + WRITECSR(clockbase+DS17887REG_A,DS17887REGA_DV0 | DS17887REGA_DV1 | byte); + + /* Set data mode to BCD, 24-hour mode, and enable daylight savings */ + byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF); + byte &= (~DS17887REGB_DM & ~DS17887REGB_AIE); + WRITECSR(clockbase+DS17887REG_B, DS17887REGB_24 | DS17887REGB_DSE | byte ); + + return 0; +} + +/* ********************************************************************* + * ds17887_clock_read(ctx,buffer) + * + * Read time/date from the RTC. Read a total of 8 bytes in this format: + * hour-minute-second-month-day-year1-year2 + * + * Input parameters: + * ctx - device context (can obtain our softc here) + * buffer - buffer descriptor (target buffer, length, offset) + * + * Return value: + * number of bytes read + * -1 if an error occured + ********************************************************************* */ + +static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + + ds17887_clock_t *softc = ctx->dev_softc; + unsigned char *bptr; + physaddr_t clockbase; + + clockbase = softc->clock_base; + + bptr = buffer->buf_ptr; + + *bptr++ = READCSR(clockbase+DS17887REG_HR); + *bptr++ = READCSR(clockbase+DS17887REG_MN); + *bptr++ = READCSR(clockbase+DS17887REG_SC); + *bptr++ = READCSR(clockbase+DS17887REG_MO); + *bptr++ = READCSR(clockbase+DS17887REG_DM); + *bptr++ = READCSR(clockbase+DS17887REG_YR); + *bptr++ = READCSR(clockbase+DS17887REG_CE); + + buffer->buf_retlen = 8; + return 0; +} + +/* ********************************************************************* + * ds17887_clock_write(ctx,buffer) + * + * Write time/date to the RTC. Write in this format: + * hour-minute-second-month-day-year1-year2-(time/date flag) + * + * Input parameters: + * ctx - device context (can obtain our softc here) + * buffer - buffer descriptor (target buffer, length, offset) + * + * Return value: + * number of bytes written + * -1 if an error occured + ********************************************************************* */ + +static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + ds17887_clock_t *softc = ctx->dev_softc; + uint8_t byte; + unsigned char *bptr; + uint8_t hr,min,sec; + uint8_t mo,day,yr,y2k; + uint8_t timeDateFlag; + physaddr_t clockbase; + + clockbase = softc->clock_base; + + bptr = buffer->buf_ptr; + + /* Set SET bit */ + byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF); + WRITECSR(clockbase+DS17887REG_B,DS17887REGB_SET | byte); + + timeDateFlag = *(bptr + 7); + + /* write time or date */ + if(timeDateFlag == SET_TIME) { + + hr = (uint8_t) *bptr; + WRITECSR(clockbase+DS17887REG_HR,BCD(hr)); + + min = (uint8_t) *(bptr+1); + WRITECSR(clockbase+DS17887REG_MN,BCD(min)); + + sec = (uint8_t) *(bptr+2); + WRITECSR(clockbase+DS17887REG_SC,BCD(sec)); + + buffer->buf_retlen = 3; + } + else if(timeDateFlag == SET_DATE) { + + mo = (uint8_t) *(bptr+3); + WRITECSR(clockbase+DS17887REG_MO,BCD(mo)); + + day = (uint8_t) *(bptr+4); + WRITECSR(clockbase+DS17887REG_DM,BCD(day)); + + yr = (uint8_t) *(bptr+5); + WRITECSR(clockbase+DS17887REG_YR,BCD(yr)); + + y2k = (uint8_t) *(bptr+6); + WRITECSR(clockbase+DS17887REG_CE,y2k); + + buffer->buf_retlen = 4; + } + else { + return -1; + } + + /* clear SET bit */ + byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF); + WRITECSR(clockbase+DS17887REG_B,~DS17887REGB_SET & byte); + + return 0; +} + +/* ********************************************************************* + * ds17887_clock_inpstat(ctx,inpstat) + * + * Test input (read) status for the device + * + * Input parameters: + * ctx - device context (can obtain our softc here) + * inpstat - input status descriptor to receive value + * + * Return value: + * 0 if ok + * -1 if an error occured + ********************************************************************* */ + +static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + inpstat->inp_status = 1; + + return 0; +} + +/* ********************************************************************* + * ds17887_clock_ioctl(ctx,buffer) + * + * Perform miscellaneous I/O control operations on the device. + * + * Input parameters: + * ctx - device context (can obtain our softc here) + * buffer - buffer descriptor (target buffer, length, offset) + * + * Return value: + * number of bytes read + * -1 if an error occured + ********************************************************************* */ + +static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + return 0; +} + +/* ********************************************************************* + * ds17887_clock_close(ctx,buffer) + * + * Close the device. + * + * Input parameters: + * ctx - device context (can obtain our softc here) + * + * Return value: + * 0 if ok + * -1 if an error occured + ********************************************************************* */ + +static int ds17887_clock_close(cfe_devctx_t *ctx) +{ + return 0; +} + + + + + + + + diff --git a/cfe/cfe/dev/dev_flash.c b/cfe/cfe/dev/dev_flash.c new file mode 100644 index 0000000..98ad3e7 --- /dev/null +++ b/cfe/cfe/dev/dev_flash.c @@ -0,0 +1,1367 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash device driver File: dev_flash.c + * + * This driver supports various types of flash + * parts. You can also put the environment storage in + * the flash - the top sector is reserved for that purpose. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "addrspace.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_error.h" + +#include "dev_flash.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define FLASHCMD(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \ + ((x)<<(sc)->flashdrv_widemode))) = (y) +#define FLASHSTATUS(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \ + ((x)<<(sc)->flashdrv_widemode))) + +#define WRITEFLASH_K1(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x))) = (y) +#define READFLASH_K1(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x))) + +#define WRITEFLASH_K1W(sc,x,y) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x))) = (y) +#define READFLASH_K1W(sc,x) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x))) + + +#define GETCFIBYTE(softc,offset) READFLASH_K1(softc,((offset) << (softc->flashdrv_widemode))) + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + + +static void flashdrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +static int flashdrv_open(cfe_devctx_t *ctx); +static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int flashdrv_close(cfe_devctx_t *ctx); + +/* ********************************************************************* + * Device dispatch + ********************************************************************* */ + +const static cfe_devdisp_t flashdrv_dispatch = { + flashdrv_open, + flashdrv_read, + flashdrv_inpstat, + flashdrv_write, + flashdrv_ioctl, + flashdrv_close, + NULL, + NULL +}; + +const cfe_driver_t flashdrv = { + "CFI flash", + "flash", + CFE_DEV_FLASH, + &flashdrv_dispatch, + flashdrv_probe +}; + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct flash_cfidata_s { + unsigned int cfidata_cmdset; /* ID of primary command set */ + unsigned int cfidata_devif; /* device interface byte */ + unsigned int cfidata_size; /* probed device size */ +} flash_cfidata_t; + +typedef struct flashops_s flashops_t; + +typedef struct flashdrv_s { + flash_probe_t flashdrv_probe; /* data from probe */ + int flashdrv_devsize; /* size reported by driver */ + unsigned char *flashdrv_cmdaddr; /* virtual address (K1) */ + int flashdrv_widemode; /* 1=wide flash in byte mode, 0=narrow flash */ + int flashdrv_initialized; /* true if we've probed already */ + flash_info_t flashdrv_info; + int flashdrv_nvram_ok; /* true if we can use as NVRAM */ + int flashdrv_unlocked; /* true if we can r/w past devsize */ + nvram_info_t flashdrv_nvraminfo; + flashops_t *flashdrv_ops; + flash_cfidata_t flashdrv_cfidata; +} flashdrv_t; + +struct flashops_s { + int (*erasesector)(flashdrv_t *f,int offset); + int (*writeblk)(flashdrv_t *f,int offset,void *buf,int len); +}; + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define FLASHOP_ERASE_SECTOR(softc,sect) (*((softc)->flashdrv_ops->erasesector))((softc),(sect)) +#define FLASHOP_WRITE_BLOCK(softc,off,buf,len) (*((softc)->flashdrv_ops->writeblk))((softc),(off),(buf),(len)) + +/* ********************************************************************* + * forward declarations + ********************************************************************* */ + + +static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector); + +static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len); +static int amd_flash_erase_sector(flashdrv_t *softc,int offset); + +static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len); +static int intel_flash_erase_sector(flashdrv_t *softc,int offset); + +static flashops_t amd_flashops = { + amd_flash_erase_sector, + amd_flash_write_block, +}; + +static flashops_t intel_flashops = { + intel_flash_erase_sector, + intel_flash_write_block, +}; + +#define FLASHOPS_DEFAULT amd_flashops + + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern void *flash_write_all_ptr; +extern int flash_write_all_len; + +extern void _cfe_flushcache(int); + + +#if 0 +/* ********************************************************************* + * jedec_flash_maufacturer(softc) + * + * Return the manufacturer ID for this flash part. + * + * Input parameters: + * softc - flash context + * + * Return value: + * nothing + ********************************************************************* */ + +static unsigned int jedec_flash_manufacturer(flashdrv_t *softc) +{ + unsigned int res; + + /* Do an "unlock write" sequence */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL); + + res = FLASHSTATUS(softc,FLASH_JEDEC_OFFSET_MFR) & 0xFF; + + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_RESET); + + return res; +} + +/* ********************************************************************* + * jedec_flash_type(softc) + * + * Return the manufacturer's type for the flash + * + * Input parameters: + * softc - flash context + * + * Return value: + * nothing + ********************************************************************* */ +static unsigned int jedec_flash_type(flashdrv_t *softc) +{ + unsigned int res; + + /* Do an "unlock write" sequence */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL); + + res = FLASHSTATUS(softc,FLASH_JEDEC_OFFSET_DEV) & 0xFF; + + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_RESET); + + return res; +} + +#endif + +/* ********************************************************************* + * amd_flash_write_byte(softc,offset,val) + * + * Write a single byte to the flash. The sector that the flash + * byte is in should have been previously erased, or else this + * routine may hang. + * + * Input parameters: + * softc - flash context + * offset - distance in bytes into the flash + * val - byte to write + * + * Return value: + * 0 if ok + * else if flash could not be written + ********************************************************************* */ +static inline int amd_flash_write_byte(flashdrv_t *softc,int offset, unsigned char val) +{ + unsigned int value; + + /* Do an "unlock write" sequence */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); + + /* Send a program command */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM); + + /* Write a byte */ + WRITEFLASH_K1(softc,offset,val); + + for (;;) { + value = READFLASH_K1(softc,offset) & 0xFF; + + if ((value & 0x80) == (val & 0x80)) { + return 0; + } + if ((value & 0x20) != 0x20) { + continue; + } + + if ((READFLASH_K1(softc,offset) & 0x80) == (val & 0x80)) { + return 0; + } + else { + return -1; + } + } +} + + +/* ********************************************************************* + * amd_flash_write_block(softc,offset,val) + * + * Write a single byte to the flash. The sector that the flash + * byte is in should have been previously erased, or else this + * routine may hang. + * + * Input parameters: + * softc - flash context + * offset - distance in bytes into the flash + * buf - buffer of bytes to write + * len - number of bytes to write + * + * Return value: + * number of bytes written + ********************************************************************* */ +static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len) +{ + unsigned char *ptr; + + ptr = buf; + + while (len) { + if (amd_flash_write_byte(softc,offset,*ptr) < 0) break; + len--; + ptr++; + offset++; + + } + + return (ptr - (unsigned char *)buf); +} + + +/* ********************************************************************* + * amd_flash_erase_sector(softc,offset) + * + * Erase a single sector in the flash device + * + * Input parameters: + * softc - device context + * offset - offset in flash of sector to erase + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int amd_flash_erase_sector(flashdrv_t *softc,int offset) +{ + /* Do an "unlock write" sequence */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 1-2 */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); + + /* send the erase command */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3); /* cycle 3 */ + + /* Do an "unlock write" sequence */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 4-5 */ + FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); + + /* + * Send the "erase sector" qualifier - don't use FLASHCMD + * because it changes the offset. + */ + WRITEFLASH_K1(softc,offset,AMD_FLASH_ERASE_SEC_6); + + while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) { + /* NULL LOOP */ + } + + return 0; +} + + + +/* ********************************************************************* + * intel_flash_write_byte(softc,offset,val) + * + * Write a single byte to the flash. The sector that the flash + * byte is in should have been previously erased, or else this + * routine may hang. + * + * Input parameters: + * softc - flash context + * offset - distance in bytes into the flash + * val - byte to write + * + * Return value: + * 0 if ok + * else if flash could not be written + ********************************************************************* */ +static inline int intel_flash_write_byte(flashdrv_t *softc, + int offset, unsigned char val) +{ + unsigned int value; + + /* Send a program command */ + WRITEFLASH_K1(softc,offset,INTEL_FLASH_PROGRAM); + + /* Write a byte */ + WRITEFLASH_K1(softc,offset,val); + + + while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) { + /* NULL LOOP */ + } + + value = READFLASH_K1(softc,offset) & 0xFF; + + if (value & (0x01|0x08|0x10)) return -1; + return 0; +} + +/* ********************************************************************* + * intel_flash_write_word(softc,offset,val) + * + * Write a single word to the flash. The sector that the flash + * byte is in should have been previously erased, or else this + * routine may hang. + * + * Input parameters: + * softc - flash context + * offset - distance in bytes into the flash + * val - word to write + * + * Return value: + * 0 if ok + * else if flash could not be written + ********************************************************************* */ +static inline int intel_flash_write_word(flashdrv_t *softc, + int offset, unsigned short val) +{ + unsigned int value; + + + /* Send a program command */ + WRITEFLASH_K1W(softc,offset,INTEL_FLASH_PROGRAM); + + /* Write a byte */ + WRITEFLASH_K1W(softc,offset,val); + + + while ((READFLASH_K1W(softc,offset) & 0x80) != 0x80) { + /* NULL LOOP */ + } + + value = READFLASH_K1W(softc,offset) & 0xFF; + + if (value & (0x01|0x08|0x10)) return -1; + return 0; +} + +/* ********************************************************************* + * intel_flash_write_block(softc,offset,val) + * + * Write a single byte to the flash. The sector that the flash + * byte is in should have been previously erased, or else this + * routine may hang. + * + * Input parameters: + * softc - flash context + * offset - distance in bytes into the flash + * buf - buffer of bytes to write + * len - number of bytes to write + * + * Return value: + * number of bytes written + ********************************************************************* */ +static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len) +{ + unsigned char *ptr; + unsigned short *ptrw; + + if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) { + ptrw = buf; + offset &= ~1; /* offset must be even */ + while (len > 0) { + if (intel_flash_write_word(softc,offset,*ptrw) < 0) break; + len-=2; + ptrw++; + offset+=2; + } + WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE); + return ((unsigned char *) ptrw - (unsigned char *)buf); + } + else { + ptr = buf; + while (len) { + if (intel_flash_write_byte(softc,offset,*ptr) < 0) break; + len--; + ptr++; + offset++; + } + WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE); + return (ptr - (unsigned char *)buf); + } + +} + + +/* ********************************************************************* + * intel_flash_erase_sector(softc,offset) + * + * Erase a single sector on the flash device + * + * Input parameters: + * softc - device context + * offset - offset in flash of sector to erase + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +static int intel_flash_erase_sector(flashdrv_t *softc,int offset) +{ + WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_BLOCK); + WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_CONFIRM); + + while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) { + /* NULL LOOP */ + } + WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE); + + return 0; +} + + + + + +/* ********************************************************************* + * FLASH_ERASE_RANGE(softc,range) + * + * Erase a range of sectors + * + * Input parameters: + * softc - our flash + * range - range structure + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +static int flash_erase_range(flashdrv_t *softc,flash_range_t *range) +{ + flash_sector_t sector; + int res; + + if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) { + return CFE_ERR_UNSUPPORTED; + } + + + if (range->range_base+range->range_length > softc->flashdrv_devsize) { + return CFE_ERR_INV_PARAM; + } + + res = 0; + + sector.flash_sector_idx = 0; + + for (;;) { + res = flash_sector_query(softc,§or); + if (res != 0) break; + if (sector.flash_sector_status == FLASH_SECTOR_INVALID) { + break; + } + + if ((sector.flash_sector_offset >= range->range_base) && + (sector.flash_sector_offset < + (range->range_base+range->range_length-1))) { + + if (softc->flashdrv_nvram_ok && + (sector.flash_sector_offset >= softc->flashdrv_nvraminfo.nvram_offset)) { + break; + } + res = FLASHOP_ERASE_SECTOR(softc,sector.flash_sector_offset); + if (res != 0) break; + } + sector.flash_sector_idx++; + } + + return res; + +} + +/* ********************************************************************* + * FLASH_ERASE_ALL(softc) + * + * Erase the entire flash device, except the NVRAM area, + * sector-by-sector. + * + * Input parameters: + * softc - our flash + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int flash_erase_all(flashdrv_t *softc) +{ + flash_range_t range; + + range.range_base = 0; + range.range_length = softc->flashdrv_devsize; + + return flash_erase_range(softc,&range); +} + +/* ********************************************************************* + * FLASH_CFI_GETSECTORS(softc) + * + * Query the CFI information and store the sector info in our + * private probe structure. + * + * Input parameters: + * softc - our flash info + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int flash_cfi_getsectors(flashdrv_t *softc) +{ + int idx; + int regcnt; + int nblks; + int blksiz; + + regcnt = GETCFIBYTE(softc,FLASH_CFI_REGION_COUNT); + + softc->flashdrv_probe.flash_nsectors = regcnt; + + for (idx = 0; idx < regcnt; idx++) { + nblks = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+0+idx*4) + + (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+1+idx*4)<<8)) + 1; + blksiz = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+2+idx*4) + + (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+3+idx*4)<<8)) * 256; + softc->flashdrv_probe.flash_sectors[idx] = + FLASH_SECTOR_RANGE(nblks,blksiz); + } + + + return 0; +} + +/* ********************************************************************* + * FLASH_SECTOR_QUERY(softc,sector) + * + * Query the sector information about a particular sector. You can + * call this iteratively to find out about all of the sectors. + * + * Input parameters: + * softc - our flash info + * sector - structure to receive sector information + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector) +{ + int idx; + int nblks; + int blksiz; + unsigned int offset; + int curblk; + + if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) { + return CFE_ERR_UNSUPPORTED; + } + + if (softc->flashdrv_probe.flash_nsectors == 0) { + return CFE_ERR_UNSUPPORTED; + } + + offset = 0; + curblk = 0; + for (idx = 0; idx < softc->flashdrv_probe.flash_nsectors; idx++) { + nblks = FLASH_SECTOR_NBLKS(softc->flashdrv_probe.flash_sectors[idx]); + blksiz = FLASH_SECTOR_SIZE(softc->flashdrv_probe.flash_sectors[idx]); + if (sector->flash_sector_idx < curblk+nblks) { + sector->flash_sector_status = FLASH_SECTOR_OK; + sector->flash_sector_offset = + offset + (sector->flash_sector_idx-curblk)*blksiz; + sector->flash_sector_size = blksiz; + break; + } + + offset += (nblks)*blksiz; + curblk += nblks; + } + + + if (idx == softc->flashdrv_probe.flash_nsectors) { + sector->flash_sector_status = FLASH_SECTOR_INVALID; + } + + return 0; +} + + +/* ********************************************************************* + * FLASH_SET_CMDSET(softc,cmdset) + * + * Set the command-set that we'll honor for this flash. + * + * Input parameters: + * softc - our flash + * cmdset - FLASH_CFI_CMDSET_xxx + * + * Return value: + * nothing + ********************************************************************* */ + +static void flash_set_cmdset(flashdrv_t *softc,int cmdset) +{ + switch (cmdset) { + case FLASH_CFI_CMDSET_INTEL_ECS: + case FLASH_CFI_CMDSET_INTEL_STD: + softc->flashdrv_ops = &intel_flashops; + /* XXX: Intel flashes don't have the "a-1" line. Yay. */ + softc->flashdrv_widemode = 0; + break; + case FLASH_CFI_CMDSET_AMD_STD: + case FLASH_CFI_CMDSET_AMD_ECS: + softc->flashdrv_ops = &amd_flashops; + break; + default: + /* we don't understand the command set - treat it like ROM */ + softc->flashdrv_info.flash_type = FLASH_TYPE_ROM; + } +} + + +/* ********************************************************************* + * FLASH_CFI_PROBE(softc) + * + * Try to do a CFI query on this device. If we find the m + * magic signature, extract some useful information from the + * query structure. + * + * Input parameters: + * softc - out flash + * + * Return value: + * 0 if successful, <0 if error + ********************************************************************* */ +static int flash_cfi_probe(flashdrv_t *softc) +{ + FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE); + + if (!((GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+0) == 'Q') && + (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+1) == 'R') && + (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+2) == 'Y'))) { + + FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT); + return CFE_ERR_UNSUPPORTED; + } + + /* + * Gather info from flash + */ + + softc->flashdrv_cfidata.cfidata_cmdset = + ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET))) + + (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET+1))) << 8); + + softc->flashdrv_cfidata.cfidata_devif = + ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE))) + + (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE+1))) << 8); + + softc->flashdrv_cfidata.cfidata_size = + 1 << ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_SIZE))); + + flash_cfi_getsectors(softc); + + /* + * Don't need to be in query mode anymore. + */ + + FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT); + + softc->flashdrv_info.flash_type = FLASH_TYPE_FLASH; + + flash_set_cmdset(softc,softc->flashdrv_cfidata.cfidata_cmdset); + + return 0; + +} + +/* ********************************************************************* + * FLASH_GETWIDTH(softc,info) + * + * Try to determine the width of the flash. This is needed for + * management purposes, since some 16-bit flash parts in 8-bit mode + * have an "A-1" (address line -1) wire to select bytes within + * a 16-bit word. When this is present, the flash commands + * will have different offsets. + * + * Input parameters: + * softc - our flash + * info - flash info structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void flash_getwidth(flashdrv_t *softc,flash_info_t *info) +{ + softc->flashdrv_widemode = 0; /* first try narrow */ + + if (flash_cfi_probe(softc) == 0) { + return; + } + + softc->flashdrv_widemode = 1; /* then wide */ + + if (flash_cfi_probe(softc) == 0) { + return; + } + + /* Just return, assume not wide if no CFI interface */ + softc->flashdrv_widemode = 0; + + softc->flashdrv_info.flash_type = FLASH_TYPE_ROM; /* no CFI: treat as ROM */ +} + +/* ********************************************************************* + * flash_getinfo(softc) + * + * Try to determine if the specified region is flash, ROM, SRAM, + * or something else. + * + * Input parameters: + * softc - our context + * + * Return value: + * nothing + ********************************************************************* */ + +static void flash_getinfo(flashdrv_t *softc) +{ + uint8_t save0,save1; + volatile uint8_t *ptr; + flash_info_t *info = &(softc->flashdrv_info); + + /* + * Set up some defaults based on the probe data + */ + + softc->flashdrv_widemode = 0; + info->flash_base = softc->flashdrv_probe.flash_phys; + info->flash_size = softc->flashdrv_probe.flash_size; + softc->flashdrv_devsize = softc->flashdrv_probe.flash_size; + info->flash_type = FLASH_TYPE_UNKNOWN; + info->flash_flags = 0; + + /* + * If we've been told not to try probing, just assume + * we're a flash part. + */ + + if (softc->flashdrv_probe.flash_flags & FLASH_FLG_MANUAL) { + info->flash_type = FLASH_TYPE_FLASH; + if (softc->flashdrv_probe.flash_flags & FLASH_FLG_WIDE) { + softc->flashdrv_widemode = TRUE; + } + if (softc->flashdrv_probe.flash_cmdset) { + flash_set_cmdset(softc,softc->flashdrv_probe.flash_cmdset); + } + return; + } + + /* + * Attempt to read/write byte zero. If it is changable, + * this is SRAM (or maybe a ROM emulator with the write line hooked up) + */ + + ptr = (volatile uint8_t *) UNCADDR(softc->flashdrv_probe.flash_phys); + save0 = *ptr; /* save old value */ + save1 = *(ptr+1); /* save old value */ + *(ptr) = 0x55; + if ((*ptr) == 0x55) { + *(ptr) = 0xAA; + if ((*ptr) == 0xAA) { + info->flash_type = FLASH_TYPE_SRAM; + } + } + + if (*ptr == save0) info->flash_type = FLASH_TYPE_ROM; + else (*ptr) = save0; /* restore old value */ + + /* + * If we thought it was ROM, try doing a CFI query + * to see if it was flash. This check is kind of kludgey + * but should work. + */ + + if (info->flash_type == FLASH_TYPE_ROM) { + flash_getwidth(softc,info); + if (info->flash_type == FLASH_TYPE_FLASH) { + } + } +} + +/* ********************************************************************* + * flashdrv_setup_nvram(softc) + * + * If we're going to be using a sector of the flash for NVRAM, + * go find that sector and set it up. + * + * Input parameters: + * softc - our flash + * + * Return value: + * nothing. flashdrv_nvram_ok might change though. + ********************************************************************* */ + +static void flashdrv_setup_nvram(flashdrv_t *softc) +{ + flash_sector_t sector; + int res; + + softc->flashdrv_nvram_ok = FALSE; + + if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) { + return; + } + + sector.flash_sector_idx = 0; + for (;;) { + res = flash_sector_query(softc,§or); + if (res == CFE_ERR_UNSUPPORTED) break; + if (res == 0) { + if (sector.flash_sector_status != FLASH_SECTOR_INVALID) { + sector.flash_sector_idx++; + continue; + } + } + break; + } + + /* The sector offset will still contain the value at the end + of the last successful call. That's the last sector, so + we can now use this to fill in the NVRAM info structure */ + + if (res != CFE_ERR_UNSUPPORTED) { + softc->flashdrv_nvraminfo.nvram_offset = sector.flash_sector_offset; + softc->flashdrv_nvraminfo.nvram_size = sector.flash_sector_size; + softc->flashdrv_nvraminfo.nvram_eraseflg = TRUE; /* needs erase */ + softc->flashdrv_nvram_ok = TRUE; + /* + * Set the flash's size as reported in the flash_info structure + * to be the size without the NVRAM sector at the end. + */ + softc->flashdrv_info.flash_size = sector.flash_sector_offset; + softc->flashdrv_devsize = sector.flash_sector_offset; + } + +} + + +/* ********************************************************************* + * flashdrv_probe(drv,probe_a,probe_b,probe_ptr) + * + * Device probe routine. Attach the flash device to + * CFE's device table. + * + * Input parameters: + * drv - driver descriptor + * probe_a - physical address of flash + * probe_b - size of flash (bytes) + * probe_ptr - unused + * + * Return value: + * nothing + ********************************************************************* */ + +static void flashdrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + flashdrv_t *softc; + flash_probe_t *probe; + char descr[80]; + + probe = (flash_probe_t *) probe_ptr; + + /* + * probe_a is the flash base address + * probe_b is the size of the flash + * probe_ptr is unused. + */ + + softc = (flashdrv_t *) KMALLOC(sizeof(flashdrv_t),0); + if (softc) { + memset(softc,0,sizeof(flashdrv_t)); + + if (probe) { + /* Passed probe structure, do fancy stuff */ + memcpy(&(softc->flashdrv_probe),probe,sizeof(flash_probe_t)); + if (softc->flashdrv_probe.flash_prog_phys == 0) { + softc->flashdrv_probe.flash_prog_phys = + softc->flashdrv_probe.flash_phys; + } + } + else { + /* Didn't pass probe structure, do the compatible thing */ + softc->flashdrv_probe.flash_phys = probe_a; + softc->flashdrv_probe.flash_prog_phys = probe_a; + softc->flashdrv_probe.flash_size = probe_b; + softc->flashdrv_probe.flash_flags = FLASH_FLG_NVRAM; + } + + softc->flashdrv_cmdaddr = (char *) UNCADDR(softc->flashdrv_probe.flash_prog_phys); + softc->flashdrv_initialized = 0; + softc->flashdrv_ops = &FLASHOPS_DEFAULT; + xsprintf(descr,"%s at %08X size %uKB",drv->drv_description, + softc->flashdrv_probe.flash_phys, + softc->flashdrv_probe.flash_size/1024); + cfe_attach(drv,softc,NULL,descr); + } + +} + + +/* ********************************************************************* + * flashdrv_open(ctx) + * + * Called when the flash device is opened. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 if ok else error code + ********************************************************************* */ + +static int flashdrv_open(cfe_devctx_t *ctx) +{ + flashdrv_t *softc = ctx->dev_softc; + + /* + * do initialization + */ + + if (!softc->flashdrv_initialized) { + + /* + * Assume it's not an NVRAM-capable flash + */ + + softc->flashdrv_nvram_ok = FALSE; + + /* + * Probe flash for geometry + */ + flash_getinfo(softc); + + /* + * Find the last sector if in NVRAM mode + */ + + if (softc->flashdrv_probe.flash_flags & FLASH_FLG_NVRAM) { + flashdrv_setup_nvram(softc); + } + + softc->flashdrv_initialized = TRUE; + } + + return 0; +} + + +/* ********************************************************************* + * flashdrv_read(ctx,buffer) + * + * Read data from the flash device. The flash device is + * considered to be like a disk (you need to specify the offset). + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + flashdrv_t *softc = ctx->dev_softc; + unsigned char *bptr; + unsigned char *flashbase; + int offset; + int blen; + + /* + * For now, read the flash from K1 (always). Eventually + * we need to flush the cache after a write. + */ + + flashbase = (unsigned char *) UNCADDR(softc->flashdrv_probe.flash_phys); + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + offset = (int) buffer->buf_offset; + + if (!(softc->flashdrv_unlocked)) { + if ((offset + blen) > softc->flashdrv_devsize) { + blen = softc->flashdrv_devsize - offset; + } + } + +#ifdef _FLASH_BROKEN_BYTEREAD_ + /* + * BCM1250 users: don't worry about this. This hack is for + * something else and should not be used with the BCM1250. + */ + if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) { + uint16_t *src; + int len = blen; + int idx = 0; + union { + uint16_t x; + char b[2]; + } u; + + src = (uint16_t *) flashbase; + while (len > 0) { + u.x = src[(idx+offset)>>1]; + *bptr++ = u.b[(idx+offset)&1]; + len--; + idx++; + } + } + else { + memcpy(bptr,flashbase + offset, blen); + } +#else + memcpy(bptr,flashbase + offset, blen); +#endif + + buffer->buf_retlen = blen; + + return 0; +} + +/* ********************************************************************* + * flashdrv_inpstat(ctx,inpstat) + * + * Return "input status". For flash devices, we always return true. + * + * Input parameters: + * ctx - device context + * inpstat - input status structure + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + /* flashdrv_t *softc = ctx->dev_softc; */ + + inpstat->inp_status = 1; + return 0; +} + + +/* ********************************************************************* + * flash_writeall(softc,buffer) + * + * Write the entire flash and reboot. This is a special case + * used for when the flash currently being used for CFE's + * execution is updated. A small assembly routine is relocated + * to DRAM to do the update (so that the programming routine is + * not erased while we're running it), and then the update + * is done. When completed, CFE is restarted. + * + * (we could get really sleazy here and touch the routine first + * so it will stay in the cache, thereby eliminating the need + * to relocate it, but that's dangerous) + * + * Input parameters: + * softc - our context + * buffer - buffer descriptor + * + * Return value: + * does not return + ********************************************************************* */ + +static int flash_writeall(flashdrv_t *softc,iocb_buffer_t *buffer) +{ + void *rptr; + void (*routine)(unsigned char *data,unsigned int flashbase, + unsigned int size,unsigned int secsize); + + rptr = KMALLOC(flash_write_all_len,0); + + if (!rptr) return CFE_ERR_NOMEM; + + memcpy(rptr,flash_write_all_ptr,flash_write_all_len); + + _cfe_flushcache(0); + + routine = rptr; + + (*routine)(buffer->buf_ptr, + softc->flashdrv_probe.flash_phys, + buffer->buf_length, + 65536); + + return -1; +} + + +/* ********************************************************************* + * flashdrv_write(ctx,buffer) + * + * Write data to the flash device. The flash device is + * considered to be like a disk (you need to specify the offset). + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + flashdrv_t *softc = ctx->dev_softc; + unsigned char *bptr; + int offset; + int blen; + int res; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + offset = (int) buffer->buf_offset; + + if (!(softc->flashdrv_unlocked)) { + if ((offset + blen) > softc->flashdrv_devsize) { + blen = softc->flashdrv_devsize - offset; + } + } + + res = FLASHOP_WRITE_BLOCK(softc,offset,bptr,blen); + + buffer->buf_retlen = res; + + /* XXX flush the cache here? */ + + return (res == blen) ? 0 : CFE_ERR_IOERR; +} + +/* ********************************************************************* + * flashdrv_ioctl(ctx,buffer) + * + * Handle special IOCTL functions for the flash. Flash devices + * support NVRAM information, sector and chip erase, and a + * special IOCTL for updating the running copy of CFE. + * + * Input parameters: + * ctx - device context + * buffer - descriptor for IOCTL parameters + * + * Return value: + * 0 if ok else error + ********************************************************************* */ +static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + flashdrv_t *softc = ctx->dev_softc; + nvram_info_t *info; + int offset; + + /* + * If using flash to store environment, only the last sector + * is used for environment stuff. + */ + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_NVRAM_ERASE: + if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED; + FLASHOP_ERASE_SECTOR(softc,softc->flashdrv_nvraminfo.nvram_offset); + return 0; + + case IOCTL_NVRAM_GETINFO: + info = (nvram_info_t *) buffer->buf_ptr; + if (buffer->buf_length != sizeof(nvram_info_t)) return CFE_ERR_INV_PARAM; + if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED; + info->nvram_offset = softc->flashdrv_nvraminfo.nvram_offset; + info->nvram_size = softc->flashdrv_nvraminfo.nvram_size; + info->nvram_eraseflg = softc->flashdrv_nvraminfo.nvram_eraseflg; + buffer->buf_retlen = sizeof(nvram_info_t); + return 0; + + case IOCTL_FLASH_ERASE_SECTOR: + offset = (int) buffer->buf_offset; + if (!(softc->flashdrv_unlocked)) { + if (offset >= softc->flashdrv_devsize) return -1; + } + FLASHOP_ERASE_SECTOR(softc,offset); + return 0; + + case IOCTL_FLASH_ERASE_ALL: + offset = (int) buffer->buf_offset; + if (offset != 0) return -1; + flash_erase_all(softc); + return 0; + + case IOCTL_FLASH_WRITE_ALL: + flash_writeall(softc,buffer); + return -1; /* should not return */ + + case IOCTL_FLASH_GETINFO: + memcpy(buffer->buf_ptr,&(softc->flashdrv_info),sizeof(flash_info_t)); + return 0; + + case IOCTL_FLASH_GETSECTORS: + return flash_sector_query(softc,(flash_sector_t *) buffer->buf_ptr); + + + case IOCTL_FLASH_ERASE_RANGE: + return flash_erase_range(softc,(flash_range_t *) buffer->buf_ptr); + + case IOCTL_NVRAM_UNLOCK: + softc->flashdrv_unlocked = TRUE; + break; + + default: + return -1; + } + + return -1; +} + + +/* ********************************************************************* + * flashdrv_close(ctx) + * + * Close the flash device. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 + ********************************************************************* */ +static int flashdrv_close(cfe_devctx_t *ctx) +{ + /* flashdrv_t *softc = ctx->dev_softc; */ + + /* XXX Invalidate the cache */ + + return 0; +} + + diff --git a/cfe/cfe/dev/dev_ht7520.c b/cfe/cfe/dev/dev_ht7520.c new file mode 100644 index 0000000..8e64971 --- /dev/null +++ b/cfe/cfe/dev/dev_ht7520.c @@ -0,0 +1,167 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * HT7520 (Golem) Bridge Support File: dev_ht7520.c + * + ********************************************************************* + * + * Copyright 2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_physio.h" + +#include "pcireg.h" +#include "pcivar.h" + +extern int eoi_implemented; + +void ht7520apic_preset (pcitag_t tag); +void ht7520apic_setup (pcitag_t tag); + + +/* PLX HT7520 (LDT to PCI-X bridge + APIC) specific definitions */ + +#define PCI_VENDOR_AMD 0x1022 +#define PCI_PRODUCT_PLX_HT7520 0x7450 +#define PCI_PRODUCT_PLX_HT7520_APIC 0x7451 + +/* HT7520 specific registers */ + +/* APIC configuration registers */ + +#define APIC_CONTROL_REG 0x0044 + +#define APIC_CONTROL_OSVISBAR (1 << 0) +#define APIC_CONTROL_IOAEN (1 << 1) + +#define APIC_BASE_ADDR_REG 0x0048 + +/* APIC registers in BAR0 memory space */ + +#define HT7520_APIC_INDEX_REG 0x0000 +#define HT7520_APIC_DATA_REG 0x0010 + +#define APIC_ID_INDEX 0x00 +#define APIC_VERSION_INDEX 0x01 +#define APIC_ARBID_INDEX 0x02 +#define APIC_RDR_BASE_INDEX 0x10 +#define APIC_RDR_LO_INDEX(n) (APIC_RDR_BASE_INDEX + 2*(n)) +#define APIC_RDR_HI_INDEX(n) (APIC_RDR_BASE_INDEX + 2*(n) + 1) + +#define RDR_HI_DEST_SHIFT (56-32) +#define RDR_HI_DEST_MASK (0xff << RDR_HI_DEST_SHIFT) +#define RDR_LO_IM (1 << 16) +#define RDR_LO_TM (1 << 15) +#define RDR_LO_IRR (1 << 14) +#define RDR_LO_POL (1 << 13) +#define RDR_LO_DS (1 << 12) +#define RDR_LO_DM (1 << 11) +#define RDR_LO_MT_SHIFT 8 +#define RDR_LO_MT_MASK (3 << RDR_LO_MT_SHIFT) +#define RDR_LO_IV_SHIFT 0 +#define RDR_LO_IV_MASK (0xff << RDR_LO_IV_SHIFT) + +void +ht7520apic_preset (pcitag_t tag) +{ + pcireg_t ctrl; + + /* For some reason, BAR0 (necessary for setting the interrupt + mapping) is hidden by default; the following makes it + visible. */ + ctrl = pci_conf_read(tag, APIC_CONTROL_REG); + ctrl |= APIC_CONTROL_IOAEN | APIC_CONTROL_OSVISBAR; + pci_conf_write(tag, APIC_CONTROL_REG, ctrl); + ctrl = pci_conf_read(tag, APIC_CONTROL_REG); /* push */ +} + +void +ht7520apic_setup (pcitag_t tag) +{ + int bus, device, function; + pcitag_t br_tag; + int secondary; + struct pci_bus *pb; + unsigned offset; + phys_addr_t apic_addr; + uint32_t rdrh, rdrl; + int i; + + /* The HT7520 splits the bridge and APIC functionality between two + functions. The following code depends upon a known + relationship between the bridge and APIC tags, with a temporary + fudge for the simulator. NB: We assume that the bridge + function has already been initialized. */ + + pci_break_tag(tag, &bus, &device, &function); + +#ifdef _FUNCSIM_ + br_tag = pci_make_tag(bus, device-2, 0); +#else + br_tag = pci_make_tag(bus, device, function-1); +#endif + secondary = (pci_conf_read(br_tag, PPB_BUSINFO_REG) >> 8) & 0xff; + pb = &_pci_bus[secondary]; + + /* Set up interrupt mappings. */ + pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BITS, &apic_addr); + + offset = pb->inta_shift % 4; + for (i = 0; i < 4; i++) { + phys_write32(apic_addr + HT7520_APIC_INDEX_REG, APIC_RDR_HI_INDEX(i)); + rdrh = 0x03 << RDR_HI_DEST_SHIFT; /* CPU 0 + CPU 1 */ + phys_write32(apic_addr + HT7520_APIC_DATA_REG, rdrh); + rdrh = phys_read32(apic_addr + HT7520_APIC_DATA_REG); /* push */ + + phys_write32(apic_addr + HT7520_APIC_INDEX_REG, APIC_RDR_LO_INDEX(i)); + if (eoi_implemented) { + /* Passes >=2 have working EOI. Trigger=Level */ + rdrl = (RDR_LO_TM | /* Level */ + RDR_LO_POL | /* Active Low */ + RDR_LO_DM | /* Logical */ + 0x0 << RDR_LO_MT_SHIFT | /* Fixed */ + (56+offset) << RDR_LO_IV_SHIFT); /* Vector */ + } else { + /* Pass 1 lacks working EOI. Trigger=Edge. Note that + LO_POL appears mis-documented for edges. */ + rdrl = (RDR_LO_DM | /* Logical */ + 0x0 << RDR_LO_MT_SHIFT | /* Fixed */ + (56+offset) << RDR_LO_IV_SHIFT); /* Vector */ + } + phys_write32(apic_addr + HT7520_APIC_DATA_REG, rdrl); + offset = (offset + 1) % 4; + } +} diff --git a/cfe/cfe/dev/dev_ide_common.c b/cfe/cfe/dev/dev_ide_common.c new file mode 100644 index 0000000..e15ac8a --- /dev/null +++ b/cfe/cfe/dev/dev_ide_common.c @@ -0,0 +1,1249 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Generic IDE disk driver File: dev_ide_common.c + * + * This is a simple driver for IDE hard disks. The mechanics + * of talking to the I/O ports are abstracted sufficiently to make + * this driver usable for various bus interfaces. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_timer.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_error.h" + +#include "dev_ide_common.h" + +#include "dev_ide.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define DISK_MASTER 0 +#define DISK_SLAVE 1 + +#define IDE_WRITEREG8(ide,reg,val) IDEDISP_WRITEREG8(ide->idecommon_dispatch,reg,val) +#define IDE_WRITEREG16(ide,reg,val) IDEDISP_WRITEREG8(ide->idecommon_dispatch,reg,val) +#define IDE_WRITEBUF(ide,reg,buf,len) IDEDISP_WRITEBUF(ide->idecommon_dispatch,reg,buf,len) +#define IDE_READREG8(ide,reg) IDEDISP_READREG8(ide->idecommon_dispatch,reg) +#define IDE_READREG16(ide,reg) IDEDISP_READREG16(ide->idecommon_dispatch,reg) +#define IDE_READBUF(ide,reg,buf,len) IDEDISP_READBUF(ide->idecommon_dispatch,reg,buf,len) + +#define GETWORD_LE(buf,wordidx) (((unsigned int) (buf)[(wordidx)*2]) + \ + (((unsigned int) (buf)[(wordidx)*2+1]) << 8)) + +#define _IDE_DEBUG_ + + +static void idecommon_testdrq(idecommon_t *ide); + +/* ********************************************************************* + * idecommon_sectorshift(size) + * + * Given a sector size, return log2(size). We cheat; this is + * only needed for 2048 and 512-byte sectors. + * Explicitly using shifts and masks in sector number calculations + * helps on 32-bit-only platforms, since we probably won't need + * a helper library. + * + * Input parameters: + * size - sector size + * + * Return value: + * # of bits to shift + ********************************************************************* */ + +#define idecommon_sectorshift(size) (((size)==2048)?11:9) + +/* ********************************************************************* + * idecommon_waitnotbusy(ide) + * + * Wait for an IDE device to report "not busy" + * + * Input parameters: + * ide - IDE interface + * + * Return value: + * 0 if ok, else -1 if timeout + ********************************************************************* */ + +static int idecommon_waitnotbusy(idecommon_t *ide) +{ + int32_t timer; + uint8_t status; + + TIMER_SET(timer,10*CFE_HZ); + + while (!TIMER_EXPIRED(timer)) { + status = IDE_READREG8(ide,IDE_REG_STATUS); + if (!(status & IDE_STS_BSY) && (status & IDE_STS_DRQ)) { + idecommon_testdrq(ide); + continue; + } + if ((status & (IDE_STS_BSY | IDE_STS_DRQ )) == 0) return 0; + POLL(); + } + +#ifdef _IDE_DEBUG_ + xprintf("Device did not become unbusy\n"); +#endif + return -1; +} + +#if 0 +/* ********************************************************************* + * idecommon_waitready(ide) + * + * Wait for the specified device to become ready. + * + * Input parameters: + * ide - IDE interface + * + * Return value: + * 0 if device became ready + * -1 if device did not become ready + ********************************************************************* */ + +static int idecommon_waitready(idecommon_t *ide) +{ + int32_t timer; + uint8_t status; + + TIMER_SET(timer,10*CFE_HZ); + + while (!TIMER_EXPIRED(timer)) { + status = IDE_READREG8(ide,IDE_REG_STATUS); + if (status & IDE_STS_RDY) return 0; + POLL(); + } + +#ifdef _IDE_DEBUG_ + xprintf("Disk did not become ready\n"); +#endif + + return -1; +} +#endif + +/* ********************************************************************* + * idecommon_waitbusy(idx) + * + * Wait for an IDE disk to start processing a command, or at + * least long enough to indicate that it is doing so. + * The code below looks suspiciously like a timing loop. + * unfortunately, that's what it is, determined empirically + * for certain ATA flash cards. Without this many reads to the + * ALTSTAT register, the PCMCIA controller deasserts the + * card detect pins briefly. Anyone have any clues? + * + * Input parameters: + * ide - IDE interface + * + * Return value: + * void + ********************************************************************* */ + +static void idecommon_waitbusy(idecommon_t *ide) +{ + int idx; + + for (idx = 0; idx < 10; idx++) { + IDE_READREG8(ide,IDE_REG_ALTSTAT); + IDE_READREG8(ide,IDE_REG_ALTSTAT); + IDE_READREG8(ide,IDE_REG_ALTSTAT); + IDE_READREG8(ide,IDE_REG_ALTSTAT); + } +} + + +/* ********************************************************************* + * idecommon_wait_drq(ide) + * + * Wait for the BUSY bit to be clear and the DRQ bit to be set. + * This is usually the indication that it's time to transfer data. + * + * Input parameters: + * ide - IDE interface + * 0 if DRQ is set + * -1 if timeout occured + ********************************************************************* */ + +static int idecommon_wait_drq(idecommon_t *ide) +{ + int32_t timer; + uint8_t status; + + TIMER_SET(timer,10*CFE_HZ); + + while (!TIMER_EXPIRED(timer)) { + POLL(); + status = IDE_READREG8(ide,IDE_REG_STATUS); + if (!(status & IDE_STS_BSY) && (status & IDE_STS_ERR)) { + xprintf("Drive status: %02X error %02X\n",status, + IDE_READREG8(ide,IDE_REG_ERROR)); + return -1; + } + if (!(status & IDE_STS_BSY) && (status & IDE_STS_DRQ)) return 0; + } + +#ifdef _IDE_DEBUG_ + xprintf("Timeout waiting for disk\n"); +#endif + + return -1; +} + +/* ********************************************************************* + * idecommon_testdrq(ide) + * + * Debug routine. Check the DRQ bit. If it's set, it is not + * supposed to be, so transfer data until it clears and report + * how much we had to transfer. + * + * Input parameters: + * ide - IDE interface + * + * Return value: + * nothing + ********************************************************************* */ + +#ifdef _IDE_DEBUG_ +static void idecommon_testdrq(idecommon_t *ide) +{ + uint8_t status; + uint16_t data; + int idx; + + status = IDE_READREG8(ide,IDE_REG_STATUS); + if (status & IDE_STS_DRQ) { + xprintf("Error: DRQ should be zero\n"); + idx = 0; + while (status & IDE_STS_DRQ) { + data = IDE_READREG16(ide,IDE_REG_DATA); + idx++; + status = IDE_READREG8(ide,IDE_REG_STATUS); + } + xprintf("Had to read data %d times to clear DRQ\n",idx); + } +} +#else +#define idecommon_testdrq(ide) +#endif + + +/* ********************************************************************* + * idecommon_dumpregs(ide) + * + * Dump out the IDE registers. (debug routine) + * + * Input parameters: + * ide - ide disk + * + * Return value: + * nothing + ********************************************************************* */ + +static void idecommon_dumpregs(idecommon_t *ide) +{ +#if 0 + uint8_t reg = 0; + + reg = IDE_READREG8(ide,IDE_REG_STATUS); + xprintf("Status:%02X ",reg); + + reg = IDE_READREG8(ide,IDE_REG_DRVHD); + xprintf("DrvHd:%02X ",reg); + + reg = IDE_READREG8(ide,IDE_REG_CYLLSB); + xprintf("CylLSB:%02X ",reg); + + reg = IDE_READREG8(ide,IDE_REG_CYLMSB); + xprintf("CylMSB:%02X ",reg); + + reg = IDE_READREG8(ide,IDE_REG_SECNUM); + xprintf("SecNum:%02X ",reg); + + reg = IDE_READREG8(ide,IDE_REG_SECCNT); + xprintf("SecCnt:%02X ",reg); + + xprintf("\n"); +#endif +} + + +/* ********************************************************************* + * idecommon_reset(ide) + * + * Reset the IDE interface. + * + * Input parameters: + * ide - IDE interface + * + * Return value: + * 0 if ok, else -1 if a timeout occured + ********************************************************************* */ + +static int idecommon_reset(idecommon_t *ide) +{ + return 0; +} + +/* ********************************************************************* + * idecommon_identify(ide,buffer) + * + * Execute an IDENTIFY command to get information about the disk. + * + * Input parameters: + * ide - IDE interface + * buffer - pointer to 512 byte buffer + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int idecommon_identify(idecommon_t *ide,unsigned char *buffer) +{ + + /* Device Select Protocol; see ATAPI-4 sect 9.6 */ + + if (idecommon_waitnotbusy(ide) < 0) return -1; + IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4)|0); + if (idecommon_waitnotbusy(ide) < 0) return -1; + + /* Set device registers */ + + IDE_WRITEREG8(ide,IDE_REG_CYLLSB,0); + IDE_WRITEREG8(ide,IDE_REG_CYLMSB,0); + IDE_WRITEREG8(ide,IDE_REG_SECNUM,1); + IDE_WRITEREG8(ide,IDE_REG_SECCNT,1); + + idecommon_testdrq(ide); + + /* Issue command, then read ALT STATUS (9.7) */ + + if (ide->idecommon_atapi) { + IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_ATAPI_IDENTIFY); + } + else { + IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_DRIVE_INFO); + } + + IDE_READREG8(ide,IDE_REG_ALTSTAT); + idecommon_waitbusy(ide); /* should not be necessary */ + + /* Wait BSY=0 && DRQ=1, then read buffer, see sect 9.7 */ + + if (idecommon_wait_drq(ide) < 0) return -1; + IDE_READBUF(ide,IDE_REG_DATA,buffer,DISK_SECTORSIZE); + + idecommon_testdrq(ide); + + return 0; +} + +/* ********************************************************************* + * idecommon_packet(ide,packet,pktlen,databuf,datalen) + * + * Process an IDE "packet" command, for ATAPI devices + * + * Input parameters: + * ide - IDE interface + * packet,pktlen - command packet + * databuf,datalen - data buffer + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int idecommon_packet(idecommon_t *ide, + uint8_t *packet,int pktlen, + uint8_t *databuf,int datalen) +{ + uint8_t status; + + /* + * Not valid on non-ATAPI disks + */ + + if (!ide->idecommon_atapi) return -1; + + /* + * Set up the standard IDE registers for an ATAPI PACKET command + */ + + /* Device Select Protocol */ + if (idecommon_waitnotbusy(ide) < 0) return -1; + IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4)); + if (idecommon_waitnotbusy(ide) < 0) return -1; + + /* Device Registers */ + IDE_WRITEREG8(ide,IDE_REG_BCLSB,(datalen & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_BCMSB,((datalen >> 8) & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_SECNUM,0); + IDE_WRITEREG8(ide,IDE_REG_SECCNT,0); + IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_ATAPI_PACKET); + + /* + * Wait for the DRQ bit to indicate that we should send + * the packet. + */ + + if (idecommon_wait_drq(ide) < 0) return -1; + + status = IDE_READREG8(ide,IDE_REG_IR); + + /* + * Send the packet to the device + */ + + IDE_WRITEBUF(ide,IDE_REG_DATA,packet,pktlen); + + /* + * Wait for BSY to be cleared and DRQ to be set. + */ + + if (idecommon_wait_drq(ide) < 0) return -1; + status = IDE_READREG8(ide,IDE_REG_ALTSTAT); + if (idecommon_wait_drq(ide) < 0) return -1; + status = IDE_READREG8(ide,IDE_REG_IR); + + + /* + * Transfer data, if necessary. The direction will depend + * on what the drive says. If this is a non-data command, + * passing databuf == NULL can avoid all this. + */ + + if (databuf) { + status = IDE_READREG8(ide,IDE_REG_IR); + if (status & IDE_IR_CD) { + xprintf("Error: Command/data should be zero\n"); + } + + if (status & IDE_IR_IO) { /* from device (READ) */ + IDE_READBUF(ide,IDE_REG_DATA,databuf,datalen); + } + else { /* to device (WRITE) */ + IDE_WRITEBUF(ide,IDE_REG_DATA,databuf,datalen); + } + + } + + + idecommon_testdrq(ide); + + return 0; + +} + + +/* ********************************************************************* + * idecommon_request_sense(ide) + * + * Request sense data. This also clears a UNIT_ATTENTION condition + * + * Input parameters: + * ide - IDE interface + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +static int idecommon_request_sense(idecommon_t *ide) +{ + uint8_t cdb[12]; + uint8_t sensedata[32]; + int res; + int numbytes; + + numbytes = sizeof(sensedata); + + cdb[0] = CDB_CMD_REQSENSE; + cdb[1] = 0; + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = sizeof(sensedata); + cdb[5] = 0; + cdb[6] = 0; + cdb[7] = 0; + cdb[8] = 0; + cdb[9] = 0; + cdb[10] = 0; + cdb[11] = 0; + + memset(sensedata,0,sizeof(sensedata)); + + res = idecommon_packet(ide,cdb,sizeof(cdb),sensedata,numbytes); + +#if 0 + xprintf("Sense data: "); + xprintf("Err:%02X ",sensedata[0]); + xprintf("Key:%02X ",sensedata[1]); + xprintf("Information:%02X%02X ",sensedata[2],sensedata[3]); + xprintf("ASC:%02X ASCQ:%02X ",sensedata[12],sensedata[13]); + xprintf("\n"); +#endif + + idecommon_testdrq(ide); + + return res; +} + + +/* ********************************************************************* + * idecommon_read_atapi(ide,lba,numsec,buffer) + * + * Read sector(s) from the device. This version is for ATAPI devs. + * + * Input parameters: + * ide - IDE interface + * lba - logical block address + * numsec - number of sectors + * buffer - buffer address + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int idecommon_read_atapi(idecommon_t *ide,uint64_t lba, + int numsec,unsigned char *buffer) +{ + uint8_t cdb[12]; + int res = 0; + int numbytes; + int idx; + + numbytes = numsec << idecommon_sectorshift(ide->idecommon_sectorsize); + + cdb[0] = CDB_CMD_READ; + cdb[1] = 0; + cdb[2] = ((lba >> 24) & 0xFF); + cdb[3] = ((lba >> 16) & 0xFF); + cdb[4] = ((lba >> 8) & 0xFF); + cdb[5] = ((lba >> 0) & 0xFF); + cdb[6] = 0; + cdb[7] = ((numsec >> 8) & 0xFF); + cdb[8] = ((numsec >> 0) & 0xFF); + cdb[9] = 0; + cdb[10] = 0; + cdb[11] = 0; + + for (idx = 0; idx < 4; idx++) { + res = idecommon_packet(ide,cdb,sizeof(cdb),buffer,numbytes); + if (res < 0) { + idecommon_request_sense(ide); + continue; + } + break; + } + + return res; +} + + +/* ********************************************************************* + * idecommon_write_atapi(ide,lba,numsec,buffer) + * + * Write sector(s) to the device. This version is for ATAPI disks + * + * Input parameters: + * ide - IDE interface + * lba - logical block address + * numsec - number of sectors + * buffer - buffer address + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int idecommon_write_atapi(idecommon_t *ide,uint64_t lba, + int numsec,unsigned char *buffer) +{ + uint8_t cdb[12]; + int res; + int numbytes; + + numbytes = numsec << idecommon_sectorshift(ide->idecommon_sectorsize); + + cdb[0] = CDB_CMD_WRITE; + cdb[1] = 0; + cdb[2] = ((lba >> 24) & 0xFF); + cdb[3] = ((lba >> 16) & 0xFF); + cdb[4] = ((lba >> 8) & 0xFF); + cdb[5] = ((lba >> 0) & 0xFF); + cdb[6] = 0; + cdb[7] = ((numsec >> 8) & 0xFF); + cdb[8] = ((numsec >> 0) & 0xFF); + cdb[9] = 0; + cdb[10] = 0; + cdb[11] = 0; + + res = idecommon_packet(ide,cdb,sizeof(cdb),buffer,numbytes); + + return res; +} + + +/* ********************************************************************* + * idecommon_read_lba(ide,lba,numsec,buffer) + * + * Read sector(s) from the device. + * + * Input parameters: + * ide - IDE interface + * lba - logical block address + * numsec - number of sectors + * buffer - buffer address + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int idecommon_read_lba(idecommon_t *ide,uint64_t lba,int numsec,unsigned char *buffer) +{ + int secidx; + unsigned char *ptr; + + if (idecommon_waitnotbusy(ide) < 0) return -1; + IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4) | ((lba >> 24) & 0x0F) | 0x40); + if (idecommon_waitnotbusy(ide) < 0) return -1; + + IDE_WRITEREG8(ide,IDE_REG_CYLMSB,((lba >> 16) & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_CYLLSB,((lba >> 8) & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_SECNUM,(lba & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_SECCNT,numsec); + + idecommon_testdrq(ide); + + IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_READ); + + idecommon_waitbusy(ide); + if (idecommon_wait_drq(ide) < 0) return -1; + + ptr = buffer; + + for (secidx = 0; secidx < numsec; secidx++) { + IDE_READBUF(ide,IDE_REG_DATA,ptr,ide->idecommon_sectorsize); + ptr += ide->idecommon_sectorsize; + } + + idecommon_testdrq(ide); + + return 0; +} + + +/* ********************************************************************* + * idecommon_write_lba(ide,lba,numsec,buffer) + * + * Write sector(s) from the device. + * + * Input parameters: + * ide - IDE interface + * lba - logical block address + * numsec - number of sectors + * buffer - buffer address + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int idecommon_write_lba(idecommon_t *ide,uint64_t lba,int numsec,unsigned char *buffer) +{ + int secidx; + uint8_t *ptr; + + if (idecommon_waitnotbusy(ide) < 0) return -1; + IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4) | ((lba >> 24) & 0x0F) | 0x40); + if (idecommon_waitnotbusy(ide) < 0) return -1; + + IDE_WRITEREG8(ide,IDE_REG_CYLMSB,((lba >> 16) & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_CYLLSB,((lba >> 8) & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_SECNUM,(lba & 0xFF)); + IDE_WRITEREG8(ide,IDE_REG_SECCNT,numsec); + + IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_WRITE); + + if (idecommon_wait_drq(ide) < 0) return -1; + + ptr = buffer; + + for (secidx = 0; secidx < numsec; secidx++) { + IDE_WRITEBUF(ide,IDE_REG_DATA,ptr,ide->idecommon_sectorsize); + ptr += ide->idecommon_sectorsize; + } + + idecommon_testdrq(ide); + + return 0; +} + + +/* ********************************************************************* + * idecommon_diagnostic(ide) + * + * run the device diagnostics on the IDE device. This also + * helps us determine if it's an IDE or ATAPI disk, since the + * diagnostic will leave a signature in the registers. + * + * Input parameters: + * softc - IDE interface + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int idecommon_diagnostic(idecommon_t *softc) +{ + if (idecommon_waitnotbusy(softc) < 0) return -1; + IDE_WRITEREG8(softc,IDE_REG_DRVHD,(softc->idecommon_unit<<4)); + if (idecommon_waitnotbusy(softc) < 0) return -1; + + IDE_WRITEREG8(softc,IDE_REG_COMMAND,IDE_CMD_DIAGNOSTIC); + if (idecommon_waitnotbusy(softc) < 0) return -1; + + cfe_sleep(CFE_HZ/2); + idecommon_dumpregs(softc); + + return 0; +} + + +/* ********************************************************************* + * idecommon_getmodel(buffer,model) + * + * Get the ASCII model name out of an IDE identify buffer. some + * byte swapping is involved here. The trailing blanks are trimmed. + * + * Input parameters: + * buffer - 512-byte buffer from IDENTIFY command + * model - 41-byte string (max) for model name + * + * Return value: + * nothing + ********************************************************************* */ + +static void idecommon_getmodel(uint8_t *buffer,char *model) +{ + uint16_t w; + int idx; + + for (idx = 0; idx < 20; idx++) { + w = GETWORD_LE(buffer,27+idx); + model[idx*2] = w >> 8; + model[idx*2+1] = w & 0xFF; + } + for (idx = 39; idx > 0; idx--) { + if (model[idx] != ' ') { + model[idx+1] = '\0'; + break; + } + } + +} + +/* ********************************************************************* + * idecommon_devprobe(softc) + * + * Probe the IDE device, to determine if it's actually present + * or not. If present, determine if it's IDE or ATAPI and + * get the device size. Init our internal structures so we know + * how to talk to the device. + * + * Input parameters: + * softc - IDE structure + * noisy - display stuff as we probe + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int idecommon_devprobe(idecommon_t *softc,int noisy) +{ + int res; + int atapi; + unsigned char buffer[DISK_SECTORSIZE]; + unsigned char model[41]; + uint64_t ttlsect; + int devtype; + uint16_t w; + char *typename; + + /* + * Reset the drive + */ + + res = idecommon_reset(softc); + if (res < 0) return -1; + + /* + * Run diagnostic to get the signature. + */ + + res = idecommon_diagnostic(softc); + if (res < 0) return res; + + /* + * Test signature + */ + + atapi = 0; + if ((IDE_READREG8(softc,IDE_REG_CYLLSB) == ATAPI_SIG_LSB) && + (IDE_READREG8(softc,IDE_REG_CYLMSB) == ATAPI_SIG_MSB)) { + atapi = 1; + } + + if (noisy) { + if (atapi) xprintf("ATAPI: "); + else xprintf("IDE: "); + } + + /* + * Do tha appropriate IDENTIFY command to get device information + */ + + softc->idecommon_atapi = atapi; + res = idecommon_identify(softc,buffer); + if (res < 0) return -1; + + /* + * Using that information, determine our device type + */ + + if (!atapi) { + devtype = IDE_DEVTYPE_DISK; + typename = "Disk"; + } + else { + w = GETWORD_LE(buffer,0); + switch ((w >> 8) & 31) { + case 5: /* CD-ROM */ + devtype = IDE_DEVTYPE_CDROM; + typename = "CD-ROM"; + break; + default: + devtype = IDE_DEVTYPE_ATAPIDISK; + typename = "Disk"; + break; + } + } + + /* + * Say nice things about the device. + */ + + idecommon_getmodel(buffer,model); + if (noisy) xprintf("%s, \"%s\"",typename,model); + + +#ifdef _IDE_DEBUG_ + if (!softc->idecommon_atapi) { + ttlsect = (GETWORD_LE(buffer,57) + (GETWORD_LE(buffer,58) << 16)); + if (noisy) xprintf(", Sectors: %llu (%lld MB)",ttlsect, + (uint64_t) (ttlsect/2048)); + } + else { + ttlsect = 0; + } +#endif + if (noisy) xprintf("\n"); + + /* + * Initialize internal structure info, especially pointers to the + * read/write routines and the sector size. + */ + + softc->idecommon_ttlsect = ttlsect; + idecommon_init(softc,devtype); + + return res; +} + +/* ********************************************************************* + * idecommon_open(ctx) + * + * Process the CFE OPEN call for this device. For IDE disks, + * the device is reset and identified, and the geometry is + * determined. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + + +int idecommon_open(cfe_devctx_t *ctx) +{ + idecommon_t *softc = ctx->dev_softc; + int res; + + if (softc->idecommon_deferprobe) { + res = idecommon_devprobe(softc,0); + if (res < 0) return res; + } + + return 0; +} + +/* ********************************************************************* + * idecommon_read(ctx,buffer) + * + * Process a CFE READ command for the IDE device. This is + * more complex than it looks, since CFE offsets are byte offsets + * and we may need to read partial sectors. + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * number of bytes read, or <0 if an error occured + ********************************************************************* */ + +int idecommon_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + idecommon_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + int numsec; + int res = 0; + int amtcopy; + uint64_t lba; + uint64_t offset; + unsigned char sector[MAX_SECTORSIZE]; + int sectorshift; + + sectorshift = idecommon_sectorshift(softc->idecommon_sectorsize); + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + offset = buffer->buf_offset; + numsec = (blen + softc->idecommon_sectorsize - 1) >> sectorshift; + + if (offset & (softc->idecommon_sectorsize-1)) { + lba = (offset >> sectorshift); + res = (*softc->idecommon_readfunc)(softc,lba,1,sector); + if (res < 0) goto out; + amtcopy = softc->idecommon_sectorsize - (offset & (softc->idecommon_sectorsize-1)); + if (amtcopy > blen) amtcopy = blen; + memcpy(bptr,§or[offset & (softc->idecommon_sectorsize-1)],amtcopy); + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + while (blen >= softc->idecommon_sectorsize) { + lba = (offset >> sectorshift); + amtcopy = softc->idecommon_sectorsize; + res = (*softc->idecommon_readfunc)(softc,lba,1,bptr); + if (res < 0) goto out; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + if (blen) { + lba = (offset >> sectorshift); + res = (*softc->idecommon_readfunc)(softc,lba,1,sector); + if (res < 0) goto out; + amtcopy = blen; + memcpy(bptr,sector,amtcopy); + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + +out: + buffer->buf_retlen = bptr - buffer->buf_ptr; + + return res; +} + +/* ********************************************************************* + * idecommon_inpstat(ctx,inpstat) + * + * Test input status for the IDE disk. Disks are always ready + * to read. + * + * Input parameters: + * ctx - device context + * inpstat - input status structure + * + * Return value: + * 0 + ********************************************************************* */ + +int idecommon_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + /* idecommon_t *softc = ctx->dev_softc; */ + + inpstat->inp_status = 1; + return 0; +} + +/* ********************************************************************* + * idecommon_write(ctx,buffer) + * + * Process a CFE WRITE command for the IDE device. If the write + * involves partial sectors, the affected sectors are read first + * and the changes are merged in. + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * number of bytes write, or <0 if an error occured + ********************************************************************* */ + +int idecommon_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + idecommon_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + int numsec; + int res = 0; + int amtcopy; + uint64_t offset; + uint64_t lba; + unsigned char sector[MAX_SECTORSIZE]; + int sectorshift; + + sectorshift = (softc->idecommon_sectorsize == 2048) ? 11 : 9; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + offset = buffer->buf_offset; + numsec = (blen + softc->idecommon_sectorsize - 1) >> sectorshift; + + if (offset & (softc->idecommon_sectorsize-1)) { + lba = (offset >> sectorshift); + res = (*softc->idecommon_readfunc)(softc,lba,1,sector); + if (res < 0) goto out; + amtcopy = softc->idecommon_sectorsize - (offset & (softc->idecommon_sectorsize-1)); + if (amtcopy > blen) amtcopy = blen; + memcpy(§or[offset & (softc->idecommon_sectorsize-1)],bptr,amtcopy); + res = (*softc->idecommon_writefunc)(softc,lba,1,sector); + if (res < 0) goto out; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + while (blen >= softc->idecommon_sectorsize) { + amtcopy = softc->idecommon_sectorsize; + lba = (offset >> sectorshift); + res = (*softc->idecommon_writefunc)(softc,lba,1,bptr); + if (res < 0) goto out; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + if (blen) { + lba = (offset >> sectorshift); + res = (*softc->idecommon_readfunc)(softc,lba,1,sector); + if (res < 0) goto out; + amtcopy = blen; + memcpy(sector,bptr,amtcopy); + res = (*softc->idecommon_writefunc)(softc,lba,1,sector); + if (res < 0) goto out; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + +out: + buffer->buf_retlen = bptr - buffer->buf_ptr; + + return res; +} + + +/* ********************************************************************* + * idecommon_ioctl(ctx,buffer) + * + * Process device I/O control requests for the IDE device. + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int idecommon_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + idecommon_t *softc = ctx->dev_softc; + unsigned int *info = (unsigned int *) buffer->buf_ptr; + unsigned long long *linfo = (unsigned long long *) buffer->buf_ptr; + blockdev_info_t *devinfo; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_BLOCK_GETBLOCKSIZE: + *info = softc->idecommon_sectorsize; + break; + case IOCTL_BLOCK_GETTOTALBLOCKS: + *linfo = softc->idecommon_ttlsect; + break; + case IOCTL_BLOCK_GETDEVTYPE: + devinfo = (blockdev_info_t *) buffer->buf_ptr; + devinfo->blkdev_totalblocks = softc->idecommon_ttlsect; + devinfo->blkdev_blocksize = softc->idecommon_sectorsize; + devinfo->blkdev_devtype = (softc->idecommon_devtype == IDE_DEVTYPE_CDROM) ? + BLOCK_DEVTYPE_CDROM : BLOCK_DEVTYPE_DISK; + break; + default: + return -1; + } + + return 0; +} + +/* ********************************************************************* + * idecommon_close(ctx) + * + * Close the I/O device. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int idecommon_close(cfe_devctx_t *ctx) +{ + /* idecommon_t *softc = ctx->dev_softc; */ + + return 0; +} + + +/* ********************************************************************* + * idecommon_init(ide,devtype) + * + * Set up internal values based on the device type + * + * Input parameters: + * ide - IDE interface + * devtype - device type + * + * Return value: + * nothing + ********************************************************************* */ + +void idecommon_init(idecommon_t *ide,int devtype) +{ + + ide->idecommon_devtype = devtype; + + switch (ide->idecommon_devtype) { + case IDE_DEVTYPE_DISK: + ide->idecommon_atapi = FALSE; + ide->idecommon_sectorsize = DISK_SECTORSIZE; + break; + case IDE_DEVTYPE_CDROM: + ide->idecommon_atapi = TRUE; + ide->idecommon_sectorsize = CDROM_SECTORSIZE; + break; + case IDE_DEVTYPE_ATAPIDISK: + ide->idecommon_atapi = TRUE; + ide->idecommon_sectorsize = DISK_SECTORSIZE; + break; + default: + ide->idecommon_atapi = FALSE; + ide->idecommon_sectorsize = DISK_SECTORSIZE; + break; + } + + if (ide->idecommon_atapi) { + ide->idecommon_readfunc = idecommon_read_atapi; + ide->idecommon_writefunc = idecommon_write_atapi; + } + else { + ide->idecommon_readfunc = idecommon_read_lba; + ide->idecommon_writefunc = idecommon_write_lba; + } +} + +/* ********************************************************************* + * idecommon_attach(devdisp) + * + * Set up a cfe_devdisp structure that points at the idecommon + * structures. + * + * Input parameters: + * devdisp - cfe_devdisp_t structure + * + * Return value: + * nothing + ********************************************************************* */ +void idecommon_attach(cfe_devdisp_t *disp) +{ + disp->dev_open = idecommon_open; + disp->dev_read = idecommon_read; + disp->dev_inpstat = idecommon_inpstat; + disp->dev_write = idecommon_write; + disp->dev_ioctl = idecommon_ioctl; + disp->dev_close = idecommon_close; + disp->dev_poll = NULL; + disp->dev_reset = NULL; +} diff --git a/cfe/cfe/dev/dev_ide_pci.c b/cfe/cfe/dev/dev_ide_pci.c new file mode 100644 index 0000000..ecf4c2a --- /dev/null +++ b/cfe/cfe/dev/dev_ide_pci.c @@ -0,0 +1,358 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PCI IDE disk driver File: dev_ide_pci.c + * + * This is a simple driver for IDE hard disks that are connected + * to PCI IDE controllers, such as a Promise UltraXX. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_timer.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" + +#include "dev_ide_common.h" + +#include "dev_ide.h" + +#include "pcivar.h" +#include "pcireg.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define _BYTESWAP_ /* don't byteswap these disks */ + +#define OUTB(x,y) outb(x,y) +#define OUTW(x,y) outw(x,y) +#define INB(x) inb(x) +#define INW(x) inw(x) + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + +extern void _wbflush(void); + +static void idedrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +/* ********************************************************************* + * Device Dispatch + ********************************************************************* */ + +static cfe_devdisp_t idedrv_dispatch = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +const cfe_driver_t pciidedrv = { + "PCI IDE disk", + "ide", + CFE_DEV_DISK, + &idedrv_dispatch, + idedrv_probe +}; + +const cfe_driver_t pciatapidrv = { + "PCI ATAPI device", + "atapi", + CFE_DEV_DISK, + &idedrv_dispatch, + idedrv_probe +}; + +/* ********************************************************************* + * Supported PCI devices + ********************************************************************* */ + +#define DEVID(vid,pid) (((pid)<<16)|(vid)) + +static uint32_t pciidedrv_devlist[] = { + DEVID(0x105a,0x4d33), /* Promise Ultra33 */ + DEVID(0x1095,0x0649), /* CMD PCI0649 */ + DEVID(0x1095,0x0648), /* CMD PCI0648 */ + 0xFFFFFFFF +}; + + +/* ********************************************************************* + * Port I/O routines + * + * These routines are called back from the common code to do + * I/O cycles to the IDE disk. We provide routines for + * reading and writing bytes, words, and strings of words. + ********************************************************************* */ + +static uint8_t idedrv_inb(idecommon_dispatch_t *disp,uint32_t reg) +{ + return INB(reg+disp->baseaddr); +} + +static uint16_t idedrv_inw(idecommon_dispatch_t *disp,uint32_t reg) +{ + return INW(reg+disp->baseaddr); +} + +static void idedrv_ins(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len) +{ + uint16_t data; + + while (len > 0) { + data = INW(reg+disp->baseaddr); + +#ifdef _BYTESWAP_ + *buf++ = (data >> 8) & 0xFF; + *buf++ = (data & 0xFF); +#else + *buf++ = (data & 0xFF); + *buf++ = (data >> 8) & 0xFF; +#endif + len--; + len--; + } + +} + +static void idedrv_outb(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val) +{ + OUTB(reg+disp->baseaddr,val); +} + +static void idedrv_outw(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val) +{ + OUTW(reg+disp->baseaddr,val); +} + +static void idedrv_outs(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len) +{ + uint16_t data; + + while (len > 0) { +#ifdef _BYTESWAP_ + data = (uint16_t) buf[1] + ((uint16_t) buf[0] << 8); +#else + data = (uint16_t) buf[0] + ((uint16_t) buf[1] << 8); +#endif + + OUTW(reg+disp->baseaddr,data); + + buf++; + buf++; + len--; + len--; + } +} + + +/* ********************************************************************* + * pciidedrv_find(devid,list) + * + * Find a particular product ID on the list. Return >= 0 if + * the ID is valid. + * + * Input parameters: + * devid - product and device ID we have + * list - list of product and device IDs we're looking for + * + * Return value: + * index into table, or -1 if not found + ********************************************************************* */ +static int pciidedrv_find(uint32_t devid,uint32_t *list) +{ + int idx = 0; + + while (list[idx] != 0xFFFFFFFF) { + if (list[idx] == devid) return idx; + idx++; + } + + return -1; +} + + +/* ********************************************************************* + * idedrv_probe(drv,probe_a,probe_b,probe_ptr) + * + * Our probe routine. Attach an IDE device to the firmware. + * + * Input parameters: + * drv - driver structure + * probe_a - physical address of IDE registers + * probe_b - unit number + * probe_ptr - not used + * + * Return value: + * nothing + ********************************************************************* */ + +static void idedrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + idecommon_t *softc; + idecommon_dispatch_t *disp; + char descr[80]; + char unitstr[50]; + pcitag_t tag; + int index; + uint32_t devid; + uint32_t reg; + int res; + int unit; + cfe_driver_t *realdrv; + int attached = 0; + + /* + * probe_a is unused + * probe_b is unused + * probe_ptr is unused. + */ + + index = 0; + + for (;;) { + if (pci_find_class(PCI_CLASS_MASS_STORAGE,index,&tag) != 0) break; + index++; + devid = pci_conf_read(tag,PCI_ID_REG); + + if (pciidedrv_find(devid,pciidedrv_devlist) < 0) { + continue; + } + + + reg = pci_conf_read(tag,PCI_MAPREG(0)); + + if (PCI_MAPREG_TYPE(reg) != PCI_MAPREG_TYPE_IO) { + xprintf("Skipping this IDE device, we don't do memory mapped IDE yet\n"); + continue; + } + + reg &= ~PCI_MAPREG_TYPE_MASK; + + for (unit = 0; unit < 2; unit++) { + + /* + * If we've deliberately disabled probing of this + * device, then skip it. + */ + + if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_NOPROBE) { + continue; + } + + softc = (idecommon_t *) KMALLOC(sizeof(idecommon_t),0); + disp = (idecommon_dispatch_t *) KMALLOC(sizeof(idecommon_dispatch_t),0); + + if (!softc || !disp) { + if (softc) KFREE(softc); + if (disp) KFREE(disp); + return; /* out of memory, stop here */ + } + + + softc->idecommon_addr = reg; + disp->ref = softc; + disp->baseaddr = softc->idecommon_addr; + softc->idecommon_deferprobe = 0; + softc->idecommon_dispatch = disp; + softc->idecommon_unit = unit; + + disp->outb = idedrv_outb; + disp->outw = idedrv_outw; + disp->outs = idedrv_outs; + + disp->inb = idedrv_inb; + disp->inw = idedrv_inw; + disp->ins = idedrv_ins; + + /* + * If we're autoprobing, do it now. Loop back if we have + * trouble finding the device. + * + * If not autoprobing, assume the device is there and set the + * common routines to double check later. + */ + + if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_AUTO) { + res = idecommon_devprobe(softc,1); + if (res < 0) { + KFREE(softc); + KFREE(disp); + continue; + } + } + else { + idecommon_init(softc,IDE_PROBE_GET_TYPE(probe_b,unit)); + softc->idecommon_deferprobe = 1; + } + + xsprintf(descr,"%s unit %d at I/O %04X",drv->drv_description, + softc->idecommon_unit,softc->idecommon_addr); + xsprintf(unitstr,"%d",unit); + + realdrv = (cfe_driver_t *) (softc->idecommon_atapi ? &pciatapidrv : &pciidedrv); + + idecommon_attach(&idedrv_dispatch); + cfe_attach(realdrv,softc,unitstr,descr); + attached++; + } + + } + + xprintf("PCIIDE: %d controllers found\n",attached); +} + + diff --git a/cfe/cfe/dev/dev_newflash.c b/cfe/cfe/dev/dev_newflash.c new file mode 100644 index 0000000..d196e92 --- /dev/null +++ b/cfe/cfe/dev/dev_newflash.c @@ -0,0 +1,1428 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "New" Flash device driver File: dev_newflash.c + * + * This driver supports various types of flash + * parts. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "addrspace.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_error.h" + +#include "bsp_config.h" +#include "dev_newflash.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define GETCFIBYTE(arr,x) (arr[(x)*2]) + +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +/* + * Get the address of the flash sector buffer from the + * config file. Addresses are PHYSICAL. + */ + +#ifndef CFG_FLASH_SECTOR_BUFFER_ADDR +#define CFG_FLASH_SECTOR_BUFFER_ADDR (100*1024*1024-128*1024) +#endif + +#ifndef CFG_FLASH_SECTOR_BUFFER_SIZE +#define CFG_FLASH_SECTOR_BUFFER_SIZE (128*1024) +#endif + + +/*#define _NEWFLASH_DEBUG_ */ + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + + +static void flashdrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +static int flashdrv_open(cfe_devctx_t *ctx); +static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int flashdrv_close(cfe_devctx_t *ctx); + +/* ********************************************************************* + * Device dispatch + ********************************************************************* */ + +const static cfe_devdisp_t flashdrv_dispatch = { + flashdrv_open, + flashdrv_read, + flashdrv_inpstat, + flashdrv_write, + flashdrv_ioctl, + flashdrv_close, + NULL, + NULL +}; + +const cfe_driver_t newflashdrv = { + "New CFI flash", + "flash", + CFE_DEV_FLASH, + &flashdrv_dispatch, + flashdrv_probe +}; + + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern void *flashop_engine_ptr; +extern int flashop_engine_len; + +extern void _cfe_flushcache(int); + +static int flash_sector_query(flashdev_t *softc,flash_sector_t *sector); + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +/* + * This is a pointer to a DRAM version of our flash subroutines. + * We make a global here so that it doesn't get copied multiple + * times for each flash we instantiate. + */ + +static int (*flashop_engine_ram)(flashinstr_t *prog) = NULL; +static uint8_t *flash_sector_buffer = NULL; + +/* ********************************************************************* + * FLASH_OP_BEGIN(softc) + * + * Reset the pointer to the flash operations so that we can + * begin filling in new instructions to execute + * + * Input parameters: + * softc - our softc. + * + * Return value: + * nothing + ********************************************************************* */ + +#define flash_op_begin(softc) softc->fd_iptr = 0; + +/* ********************************************************************* + * FLASH_OP_ADD(softc,op,dest,src,cnt) + * + * Add an instruction to the flashop table + * + * Input parameters: + * softc - our flash + * op,dest,src,cnt - data for the opcode + * + * Return value: + * nothing + ********************************************************************* */ + +static void flash_op_add(flashdev_t *softc,long base,long op,long dest,long src,long cnt) +{ + flashinstr_t *fi = &(softc->fd_inst[softc->fd_iptr]); + + fi->fi_op = op; + fi->fi_base = base; + fi->fi_dest = dest; + fi->fi_src = src; + fi->fi_cnt = cnt; + + softc->fd_iptr++; +} + + +/* ********************************************************************* + * FLASH_OP_EXECUTE(softc) + * + * Execute the stored "flash operations" + * + * Input parameters: + * softc - our flash + * + * Return value: + * 0 if ok, else # of failures (less than zero) + ********************************************************************* */ + +static int flash_op_execute(flashdev_t *softc) +{ + flash_op_add(softc,softc->fd_probe.flash_phys,FEOP_RETURN,0,0,0); + +#ifdef _NEWFLASH_DEBUG_ + if (1) { + int idx; + printf("---------------\nCalling engine @ %08X\n",flashop_engine_ram); + for (idx = 0; idx < softc->fd_iptr; idx++) { + printf("%2d %08X %08X %08X %08X\n", + softc->fd_inst[idx].fi_op, + softc->fd_inst[idx].fi_base, + softc->fd_inst[idx].fi_dest, + softc->fd_inst[idx].fi_src, + softc->fd_inst[idx].fi_cnt); + } + } +#endif + + /* + * If someone hooked the flashop engine, call the hook. + */ + if (softc->fd_probe.flash_engine_hook) { + return (*(softc->fd_probe.flash_engine_hook))(&(softc->fd_inst[0])); + } + + /* + * Otherwise, call the standard one. + */ + if (!flashop_engine_ram) return CFE_ERR_UNSUPPORTED; + return (*flashop_engine_ram)(&(softc->fd_inst[0])); +} + + +/* ********************************************************************* + * FLASH_SETUP_ENGINE() + * + * Set up the "flash engine", copying the routine to DRAM + * and flushing the cache so we can call it. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void flash_setup_engine(void) +{ +#if ((CFG_RAMAPP) || (CFG_EMBEDDED_PIC)) + /* CFE is relocated, no need to copy flash engine to heap */ + flashop_engine_ram = (void *) flashop_engine_ptr; +#else + /* Copy flash engine to heap */ + uint32_t *dst,*src; + int idx; + + if (flashop_engine_ram) return; /* already done */ + + /* + * Allocate space for engine + */ + + flashop_engine_ram = (void *) KMALLOC(flashop_engine_len,0); + if (!flashop_engine_ram) return; + + /* + * Copy engine to RAM - do it 32-bits at a time to avoid + * a certain platform with broken byte reads (no, not the 1250) + */ + + dst = (uint32_t *) flashop_engine_ram; + src = (uint32_t *) flashop_engine_ptr; + for (idx = 0; idx < flashop_engine_len/sizeof(uint32_t); idx++) { + *dst++ = *src++; + } + + /* + * Flush the d-cache, invalidate the I-cache. + */ + + _cfe_flushcache(1); + _cfe_flushcache(2); +#endif +} + +/* ********************************************************************* + * FLASH_ERASE_RANGE(softc,range) + * + * Erase a range of sectors + * + * Input parameters: + * softc - our flash + * range - range structure + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +static int flash_erase_range(flashdev_t *softc,flash_range_t *range) +{ + flash_sector_t sector; + int res; + + if (softc->fd_probe.flash_type != FLASH_TYPE_FLASH) { + return CFE_ERR_UNSUPPORTED; + } + + if (range->range_base+range->range_length > softc->fd_probe.flash_size) { + return CFE_ERR_INV_PARAM; + } + + res = 0; + + sector.flash_sector_idx = 0; + + for (;;) { + res = flash_sector_query(softc,§or); + if (res != 0) break; + if (sector.flash_sector_status == FLASH_SECTOR_INVALID) { + break; + } + + if ((sector.flash_sector_offset >= range->range_base) && + (sector.flash_sector_offset < + (range->range_base+range->range_length-1))) { + + flash_op_begin(softc); + flash_op_add(softc,softc->fd_probe.flash_phys, + softc->fd_erasefunc, + sector.flash_sector_offset, + 0,0); + res = flash_op_execute(softc); + + if (res != 0) break; + } + sector.flash_sector_idx++; + } + + return res; + +} + +/* ********************************************************************* + * FLASH_ERASE_ALL(softc) + * + * Erase the entire flash device, except the NVRAM area, + * sector-by-sector. + * + * Input parameters: + * softc - our flash + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int flash_erase_all(flashdev_t *softc) +{ + flash_range_t range; + + range.range_base = 0; + range.range_length = softc->fd_probe.flash_size * + softc->fd_probe.flash_nchips; + + return flash_erase_range(softc,&range); +} + + +/* ********************************************************************* + * flash_range_intersection(sector,inrange,outrange) + * + * Compute the intersection between a flash range and a + * sector. + * + * Input parameters: + * sector - sector to examine + * range - range we are checking + * outrange - where to put resulting intersection range + * + * Return value: + * 1 - range is an entire sector + * 0 - range is a partial sector + * -1 - range has no intersection + ********************************************************************* */ + +static int flash_range_intersection(flash_sector_t *sector, + flash_range_t *inrange, + flash_range_t *outrange) +{ + int start,end; + + /* + * compute the start and end pointers + */ + + start = (int) (max(sector->flash_sector_offset, + inrange->range_base)); + + end = (int) (min((sector->flash_sector_offset+sector->flash_sector_size), + (inrange->range_base+inrange->range_length))); + + /* + * if the end is in the right place wrt the start, + * there is an intersection. + */ + + if (end > start) { + outrange->range_base = (unsigned int) start; + outrange->range_length = (unsigned int) (end-start); + + if ((sector->flash_sector_offset == outrange->range_base) && + (sector->flash_sector_size == outrange->range_length)) { + return 1; /* instersection: entire sector */ + } + else { + return 0; /* intersection: partial sector */ + } + } + else { + outrange->range_base = (unsigned int) start; + outrange->range_length = 0; + return -1; /* intersection: none */ + } +} + + +/* ********************************************************************* + * FLASH_SECTOR_QUERY(softc,sector) + * + * Query the sector information about a particular sector. You can + * call this iteratively to find out about all of the sectors. + * + * Input parameters: + * softc - our flash info + * sector - structure to receive sector information + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int flash_sector_query(flashdev_t *softc,flash_sector_t *sector) +{ + int idx; + int nblks; + int blksiz; + unsigned int offset; + int whichchip; + int secidx; + int curblk; + + if (softc->fd_probe.flash_type != FLASH_TYPE_FLASH) { + return CFE_ERR_UNSUPPORTED; + } + + if (softc->fd_probe.flash_nsectors == 0) { + return CFE_ERR_UNSUPPORTED; + } + + /* Figure out which chip */ + whichchip = sector->flash_sector_idx / softc->fd_ttlsect; + if (whichchip >= softc->fd_probe.flash_nchips) { + sector->flash_sector_status = FLASH_SECTOR_INVALID; + return 0; + } + + /* Within that chip, get sector info */ + offset = softc->fd_probe.flash_size * whichchip; + secidx = sector->flash_sector_idx % softc->fd_ttlsect; + curblk = 0; + + for (idx = 0; idx < softc->fd_probe.flash_nsectors; idx++) { + nblks = FLASH_SECTOR_NBLKS(softc->fd_probe.flash_sectors[idx]); + blksiz = FLASH_SECTOR_SIZE(softc->fd_probe.flash_sectors[idx]); + if (secidx < curblk+nblks) { + sector->flash_sector_status = FLASH_SECTOR_OK; + sector->flash_sector_offset = + offset + (secidx-curblk)*blksiz; + sector->flash_sector_size = blksiz; + break; + } + + offset += (nblks)*blksiz; + curblk += nblks; + } + + + if (idx == softc->fd_probe.flash_nsectors) { + sector->flash_sector_status = FLASH_SECTOR_INVALID; + } + + return 0; +} + + +/* ********************************************************************* + * FLASH_SET_CMDSET(softc,cmdset,bus16,dev16) + * + * Set the command-set that we'll honor for this flash. + * + * Input parameters: + * softc - our flash + * cmdset - FLASH_CFI_CMDSET_xxx + * bus16 - true if bus is 16 bits wide + * dev16 - true if device supports 16-bit operation + * + * So: bus16 && dev16 -> 16-bit commands + * !bus16 && dev16 -> 8-bit commands to 16-bit flash with BYTE# + * !bus16 && !dev16 -> 8-bit commands + * + * Return value: + * nothing + ********************************************************************* */ + +static void flash_set_cmdset(flashdev_t *softc,int cmdset,int bus16,int dev16) +{ + switch (cmdset) { +#if (FLASH_DRIVERS & FLASH_DRIVER_INTEL) + case FLASH_CFI_CMDSET_INTEL_ECS: + case FLASH_CFI_CMDSET_INTEL_STD: + if (bus16) { + softc->fd_erasefunc = FEOP_INTEL_ERASE16; + softc->fd_pgmfunc = FEOP_INTEL_PGM16; + softc->fd_readfunc = FEOP_READ16; + } + else { + softc->fd_erasefunc = FEOP_INTEL_ERASE8; + softc->fd_pgmfunc = FEOP_INTEL_PGM8; + softc->fd_readfunc = FEOP_READ8; + } + break; +#endif +#if (FLASH_DRIVERS & FLASH_DRIVER_AMD) + case FLASH_CFI_CMDSET_AMD_STD: + case FLASH_CFI_CMDSET_AMD_ECS: + if (!bus16 && !dev16) { /* 8-bit bus, 8-bit flash */ + softc->fd_erasefunc = FEOP_AMD_ERASE8; + softc->fd_pgmfunc = FEOP_AMD_PGM8; + softc->fd_readfunc = FEOP_READ8; + } + else if (bus16 && dev16) { /* 16-bit bus, 16-bit flash */ + softc->fd_erasefunc = FEOP_AMD_ERASE16; + softc->fd_pgmfunc = FEOP_AMD_PGM16; + softc->fd_readfunc = FEOP_READ16; + } + else { /* 8-bit bus, 16-bit flash w/BYTE# */ + softc->fd_erasefunc = FEOP_AMD_ERASE16B; + softc->fd_pgmfunc = FEOP_AMD_PGM16B; + softc->fd_readfunc = FEOP_READ8; + } + break; +#endif + default: + /* we don't understand the command set - treat it like ROM */ + softc->fd_erasefunc = FEOP_RETURN; + softc->fd_pgmfunc = FEOP_RETURN; + softc->fd_readfunc = bus16 ? FEOP_READ16 : FEOP_READ8; + break; + } +} + +#if (FLASH_DRIVERS & FLASH_DRIVER_CFI) +/* ********************************************************************* + * FLASH_CFI_PROBE(softc) + * + * Try to do a CFI query on this device. If we find the m + * magic signature, extract some useful information from the + * query structure. + * + * Input parameters: + * softc - out flash + * + * Return value: + * 0 if successful, <0 if error + ********************************************************************* */ +static int flash_cfi_probe(flashdev_t *softc) +{ + uint8_t cfidata[FLASH_MAX_CFIDATA]; + unsigned int cmdset; + unsigned int devif; + int bus16 = 0; + int dev16 = 0; + int idx; + int found = 0; + int regcnt; + int nblks; + int blksiz; + int insane = 0; + uint8_t insaner = 0; + + if (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) { + bus16 = 1; + } + + /* + * Do a CFI query (16-bit) + */ + + idx = FEOP_CFIQUERY8; + if (softc->fd_probe.flash_flags & FLASH_FLG_DEV16) { + idx = (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ? + FEOP_CFIQUERY16 : FEOP_CFIQUERY16B; + } + + flash_op_begin(softc); + flash_op_add(softc,softc->fd_probe.flash_phys, + idx,(long)cfidata,0,FLASH_MAX_CFIDATA); + flash_op_execute(softc); + + /* + * Look for signature. + */ + + + if ((GETCFIBYTE(cfidata,FLASH_CFI_SIGNATURE+0) == 'Q') && + (GETCFIBYTE(cfidata,FLASH_CFI_SIGNATURE+1) == 'R') && + (GETCFIBYTE(cfidata,FLASH_CFI_SIGNATURE+2) == 'Y')) { + found = 1; + } + + + /* + * No CFI, bail. First, set the command set to an invalid + * value so that we'll use default routines to read but not do programming + */ + + if (!found) { + flash_set_cmdset(softc,-1,bus16,dev16); + return CFE_ERR_UNSUPPORTED; + } + + softc->fd_probe.flash_type = FLASH_TYPE_FLASH; + + /* + * Gather info from flash + */ + + cmdset = ((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_COMMAND_SET))) + + (((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_COMMAND_SET+1))) << 8); + + + devif = ((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_DEVICE_INTERFACE))) + + (((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_DEVICE_INTERFACE+1))) << 8); + + + softc->fd_probe.flash_size = (1 << (unsigned int)(GETCFIBYTE(cfidata,FLASH_CFI_DEVICE_SIZE))); + + /* + * It's a 16-bit device if it is either always 16 bits or can be. + * we'll use "bus16" to decide if the BYTE# pin was strapped + */ + + dev16 = 0; + if ((devif == FLASH_CFI_DEVIF_X16) || (devif == FLASH_CFI_DEVIF_X8X16)) dev16 = 1; + + regcnt = GETCFIBYTE(cfidata,FLASH_CFI_REGION_COUNT); + + softc->fd_probe.flash_nsectors = regcnt; + +#if 1 + /* + * Hiss! Some AMD top-boot flash parts have broken CFI tables - they are backwards! + * Do some extra probing to find it. + */ + + if (cmdset == FLASH_CFI_CMDSET_AMD_STD) { + idx = FEOP_AMD_DEVCODE8; + if (softc->fd_probe.flash_flags & FLASH_FLG_DEV16) { + idx = (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ? + FEOP_AMD_DEVCODE16 : FEOP_AMD_DEVCODE16B; + } + + flash_op_begin(softc); + flash_op_add(softc,softc->fd_probe.flash_phys, + idx,(long)&insaner,0,0); + flash_op_execute(softc); +#ifdef _NEWFLASH_DEBUG_ + xprintf("Insaner = 0x%x\n", insaner); +#endif /* _NEWFLASH_DEBUG_ */ + if(((insaner & 0xFF) == 0xC4)||((insaner & 0xFF) == 0xF6)){ + insane = 1; +#ifdef _NEWFLASH_DEBUG_ + xprintf("Warning: insane AMD part, backwards CFI table!\n"); +#endif /* _NEWFLASH_DEBUG_ */ + } + } +#else + insane = insaner = 1; +#endif /* 0 */ + + + for (idx = 0; idx < regcnt; idx++) { + nblks = ((int)GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+0+idx*4) + + (int)(GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+1+idx*4)<<8)) + 1; + blksiz = ((int)GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+2+idx*4) + + (int)(GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+3+idx*4)<<8)) * 256; + + if (insane) { + /* Insane */ + softc->fd_probe.flash_sectors[((regcnt-1)-idx)] = + FLASH_SECTOR_RANGE(nblks,blksiz); + } + else { + /* Sane */ + softc->fd_probe.flash_sectors[idx] = + FLASH_SECTOR_RANGE(nblks,blksiz); + } + } + + /* + * Set the command set we're going to use. + */ + + flash_set_cmdset(softc,cmdset,bus16,dev16); + + return 0; + +} + + + +/* ********************************************************************* + * FLASH_DO_PROBE(softc) + * + * Probe to see if we're ROM or RAM. If ROM, see if we're flash. + * If flash, do CFI query. + * + * Input parameters: + * softc - our structure + * + * Return value: + * FLASH_TYPE_xxx + ********************************************************************* */ +static int flash_do_probe(flashdev_t *softc) +{ + uint8_t test_byte0,test_byte1; + uint8_t save0,save1; + volatile uint8_t *ptr; + + /* + * flash_do_probe is called before we open the device, so we + * need to allocate space for instructions so the flashop + * engine will work. + */ + + softc->fd_inst = KMALLOC(FLASH_MAX_INST*sizeof(flashinstr_t),0); + if (!softc->fd_inst) return FLASH_TYPE_ROM; + + /* + * Attempt to read/write byte zero. If it is changable, + * this is SRAM (or maybe a ROM emulator with the write line hooked up) + */ + + ptr = (volatile uint8_t *) UNCADDR(softc->fd_probe.flash_phys); + save0 = *ptr; /* save old value */ + save1 = *(ptr+1); /* save old value */ + + test_byte0 = (save0 != 0x88) ? 0x88 : 0x89; + test_byte1 = (save1 != 0x99) ? 0x99 : 0x91; + + *(ptr) = test_byte0; + *(ptr+1) = test_byte1; + + if ((*ptr == test_byte0) && (*(ptr+1) == test_byte1)) { + softc->fd_probe.flash_type = FLASH_TYPE_SRAM; + + /*Only write back saved values if it's RAM*/ + *(ptr) = save0; + *(ptr+1) = save1; + +#ifdef _NEWFLASH_DEBUG_ + xprintf("Flash type SRAM\n"); +#endif + + } + else { + softc->fd_probe.flash_type = FLASH_TYPE_ROM; + +#ifdef _NEWFLASH_DEBUG_ + xprintf("Flash type ROM\n"); +#endif + + } + + /* + * If we thought it was ROM, try doing a CFI query + * to see if it was flash. This check is kind of kludgey + * but should work. + */ + + if (softc->fd_probe.flash_type == FLASH_TYPE_ROM) { + flash_cfi_probe(softc); + } + + + KFREE(softc->fd_inst); + softc->fd_inst = NULL; + + return softc->fd_probe.flash_type; +} + +#endif /* (FLASH_DRIVERS & FLASH_DRIVER_CFI) */ + + +/* ********************************************************************* + * flash_do_parts(probe,parts) + * + * Partition the flash into the sizes specified. We use + * the sizes in the table to generate a table of {offset,size} + * pairs that eventually become partitions. + * + * The only thing magical about this is that size "0" means + * "fill to max" and that partitions beyond the "0" are aligned + * to the top of the flash. Therefore, if you had a 4MB + * flash and listed four partitions, 512K, 0, 512K, 512K, + * then there would be a 2.5M partition in the middle and two + * 512K partitions at the top. + * + * Input parameters: + * probe - flash probe data (user-supplied table) + * parts - our partition table (output) + * + * Return value: + * nothing + ********************************************************************* */ + +static void flash_do_parts(flashdev_t *softc) +{ + int idx; + int middlepart = -1; + int lobound = 0; + newflash_probe_t *probe = &(softc->fd_probe); + flashpart_t *parts = &(softc->fd_parts[0]); + int hibound = probe->flash_size*probe->flash_nchips; + + for (idx = 0; idx < probe->flash_nparts; idx++) { + if (probe->flash_parts[idx].fp_size == 0) { + middlepart = idx; + break; + } + parts[idx].fp_offset = lobound; + parts[idx].fp_size = probe->flash_parts[idx].fp_size; + lobound += probe->flash_parts[idx].fp_size; + } + + if (idx != probe->flash_nparts) { + for (idx = probe->flash_nparts - 1; idx > middlepart; + idx--) { + parts[idx].fp_size = probe->flash_parts[idx].fp_size; + hibound -= probe->flash_parts[idx].fp_size; + parts[idx].fp_offset = hibound; + } + } + + if (middlepart != -1) { + parts[middlepart].fp_offset = lobound; + parts[middlepart].fp_size = hibound - lobound; + } + +#ifdef _NEWFLASH_DEBUG_ + printf("Partition information:\n"); + for (idx = 0; idx < probe->flash_nparts;idx++) { + printf("#%02d %08X -> %08X (%d)\n",idx, + parts[idx].fp_offset,parts[idx].fp_offset+parts[idx].fp_size-1, + parts[idx].fp_size); + } +#endif +} + + +/* ********************************************************************* + * flashdrv_allocbuf(dev) + * + * Allocate sector buffer for flash programming. Use a global + * buffer for all devices. + * + * Input parameters: + * dev - our device + * + * Return value: + * nothing + ********************************************************************* */ +static void flashdrv_allocbuf(flashdev_t *softc) +{ + if (!flash_sector_buffer) { +#if CFG_FLASH_ALLOC_SECTOR_BUFFER + flash_sector_buffer = KMALLOC(CFG_FLASH_SECTOR_BUFFER_SIZE,0); + if (!flash_sector_buffer) { + printf("FLASH: Could not allocate sector buffer, using default\n"); + flash_sector_buffer = (uint8_t *) KERNADDR(CFG_FLASH_SECTOR_BUFFER_SIZE); + } +#else + flash_sector_buffer = (uint8_t *) KERNADDR(CFG_FLASH_SECTOR_BUFFER_ADDR); +#endif + } + + softc->fd_sectorbuffer = flash_sector_buffer; +} + +/* ********************************************************************* + * flashdrv_probe(drv,probe_a,probe_b,probe_ptr) + * + * Device probe routine. Attach the flash device to + * CFE's device table. + * + * Input parameters: + * drv - driver descriptor + * probe_a - physical address of flash + * probe_b - size of flash (bytes) + * probe_ptr - unused + * + * Return value: + * nothing + ********************************************************************* */ + +static void flashdrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + flashdev_t *softc; + newflash_probe_t *probe; + int idx; + char descr[80]; + static int flashidx = 0; + char *x; + + /* + * First thing to do is configure the flashop engine + * if not already done. Basically we copy a bit of + * position-independent code into the DRAM. + */ + + flash_setup_engine(); + + /* + * Now, on with the probing. + */ + + probe = (newflash_probe_t *) probe_ptr; + + /* + * probe_a is the flash base address + * probe_b is the size of the flash + * probe_ptr is unused. + */ + + softc = (flashdev_t *) KMALLOC(sizeof(flashdev_t),0); + if (softc) { + memset(softc,0,sizeof(flashdev_t)); + + flashdrv_allocbuf(softc); + + if (probe) { + /* + * Passed probe structure, do fancy stuff + */ + memcpy(&(softc->fd_probe),probe,sizeof(newflash_probe_t)); + if (softc->fd_probe.flash_nchips == 0) { + softc->fd_probe.flash_nchips = 1; + } + } + else { + /* Didn't pass probe structure, do the compatible thing */ + softc->fd_probe.flash_phys = probe_a; + softc->fd_probe.flash_size = (probe_b & FLASH_SIZE_MASK); + softc->fd_probe.flash_flags = (probe_b & FLASH_FLG_MASK); + softc->fd_probe.flash_nchips = 1; + } + + if (softc->fd_probe.flash_flags & FLASH_FLG_MANUAL) { + /* Manual probing, just set the command set. */ + flash_set_cmdset(softc,softc->fd_probe.flash_cmdset, + ((softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ? 1 : 0), + ((softc->fd_probe.flash_flags & FLASH_FLG_DEV16) ? 1 : 0)); + } + else { + /* Do automatic probing */ +#if (FLASH_DRIVERS & FLASH_DRIVER_CFI) + flash_do_probe(softc); +#else + return; /* No automatic probing, bail! */ +#endif + } + + /* Remember total size of all devices */ + softc->fd_ttlsize = softc->fd_probe.flash_nchips * softc->fd_probe.flash_size; + + /* Set description */ + x = descr; + x += xsprintf(x,"%s at %08X size %uKB",drv->drv_description, + softc->fd_probe.flash_phys, + softc->fd_ttlsize/1024); + if (softc->fd_probe.flash_nchips > 1) { + xsprintf(x," (%d chips)",softc->fd_probe.flash_nchips); + } + + /* + * If flash is not partitioned, just instantiate one + * device. Otherwise, instantiate multiple flashes + * to cover the entire device. + */ + + if (softc->fd_probe.flash_nparts == 0) { + softc->fd_parts[0].fp_dev = softc; + softc->fd_parts[0].fp_offset = 0; + softc->fd_parts[0].fp_size = softc->fd_probe.flash_size; + cfe_attach(drv,&(softc->fd_parts[0]),NULL,descr); + } + else { + /* + * Partition flash into chunks + */ + flash_do_parts(softc); + + /* + * Instantiate devices for each piece + */ + + for (idx = 0; idx < softc->fd_probe.flash_nparts; idx++) { + char name[32]; + char *nptr; + + xsprintf(descr,"%s at %08X offset %08X size %uKB", + drv->drv_description, + softc->fd_probe.flash_phys, + softc->fd_parts[idx].fp_offset, + (softc->fd_parts[idx].fp_size+1023)/1024); + + softc->fd_parts[idx].fp_dev = softc; + if (softc->fd_probe.flash_parts[idx].fp_name == NULL) { + sprintf(name,"%d",idx); + nptr = name; + } + else { + nptr = softc->fd_probe.flash_parts[idx].fp_name; + } + cfe_attach_idx(drv, + flashidx, + &(softc->fd_parts[idx]), + nptr, + descr); + } + } + + flashidx++; + + /* Count total sectors on the device */ + + softc->fd_ttlsect = 0; + for (idx = 0; idx < softc->fd_probe.flash_nsectors; idx++) { + softc->fd_ttlsect += FLASH_SECTOR_NBLKS(softc->fd_probe.flash_sectors[idx]); + } + + } + +} + + +/* ********************************************************************* + * flashdrv_open(ctx) + * + * Called when the flash device is opened. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 if ok else error code + ********************************************************************* */ + +static int flashdrv_open(cfe_devctx_t *ctx) +{ + flashpart_t *part = ctx->dev_softc; + flashdev_t *softc = part->fp_dev; + int ttlsect = softc->fd_ttlsect; + + /* + * Calculate number of flashop instructions we'll need at most. + * This will be two for each sector plus two more for the first + * and last sectors, plus two extra + */ + + ttlsect = (ttlsect * 2 * softc->fd_probe.flash_nchips) + 6; + + /* + * Allocate memory for instructions. + */ + +#ifdef _NEWFLASH_DEBUG_ + printf("%s: allocating %d instructions\n",cfe_device_name(ctx),ttlsect); +#endif + + softc->fd_inst = KMALLOC(ttlsect*sizeof(flashinstr_t),0); + if (!softc->fd_inst) return CFE_ERR_NOMEM; + + return 0; +} + + +/* ********************************************************************* + * flashdrv_read(ctx,buffer) + * + * Read data from the flash device. The flash device is + * considered to be like a disk (you need to specify the offset). + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + flashpart_t *part = ctx->dev_softc; + flashdev_t *softc = part->fp_dev; + int blen; + int offset; + + blen = buffer->buf_length; + offset = (long)buffer->buf_offset; + + if ((offset + blen) > part->fp_size) { + blen = part->fp_size - offset; + } + + offset += part->fp_offset; + + if (blen > 0) { + flash_op_begin(softc); + flash_op_add(softc,softc->fd_probe.flash_phys, + softc->fd_readfunc,(long)buffer->buf_ptr,offset,blen); + flash_op_execute(softc); + } + + buffer->buf_retlen = blen; + + return 0; +} + +/* ********************************************************************* + * flashdrv_inpstat(ctx,inpstat) + * + * Return "input status". For flash devices, we always return true. + * + * Input parameters: + * ctx - device context + * inpstat - input status structure + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + inpstat->inp_status = 1; + return 0; +} + + +/* ********************************************************************* + * flashdrv_write(ctx,buffer) + * + * Write data to the flash device. The flash device is + * considered to be like a disk (you need to specify the offset). + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int flashdrv_write2(cfe_devctx_t *ctx,iocb_buffer_t *buffer,int reboot) +{ + flashpart_t *part = ctx->dev_softc; + flashdev_t *softc = part->fp_dev; + int blen; + int res; + int offset; + int whichchip; + long chipbase; + flash_range_t outrange; + flash_range_t inrange; + flash_sector_t sector; + + blen = buffer->buf_length; + offset = (long)buffer->buf_offset; + + /* Compute range within physical flash */ + + if ((offset + blen) > part->fp_size) { + blen = part->fp_size - offset; + } + + offset += part->fp_offset; + + /* Handle case of writing nothing */ + + if (blen == 0) { + buffer->buf_retlen = blen; + return (buffer->buf_length == blen) ? 0 : CFE_ERR_IOERR; + } + + /* now, offset/blen forms the range we want to write to. */ + + inrange.range_base = offset; + inrange.range_length = blen; + + sector.flash_sector_idx = 0; + + flash_op_begin(softc); + + for (;;) { + res = flash_sector_query(softc,§or); + if (res != 0) break; + if (sector.flash_sector_status == FLASH_SECTOR_INVALID) { + break; + } + + whichchip = sector.flash_sector_idx / softc->fd_ttlsect; + chipbase = softc->fd_probe.flash_phys + + (long) (whichchip * softc->fd_probe.flash_size); + + res = flash_range_intersection(§or,&inrange,&outrange); + + switch (res) { + case 1: /* Erease/program entire sector */ + flash_op_add(softc,chipbase, + softc->fd_erasefunc, + sector.flash_sector_offset, + 0,0); + flash_op_add(softc,chipbase, + softc->fd_pgmfunc, + outrange.range_base, + ((long)buffer->buf_ptr)+(outrange.range_base-inrange.range_base), + outrange.range_length); + break; + + case 0: /* Erase/reprogram partial sector */ + /* Save old sector */ + flash_op_add(softc,chipbase, + softc->fd_readfunc, + (long)(softc->fd_sectorbuffer), + sector.flash_sector_offset, + sector.flash_sector_size); + /* Copy in new stuff */ + flash_op_add(softc,chipbase, + FEOP_MEMCPY, + ((long)(softc->fd_sectorbuffer))+(outrange.range_base-sector.flash_sector_offset), + ((long)buffer->buf_ptr)+(outrange.range_base-inrange.range_base), + outrange.range_length); + /* Erase sector */ + flash_op_add(softc,chipbase, + softc->fd_erasefunc, + sector.flash_sector_offset, + 0,0); + /* Program sector */ + flash_op_add(softc,chipbase, + softc->fd_pgmfunc, + sector.flash_sector_offset, + (long)(softc->fd_sectorbuffer), + sector.flash_sector_size); + break; + + case -1: /* No intersection */ + break; + } + + sector.flash_sector_idx++; + + } + + if (reboot) { + flash_op_add(softc,softc->fd_probe.flash_phys,FEOP_REBOOT,0,0,0); + } + + res = flash_op_execute(softc); + + buffer->buf_retlen = blen; + + return (res == 0) ? 0 : CFE_ERR_IOERR; +} + +static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + return flashdrv_write2(ctx,buffer,0); +} + + +/* ********************************************************************* + * flashdrv_ioctl(ctx,buffer) + * + * Handle special IOCTL functions for the flash. Flash devices + * support NVRAM information, sector and chip erase, and a + * special IOCTL for updating the running copy of CFE. + * + * Input parameters: + * ctx - device context + * buffer - descriptor for IOCTL parameters + * + * Return value: + * 0 if ok else error + ********************************************************************* */ +static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + flashpart_t *part = ctx->dev_softc; + flashdev_t *softc = part->fp_dev; + nvram_info_t *nvinfo; + flash_info_t *info; + flash_range_t range; + int offset; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_NVRAM_GETINFO: + /* + * We only support NVRAM on flashes that have been partitioned + * into at least two partitions. Every partition supports + * being an NVRAM in that case, but we'll only attach one + * of them to the environment subsystem. + */ + if (softc->fd_probe.flash_nparts <= 1) { + return CFE_ERR_UNSUPPORTED; + } + nvinfo = (nvram_info_t *) buffer->buf_ptr; + if (buffer->buf_length != sizeof(nvram_info_t)) return CFE_ERR_INV_PARAM; + + nvinfo->nvram_offset = 0; + nvinfo->nvram_size = part->fp_size; + nvinfo->nvram_eraseflg = 1; + buffer->buf_retlen = sizeof(nvram_info_t); + return 0; + break; + + case IOCTL_FLASH_ERASE_SECTOR: + offset = (int) buffer->buf_offset; + offset += part->fp_offset; + if (offset >= softc->fd_probe.flash_size) return -1; + + flash_op_begin(softc); + flash_op_add(softc, + softc->fd_probe.flash_phys, + softc->fd_erasefunc, + offset, + 0,0); + flash_op_execute(softc); + return 0; + + case IOCTL_FLASH_ERASE_ALL: + offset = (int) buffer->buf_offset; + if (offset != 0) return -1; + flash_erase_all(softc); + return 0; + + case IOCTL_FLASH_WRITE_ALL: + /* Write file and reboot */ + flashdrv_write2(ctx,buffer,1); + return -1; /* should not return */ + + case IOCTL_FLASH_GETINFO: + info = (flash_info_t *) buffer->buf_ptr; + info->flash_base = softc->fd_probe.flash_phys; + info->flash_size = softc->fd_probe.flash_size; + info->flash_type = softc->fd_probe.flash_type; + info->flash_flags = FLASH_FLAG_NOERASE; + return 0; + + case IOCTL_FLASH_GETSECTORS: + return flash_sector_query(softc,(flash_sector_t *) buffer->buf_ptr); + + case IOCTL_FLASH_ERASE_RANGE: + memcpy(&range,buffer->buf_ptr,sizeof(flash_range_t)); + range.range_base += part->fp_offset; + if (range.range_length > part->fp_size) { + range.range_length = part->fp_size; + } + return flash_erase_range(softc,&range); + + default: + /* Call hook if present. */ + if (softc->fd_probe.flash_ioctl_hook) { + return (*(softc->fd_probe.flash_ioctl_hook))(ctx,buffer); + } + return -1; + } + + return -1; +} + + +/* ********************************************************************* + * flashdrv_close(ctx) + * + * Close the flash device. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 + ********************************************************************* */ +static int flashdrv_close(cfe_devctx_t *ctx) +{ + flashpart_t *part = ctx->dev_softc; + flashdev_t *softc = part->fp_dev; + + if (softc->fd_inst) { + KFREE(softc->fd_inst); + } + + softc->fd_inst = NULL; + + /* XXX Invalidate the cache ?!?! */ + + return 0; +} + + diff --git a/cfe/cfe/dev/dev_ns16550.c b/cfe/cfe/dev/dev_ns16550.c new file mode 100644 index 0000000..a70eecf --- /dev/null +++ b/cfe/cfe/dev/dev_ns16550.c @@ -0,0 +1,255 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NS16550 UART driver File: dev_ns16550.c + * + * This is a console device driver for an NS16550 UART, either + * on-board or as a PCI-device. In the case of a PCI device, + * our probe routine is called from the PCI probe code + * over in dev_ns16550_pci.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" + +#include "lib_physio.h" + +#include "bsp_config.h" + +#include "ns16550.h" + +#define WRITECSR(p,v) phys_write8((p),(v)) +#define READCSR(p) phys_read8((p)) + +static int ns16550_uart_open(cfe_devctx_t *ctx); +static int ns16550_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int ns16550_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int ns16550_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int ns16550_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int ns16550_uart_close(cfe_devctx_t *ctx); + +void ns16550_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +const cfe_devdisp_t ns16550_uart_dispatch = { + ns16550_uart_open, + ns16550_uart_read, + ns16550_uart_inpstat, + ns16550_uart_write, + ns16550_uart_ioctl, + ns16550_uart_close, + NULL, + NULL +}; + +const cfe_driver_t ns16550_uart = { + "NS16550 UART", + "uart", + CFE_DEV_SERIAL, + &ns16550_uart_dispatch, + ns16550_uart_probe +}; + +typedef struct ns16550_uart_s { + physaddr_t uart_base; + int uart_flowcontrol; + int uart_speed; +} ns16550_uart_t; + + +/* + * NS16550-compatible UART. + * probe_a: physical address of UART + */ + +void ns16550_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + ns16550_uart_t *softc; + char descr[80]; + + softc = (ns16550_uart_t *) KMALLOC(sizeof(ns16550_uart_t),0); + if (softc) { + softc->uart_base = probe_a; + softc->uart_speed = CFG_SERIAL_BAUD_RATE; + softc->uart_flowcontrol = SERIAL_FLOW_NONE; + xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)probe_a); + + cfe_attach(drv, softc, NULL, descr); + } +} + +#define DELAY(n) delay(n) +extern int32_t _getticks(void); +static void delay(int ticks) +{ + int32_t t; + + t = _getticks() + ticks; + while (_getticks() < t) + ; /* NULL LOOP */ +} + +static void ns16550_uart_setflow(ns16550_uart_t *softc) +{ + /* noop for now */ +} + + +static int ns16550_uart_open(cfe_devctx_t *ctx) +{ + ns16550_uart_t *softc = ctx->dev_softc; + int baudrate = CFG_SERIAL_BAUD_RATE; + unsigned int brtc; + + brtc = BRTC(baudrate); + + WRITECSR(softc->uart_base+R_UART_CFCR,CFCR_DLAB); + WRITECSR(softc->uart_base+R_UART_DATA,brtc & 0xFF); + WRITECSR(softc->uart_base+R_UART_IER,brtc>>8); + WRITECSR(softc->uart_base+R_UART_CFCR,CFCR_8BITS); + WRITECSR(softc->uart_base+R_UART_MCR,MCR_DTR | MCR_RTS | MCR_IENABLE); + WRITECSR(softc->uart_base+R_UART_IER,0); + + WRITECSR(softc->uart_base+R_UART_FIFO,FIFO_ENABLE); + DELAY(100); + WRITECSR(softc->uart_base+R_UART_FIFO, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1); + DELAY(100); + + if ((READCSR(softc->uart_base+R_UART_IIR) & IIR_FIFO_MASK) != IIR_FIFO_MASK) { + WRITECSR(softc->uart_base+R_UART_FIFO,0); + } + ns16550_uart_setflow(softc); + + return 0; +} + +static int ns16550_uart_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + ns16550_uart_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + while ((blen > 0) && (READCSR(softc->uart_base+R_UART_LSR) & LSR_RXRDY)) { + *bptr++ = (READCSR(softc->uart_base+R_UART_DATA) & 0xFF); + blen--; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + +static int ns16550_uart_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + ns16550_uart_t *softc = ctx->dev_softc; + + inpstat->inp_status = (READCSR(softc->uart_base+R_UART_LSR) & LSR_RXRDY) ? 1 : 0; + + return 0; +} + +static int ns16550_uart_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + ns16550_uart_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + while ((blen > 0) && (READCSR(softc->uart_base+R_UART_LSR) & LSR_TXRDY)) { + WRITECSR(softc->uart_base+R_UART_DATA, *bptr++); + blen--; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + +static int ns16550_uart_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + ns16550_uart_t *softc = ctx->dev_softc; + + unsigned int *info = (unsigned int *) buffer->buf_ptr; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_SERIAL_GETSPEED: + *info = softc->uart_speed; + break; + case IOCTL_SERIAL_SETSPEED: + softc->uart_speed = *info; + /* NYI */ + break; + case IOCTL_SERIAL_GETFLOW: + *info = softc->uart_flowcontrol; + break; + case IOCTL_SERIAL_SETFLOW: + softc->uart_flowcontrol = *info; + ns16550_uart_setflow(softc); + break; + default: + return -1; + } + + return 0; +} + +static int ns16550_uart_close(cfe_devctx_t *ctx) +{ + ns16550_uart_t *softc = ctx->dev_softc; + + WRITECSR(softc->uart_base+R_UART_MCR,0); + + return 0; +} + + diff --git a/cfe/cfe/dev/dev_ns16550_pci.c b/cfe/cfe/dev/dev_ns16550_pci.c new file mode 100644 index 0000000..021f34c --- /dev/null +++ b/cfe/cfe/dev/dev_ns16550_pci.c @@ -0,0 +1,114 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NS16550 UART driver (PCI) File: dev_ns16550_pci.c + * + * This is a console device driver for a PCI NS16550 UART + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" + +#include "pcivar.h" +#include "pcireg.h" + + +/* Probe routine for real UART driver */ +extern void ns16550_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +/* Probe routine for this UART driver. */ +static void ns16550pci_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +/* We just glom onto the dispatch table in the real driver */ +extern const cfe_devdisp_t ns16550_uart_dispatch; + +const cfe_driver_t ns16550pci_uart = { + "PCI NS16550 UART", + "uart", + CFE_DEV_SERIAL, + &ns16550_uart_dispatch, + ns16550pci_uart_probe +}; + + +static void ns16550pci_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + phys_addr_t pa; + pcitag_t tag; + int index = 0; + + /* + * NS16550-compatible UART on the PCI bus + * probe_a, probe_b and probe_ptr are unused. + */ + + /* + * This is for a SIIG card. Should probably do a little + * vendor ID table like we did for the IDE driver so + * we can spport other cards. + */ + + for (;;) { + + if (pci_find_device(0x131f,0x2000,index,&tag) != 0) { + break; + } + + pci_map_io(tag, PCI_MAPREG(0), PCI_MATCH_BYTES, &pa); + xprintf("NS16550PCI: I/O mapped registers start at %08X", (uint32_t)pa); + + ns16550_uart_probe(drv,pa,0,NULL); + + index++; + } +} + diff --git a/cfe/cfe/dev/dev_null.c b/cfe/cfe/dev/dev_null.c new file mode 100644 index 0000000..d995919 --- /dev/null +++ b/cfe/cfe/dev/dev_null.c @@ -0,0 +1,142 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Null console device File: dev_null.c + * + * This is a null console device, useful for console-less + * operation, or when using chip simulators. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" + +static void nulldrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +static int nulldrv_open(cfe_devctx_t *ctx); +static int nulldrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int nulldrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int nulldrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int nulldrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int nulldrv_close(cfe_devctx_t *ctx); + +const static cfe_devdisp_t nulldrv_dispatch = { + nulldrv_open, + nulldrv_read, + nulldrv_inpstat, + nulldrv_write, + nulldrv_ioctl, + nulldrv_close, + NULL, + NULL +}; + +const cfe_driver_t nulldrv = { + "Null console device", + "null", + CFE_DEV_SERIAL, + &nulldrv_dispatch, + nulldrv_probe +}; + + +static void nulldrv_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + cfe_attach(drv,NULL,NULL,drv->drv_description); +} + + +static int nulldrv_open(cfe_devctx_t *ctx) +{ +/* nulldrv_t *softc = ctx->dev_softc; */ + + return 0; +} + +static int nulldrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ +/* nulldrv_t *softc = ctx->dev_softc; */ + + buffer->buf_retlen = buffer->buf_length; + return 0; +} + +static int nulldrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ +/* nulldrv_t *softc = ctx->dev_softc; */ + + inpstat->inp_status = 0; + + return 0; +} + +static int nulldrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ +/* nulldrv_t *softc = ctx->dev_softc; */ + + buffer->buf_retlen = buffer->buf_length; + return 0; +} + +static int nulldrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ +/* nulldrv_t *softc = ctx->dev_softc;*/ + + return -1; +} + +static int nulldrv_close(cfe_devctx_t *ctx) +{ +/* nulldrv_t *softc = ctx->dev_softc; */ + + return 0; +} + + diff --git a/cfe/cfe/dev/dev_promice.c b/cfe/cfe/dev/dev_promice.c new file mode 100644 index 0000000..fe79086 --- /dev/null +++ b/cfe/cfe/dev/dev_promice.c @@ -0,0 +1,402 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PromICE console device File: dev_promice.c + * + * This device driver supports Grammar Engine's PromICE AI2 + * serial communications options. With this console, you can + * communicate with the firmware using only uncached reads in the + * boot ROM space. See Grammar Engine's PromICE manuals + * for more information at http://www.gei.com + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* + * Example PromICE initialization file: + * + * ----------------------- + * output=com1 + * pponly=lpt1 + * rom=27040 + * word=8 + * file=cfe.srec + * ailoc 7FC00,9600 + * ----------------------- + * + * The offset specified in the 'ailoc' line must be the location where you + * will configure the AI2 serial port. In this example, the ROM is assumed + * to be 512KB, and the AI2 serial port is at 511KB, or offset 0x7FC00. + * This area is filled with 0xCC to detect AI2's initialization sequence + * properly (see the PromICE manual). You should connect your + * PromICE's serial port up to the PC and run a terminal emulator on it. + * The parallel port will be used for downloading data to the PromICE. + * + * If you have connected the write line to the PromICE, then you can + * define the _AIDIRT_ symbol to increase performance. + */ + + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "addrspace.h" + +#define _AIDIRT_ + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static void promice_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +static int promice_open(cfe_devctx_t *ctx); +static int promice_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int promice_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int promice_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int promice_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int promice_close(cfe_devctx_t *ctx); + +/* ********************************************************************* + * Device dispatch table + ********************************************************************* */ + +const static cfe_devdisp_t promice_dispatch = { + promice_open, + promice_read, + promice_inpstat, + promice_write, + promice_ioctl, + promice_close, + NULL, + NULL +}; + +/* ********************************************************************* + * Device descriptor + ********************************************************************* */ + +const cfe_driver_t promice_uart = { + "PromICE AI2 Serial Port", + "promice", + CFE_DEV_SERIAL, + &promice_dispatch, + promice_probe +}; + +/* ********************************************************************* + * Local constants and structures + ********************************************************************* */ + +/* + * If your PromICE is connected to a 32-bit host (emulating four + * flash ROMs) and the SB1250 is set to boot from that host, define + * the PROMICE_32BITS symbol to make sure the AI2 interface is + * configured correctly. + */ + +/*#define PROMICE_32BITS*/ + +#ifdef PROMICE_32BITS +#define WORDSIZE 4 +#define WORDTYPE uint32_t +#else +#define WORDSIZE 1 +#define WORDTYPE uint8_t +#endif + + +#define ZERO_OFFSET (0) +#define ONE_OFFSET (1) +#define DATA_OFFSET (2) +#define STATUS_OFFSET (3) + +#define TDA 0x01 /* Target data available */ +#define HDA 0x02 /* Host data available */ +#define OVR 0x04 /* Host data overflow */ + +typedef struct promice_s { + unsigned long ai2_addr; + unsigned int ai2_wordsize; + volatile WORDTYPE *zero; + volatile WORDTYPE *one; + volatile WORDTYPE *data; + volatile WORDTYPE *status; +} promice_t; + + +/* ********************************************************************* + * promice_probe(drv,probe_a,probe_b,probe_ptr) + * + * Device "Probe" routine. This routine creates the soft + * context for the device and calls the attach routine. + * + * Input parameters: + * drv - driver structure + * probe_a,probe_b,probe_ptr - probe args + * + * Return value: + * nothing + ********************************************************************* */ + + +static void promice_probe(cfe_driver_t *drv, + unsigned long probe_a, + unsigned long probe_b, + void *probe_ptr) +{ + promice_t *softc; + char descr[80]; + + /* + * probe_a is the address in the ROM of the AI2 interface + * on the PromICE. + * probe_b is the word size (1,2,4) + */ + + softc = (promice_t *) KMALLOC(sizeof(promice_t),0); + if (softc) { + softc->ai2_addr = probe_a; + if (probe_b) softc->ai2_wordsize = probe_b; + else softc->ai2_wordsize = WORDSIZE; + xsprintf(descr,"%s at 0x%X",drv->drv_description,probe_a); + cfe_attach(drv,softc,NULL,descr); + } +} + + + +/* ********************************************************************* + * promice_open(ctx) + * + * Open the device + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +static int promice_open(cfe_devctx_t *ctx) +{ + promice_t *softc = ctx->dev_softc; + uint8_t dummy; + + softc->zero = (volatile WORDTYPE *) + UNCADDR(softc->ai2_addr + (ZERO_OFFSET*softc->ai2_wordsize)); + softc->one = (volatile WORDTYPE *) + UNCADDR(softc->ai2_addr + (ONE_OFFSET*softc->ai2_wordsize)); + softc->data = (volatile WORDTYPE *) + UNCADDR(softc->ai2_addr + (DATA_OFFSET*softc->ai2_wordsize)); + softc->status = (volatile WORDTYPE *) + UNCADDR(softc->ai2_addr + (STATUS_OFFSET*softc->ai2_wordsize)); + + /* + * Wait for bit 3 to clear so we know the interface is ready. + */ + + while (*(softc->status) == 0xCC) ; /* NULL LOOP */ + + /* + * a dummy read is required to clear out the interface. + */ + + dummy = *(softc->data); + + return 0; +} + +/* ********************************************************************* + * promice_read(ctx,buffer) + * + * Read data from the device + * + * Input parameters: + * ctx - device context + * buffer - I/O buffer descriptor + * + * Return value: + * number of bytes transferred, or <0 if error + ********************************************************************* */ +static int promice_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + promice_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + while ((blen > 0) && (*(softc->status) & HDA)) { + *bptr++ = *(softc->data); + blen--; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + +/* ********************************************************************* + * promice_inpstat(ctx,inpstat) + * + * Determine if read data is available + * + * Input parameters: + * ctx - device context + * inpstat - input status structure + * + * Return value: + * 0 + ********************************************************************* */ + +static int promice_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + promice_t *softc = ctx->dev_softc; + + inpstat->inp_status = (*(softc->status) & HDA) ? 1 : 0; + + return 0; +} + +/* ********************************************************************* + * promice_write(ctx,buffer) + * + * Write data to the device + * + * Input parameters: + * ctx - device context + * buffer - I/O buffer descriptor + * + * Return value: + * number of bytes transferred, or <0 if error + ********************************************************************* */ +static int promice_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + promice_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + uint8_t data; +#ifndef _AIDIRT_ + uint8_t dummy; + int count; +#endif + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + + /* + * The AI2 interface requires you to transmit characters + * one bit at a time. First a '1' start bit, + * then 8 data bits (lsb first) then another '1' stop bit. + * + * Just reference the right memory location to transmit a bit. + */ + + while ((blen > 0) && !(*(softc->status) & TDA)) { + +#ifdef _AIDIRT_ + data = *bptr++; + *(softc->zero) = data; +#else + dummy = *(softc->one); /* send start bit */ + + data = *bptr++; + + for (count = 0; count < 8; count++) { + if (data & 1) dummy = *(softc->one); + else dummy = *(softc->zero); + data >>= 1; /* shift in next bit */ + } + + dummy = *(softc->one); /* send stop bit */ +#endif + + blen--; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + +/* ********************************************************************* + * promice_ioctl(ctx,buffer) + * + * Do I/O control operations + * + * Input parameters: + * ctx - device context + * buffer - I/O control args + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int promice_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + return -1; +} + +/* ********************************************************************* + * promice_close(ctx) + * + * Close the device. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 + ********************************************************************* */ + +static int promice_close(cfe_devctx_t *ctx) +{ + return 0; +} + + diff --git a/cfe/cfe/dev/dev_sp1011.c b/cfe/cfe/dev/dev_sp1011.c new file mode 100644 index 0000000..8e0d16b --- /dev/null +++ b/cfe/cfe/dev/dev_sp1011.c @@ -0,0 +1,151 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * SP1011 (Sturgeon) Support File: dev_sp1011.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" + +#include "pcireg.h" +#include "pcivar.h" + +extern int eoi_implemented; + +void sturgeon_setup (pcitag_t tag, pci_flags_t flags); + + +/* Sturgeon LDT-to-PCI bridge (LPB) specific definitions. */ + +#define PCI_VENDOR_API 0x14d9 +#define PCI_PRODUCT_API_STURGEON 0x0010 + +/* Sturgeon specific registers */ +#define LPB_READ_CTRL_REG 0x60 +#define LPB_READ_CTRL_MASK 0xffffff + +#define LPB_READ_CTRL_PREF_EN (1 << 0) +#define LPB_READ_CTRL_RD_PREF_EN (1 << 1) +#define LPB_READ_CTRL_MULT_PREF_SHIFT 2 +#define LPB_READ_CTRL_MULT_PREF_MASK (7 << LPB_READ_CTRL_MULT_PREF_SHIFT) +#define LPB_READ_CTRL_LINE_PREF_SHIFT 5 +#define LPB_READ_CTRL_LINE_PREF_MASK (7 << LPB_READ_CTRL_LINE_PREF_SHIFT) +#define LPB_READ_CTRL_DEL_REQ_SHIFT 8 +#define LPB_READ_CTRL_DEL_REQ_MASK (3 << LPB_READ_CTRL_DEL_REQ_SHIFT) + +#define LPB_INT_CTRL_BASE 0xa0 + +#define LPB_INT_CTRL_ENABLE (1 << 15) +#define LPB_INT_CTRL_DESTMODE (1 << 14) +#define LPB_INT_CTRL_DEST_SHIFT 6 +#define LPB_INT_CTRL_DEST_MASK (0xff << LPB_INT_CTRL_DEST_SHIFT) +#define LPB_INT_CTRL_MSGTYPE_SHIFT 4 +#define LPB_INT_CTRL_MSGTYPE_MASK (0x3 << LPB_INT_CTRL_MSGTYPE_SHIFT) +#define LPB_INT_CTRL_POLARITY (1 << 3) +#define LPB_INT_CTRL_TRIGGERMODE (1 << 2) +#define LPB_INT_CTRL_VECTOR_SHIFT 0 +#define LPB_INT_CTRL_VECTOR_MASK (0x3 << 0) + +#define LPB_INT_BLOCK1_REG 0xc4 + +void +sturgeon_setup (pcitag_t tag, pci_flags_t flags) +{ + int bus, device, function; + int secondary; + struct pci_bus *pb; + unsigned offset; + pcireg_t t, ctrl, intmap; + + pci_break_tag(tag, &bus, &device, &function); + + secondary = (pci_conf_read(tag, PPB_BUSINFO_REG) >> 8) & 0xff; + pb = &_pci_bus[secondary]; + + /* set up READ CONTROL register for selected prefetch option */ + ctrl = pci_conf_read(tag, LPB_READ_CTRL_REG) & ~LPB_READ_CTRL_MASK; + if ((flags & PCI_FLG_LDT_PREFETCH) != 0) { + /* Prefetch enable: all cycle types, 2 delayed requests, + 4 lines of fetch ahead for MemRdMult */ + ctrl |= (LPB_READ_CTRL_PREF_EN + | LPB_READ_CTRL_RD_PREF_EN + | (3 << LPB_READ_CTRL_MULT_PREF_SHIFT) + | (1 << LPB_READ_CTRL_DEL_REQ_SHIFT)); + } else { + /* No prefetch */ + ctrl |= 0; + } + pci_conf_write(tag, LPB_READ_CTRL_REG, ctrl); + + /* It's apparently not possible for software to distinguish + the CSWARM's debug Sturgeon (which has floating interrupt + inputs), so we route interrupts only if there are secondary + devices. */ + if (pb->ndev > 0) { + /* Setup interrupt mapping for Block 1: + Enabled, Dest=Logical (CPU 0 + CPU 1), Type=Fixed */ + intmap = (LPB_INT_CTRL_ENABLE | + LPB_INT_CTRL_DESTMODE | /* Logical */ + (0x3 << LPB_INT_CTRL_DEST_SHIFT) | /* CPU 0+1 */ + (0x0 << LPB_INT_CTRL_MSGTYPE_SHIFT)); /* Fixed */ + if (eoi_implemented) { + /* Passes >=2 have working EOI. Trigger=Level */ + intmap |= LPB_INT_CTRL_TRIGGERMODE; /* Level */ + } else { + /* Pass 1 lacks working EOI. Trigger=Edge */ + intmap |= 0; /* Edge */ + } + + offset = pb->inta_shift % 4; + t = (intmap + offset); + offset = (offset+1) % 4; + t |= (intmap + offset) << 16; + pci_conf_write(tag, LPB_INT_CTRL_BASE + 8, t); + + offset = (offset+1) % 4; + t = (intmap + offset); + offset = (offset+1) % 4; + t |= (intmap + offset) << 16; + pci_conf_write(tag, LPB_INT_CTRL_BASE + 12, t); + + t = pci_conf_read(tag, LPB_INT_BLOCK1_REG); + t &= 0xffffff00; + t |= (0x40 | (56 >> 2)); + pci_conf_write(tag, LPB_INT_BLOCK1_REG, t); + } +} diff --git a/cfe/cfe/dev/dev_tulip.c b/cfe/cfe/dev/dev_tulip.c new file mode 100644 index 0000000..dec6b56 --- /dev/null +++ b/cfe/cfe/dev/dev_tulip.c @@ -0,0 +1,2985 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * DC21x4x Ethernet Driver File: dev_tulip.c + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" + +#ifndef _SB_MAKE64 +#define _SB_MAKE64(x) ((uint64_t)(x)) +#endif +#ifndef _SB_MAKEMASK1 +#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n)) +#endif + +#include "lib_types.h" +#include "lib_hssubr.h" +#include "lib_malloc.h" +#include "lib_string.h" +#define blockcopy memcpy +#include "lib_printf.h" +#include "lib_queue.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_error.h" +#include "cfe_irq.h" + +#include "pcivar.h" +#include "pcireg.h" + +#include "dc21143.h" +#include "mii.h" + +/* This is a driver for specific configurations of the DC21040, DC21041, + DC21140A and DC21143, not a generic Tulip driver. The prefix + "tulip_" is used to indicate generic Tulip functions, while + "dc21040_", "dc21041_", "dc21140_" or "dc21143_" indicates functions + specific to a chip variant. + + The 21041 driver assumes a 10BT HD interface, since autonegotiation + is known to be broken in the early revisons of that chip. Example + cards come from DEC and SMC. Essentially the same driver is used + for 21040 cards. + + The 21140 driver assumes that the PHY uses a standard MII interface + for both 100BT and 10BT. Example cards come from DEC (National DP83840 + plus Twister PHY) and Netgear (Level One PHY). + + Some early 21140 boards are exceptions and use SYM plus SRL + with different PHY chips for 10 and 100 (limited support). + + The 21143 driver assumes by default that the PHY uses the SYM ("5 + wire") interface for 100BT with pass-through for 10BT. Example + cards come from DEC (MicroLinear ML6694 PHY) and Znyx (QS6611 or + Kendin KS8761 PHY). It also supports an MII interface for + recognized adapters. An example card comes from Adaptec (National + DP83840A and Twister PHY). There is no support for AUI interfaces. + + This SB1250 version takes advantage of DMA coherence and uses + "preserve bit lanes" addresses for all accesses that cross the + ZBbus-PCI bridge. */ + +#ifndef TULIP_DEBUG +#define TULIP_DEBUG 0 +#endif + +#ifndef TULIP_TUNE +#define TULIP_TUNE 1 +#endif + +/* Set IPOLL to drive processing through the pseudo-interrupt + dispatcher. Set XPOLL to drive processing by an external polling + agent. Setting both is ok. */ + +#ifndef IPOLL +#define IPOLL 0 +#endif +#ifndef XPOLL +#define XPOLL 1 +#endif + +#define ENET_ADDR_LEN 6 /* size of an ethernet address */ +#define MAX_ETHER_PACK 1518 /* max size of a packet */ +#define CRC_SIZE 4 /* size of CRC field */ + +/* Packet buffers. For tulip, the packet must be aligned to a 32-bit + word boundary, and we would like it aligned to a cache line + boundary for performance. */ + +#define CACHE_ALIGN 32 + +#if __long64 +typedef struct eth_pkt_s { + queue_t next; /* 16 */ + uint8_t *buffer; /* 8 */ + uint32_t flags; /* 4 */ + int32_t length; /* 4 */ + uint8_t data[MAX_ETHER_PACK]; +} eth_pkt_t; +#else +typedef struct eth_pkt_s { + queue_t next; /* 8 */ + uint8_t *buffer; /* 4 */ + uint32_t flags; /* 4 */ + int32_t length; /* 4 */ + uint32_t unused[3]; /* 12 */ + uint8_t data[MAX_ETHER_PACK]; +} eth_pkt_t; +#endif + +#define ETH_PKTBUF_LINES ((sizeof(eth_pkt_t) + (CACHE_ALIGN-1))/CACHE_ALIGN) +#define ETH_PKTBUF_SIZE (ETH_PKTBUF_LINES*CACHE_ALIGN) +#define ETH_PKTBUF_OFFSET (offsetof(eth_pkt_t, data)) + +#define ETH_PKT_BASE(data) ((eth_pkt_t *)((data) - ETH_PKTBUF_OFFSET)) + +/* packet flags */ +#define ETH_TX_SETUP 1 /* assumes Perfect Filtering format */ + +static void +show_packet(char c, eth_pkt_t *pkt) +{ + int i; + int n = (pkt->length < 32 ? pkt->length : 32); + + xprintf("%c[%4d]:", c, pkt->length); + for (i = 0; i < n; i++) { + if (i % 4 == 0) + xprintf(" "); + xprintf("%02x", pkt->buffer[i]); + } + xprintf("\n"); +} + + +/* Descriptor structures */ + +typedef struct rx_dscr { + uint32_t rxd_flags; + uint32_t rxd_bufsize; + pci_addr_t rxd_bufaddr1; + pci_addr_t rxd_bufaddr2; +} rx_dscr; + +typedef struct tx_dscr { + uint32_t txd_flags; + uint32_t txd_bufsize; + pci_addr_t txd_bufaddr1; + pci_addr_t txd_bufaddr2; +} tx_dscr; + +/* CAM structure */ + +typedef union { + struct { + uint32_t physical[CAM_PERFECT_ENTRIES][3]; + } p; + struct { + uint32_t hash[32]; + uint32_t mbz[7]; + uint32_t physical[3]; + } h; +} tulip_cam; + + +/* Driver data structures */ + +typedef enum { + eth_state_uninit, + eth_state_setup, + eth_state_off, + eth_state_on, + eth_state_broken +} eth_state_t; + +#define ETH_PKTPOOL_SIZE 32 +#define ETH_PKT_SIZE MAX_ETHER_PACK + +typedef struct tulip_softc { + uint32_t membase; + uint8_t irq; /* interrupt mapping (used if IPOLL) */ + pcitag_t tag; /* tag for configuration registers */ + + uint8_t hwaddr[ENET_ADDR_LEN]; + uint16_t device; /* chip device code */ + uint8_t revision; /* chip revision and step (Table 3-7) */ + + /* current state */ + eth_state_t state; + + /* These fields are the chip startup values. */ +// uint16_t media; /* media type */ + uint32_t opmode; /* operating mode */ + uint32_t intmask; /* interrupt mask */ + uint32_t gpdata; /* output bits for csr15 (21143) */ + + /* These fields are set before calling dc21x4x_hwinit */ + int linkspeed; /* encodings from cfe_ioctl */ + int loopback; + + /* Packet free list */ + queue_t freelist; + uint8_t *pktpool; + queue_t rxqueue; + + /* The descriptor tables */ + uint8_t *rxdscrmem; /* receive descriptors */ + uint8_t *txdscrmem; /* transmit descriptors */ + + /* These fields keep track of where we are in tx/rx processing */ + volatile rx_dscr *rxdscr_start; /* beginning of ring */ + volatile rx_dscr *rxdscr_end; /* end of ring */ + volatile rx_dscr *rxdscr_remove; /* next one we expect tulip to use */ + volatile rx_dscr *rxdscr_add; /* next place to put a buffer */ + int rxdscr_onring; + + volatile tx_dscr *txdscr_start; /* beginning of ring */ + volatile tx_dscr *txdscr_end; /* end of ring */ + volatile tx_dscr *txdscr_remove; /* next one we will use for tx */ + volatile tx_dscr *txdscr_add; /* next place to put a buffer */ + + cfe_devctx_t *devctx; + + /* These fields describe the PHY */ + enum {SRL, MII, SYM} phy_type; + int mii_addr; + + /* Statistics */ + uint32_t inpkts; + uint32_t outpkts; + uint32_t interrupts; + uint32_t rx_interrupts; + uint32_t tx_interrupts; + uint32_t bus_errors; +} tulip_softc; + + +/* Entry to and exit from critical sections (currently relative to + interrupts only, not SMP) */ + +#if CFG_INTERRUPTS +#define CS_ENTER(sc) cfe_disable_irq(sc->irq) +#define CS_EXIT(sc) cfe_enable_irq(sc->irq) +#else +#define CS_ENTER(sc) ((void)0) +#define CS_EXIT(sc) ((void)0) +#endif + + +/* Driver parameterization */ + +#define MAXRXDSCR 32 +#define MAXTXDSCR 32 +#define MINRXRING 8 + +#define MEDIA_UNKNOWN 0 +#define MEDIA_AUI 1 +#define MEDIA_BNC 2 +#define MEDIA_UTP_FULL_DUPLEX 3 +#define MEDIA_UTP_NO_LINK_TEST 4 +#define MEDIA_UTP 5 + +/* Prototypes */ + +static void tulip_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +/* Address mapping macros */ + +/* Note that PTR_TO_PHYS only works with 32-bit addresses, but then + so does the Tulip. */ +#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x))) +#define PHYS_TO_PTR(a) ((uint8_t *)PHYS_TO_K0(a)) + +/* All mappings through the PCI host bridge use match bits mode. */ +#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000) +#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF) + +#define PCI_TO_PTR(a) (PHYS_TO_PTR(PCI_TO_PHYS(a))) +#define PTR_TO_PCI(x) (PHYS_TO_PCI(PTR_TO_PHYS(x))) + +#if __long64 +#define READCSR(sc,csr) \ + (*((volatile uint32_t *) (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr))))) + +#define WRITECSR(sc,csr,val) \ + (*((volatile uint32_t *) \ + (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))) = (val)) + +#else +#define READCSR(sc,csr) \ + (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))) + +#define WRITECSR(sc,csr,val) \ + (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)), (val))) + +#endif + +#define RESET_ADAPTER(sc) \ + { \ + WRITECSR((sc), R_CSR_BUSMODE, M_CSR0_SWRESET); \ + cfe_sleep(CFE_HZ/10); \ + } + + +/* Debugging */ + +static void +dumpstat(tulip_softc *sc) +{ + xprintf("-- CSR 5 = %08X CSR 6 = %08x\n", + READCSR(sc, R_CSR_STATUS), READCSR(sc, R_CSR_OPMODE)); +} + +static void +dumpcsrs(tulip_softc *sc) +{ + int idx; + + xprintf("-------------\n"); + for (idx = 0; idx < 16; idx++) { + xprintf("CSR %2d = %08X\n", idx, READCSR(sc, idx*8)); + } + xprintf("-------------\n"); +} + + +/* Packet management */ + +/* ********************************************************************* + * ETH_ALLOC_PKT(sc) + * + * Allocate a packet from the free list. + * + * Input parameters: + * sc - eth structure + * + * Return value: + * pointer to packet structure, or NULL if none available + ********************************************************************* */ +static eth_pkt_t * +eth_alloc_pkt(tulip_softc *sc) +{ + eth_pkt_t *pkt; + + CS_ENTER(sc); + pkt = (eth_pkt_t *) q_deqnext(&sc->freelist); + CS_EXIT(sc); + if (!pkt) return NULL; + + pkt->buffer = pkt->data; + pkt->length = ETH_PKT_SIZE; + pkt->flags = 0; + + return pkt; +} + + +/* ********************************************************************* + * ETH_FREE_PKT(sc,pkt) + * + * Return a packet to the free list + * + * Input parameters: + * sc - sbmac structure + * pkt - packet to return + * + * Return value: + * nothing + ********************************************************************* */ +static void +eth_free_pkt(tulip_softc *sc, eth_pkt_t *pkt) +{ + CS_ENTER(sc); + q_enqueue(&sc->freelist, &pkt->next); + CS_EXIT(sc); +} + + +/* ********************************************************************* + * ETH_INITFREELIST(sc) + * + * Initialize the buffer free list for this mac. The memory + * allocated to the free list is carved up and placed on a linked + * list of buffers for use by the mac. + * + * Input parameters: + * sc - eth structure + * + * Return value: + * nothing + ********************************************************************* */ +static void +eth_initfreelist(tulip_softc *sc) +{ + int idx; + uint8_t *ptr; + eth_pkt_t *pkt; + + q_init(&sc->freelist); + + ptr = sc->pktpool; + for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) { + pkt = (eth_pkt_t *) ptr; + eth_free_pkt(sc, pkt); + ptr += ETH_PKTBUF_SIZE; + } +} + + +/* Utilities */ + +static const char * +tulip_devname(tulip_softc *sc) +{ + return (sc->devctx != NULL ? cfe_device_name(sc->devctx) : "eth?"); +} + + +/* Descriptor ring management */ + +static int +tulip_add_rcvbuf(tulip_softc *sc, eth_pkt_t *pkt) +{ + volatile rx_dscr *rxd; + volatile rx_dscr *nextrxd; + uint32_t flags = 0; + + rxd = sc->rxdscr_add; + + /* Figure out where the next descriptor will go */ + nextrxd = rxd+1; + if (nextrxd == sc->rxdscr_end) { + nextrxd = sc->rxdscr_start; + flags = M_RDES1_ENDOFRING; + } + + /* + * If the next one is the same as our remove pointer, + * the ring is considered full. (it actually has room for + * one more, but we reserve the remove == add case for "empty") + */ + if (nextrxd == sc->rxdscr_remove) return -1; + + rxd->rxd_bufsize = V_RDES1_BUF1SIZE(1520) | flags; + rxd->rxd_bufaddr1 = PTR_TO_PCI(pkt->buffer); + rxd->rxd_bufaddr2 = 0; + rxd->rxd_flags = M_RDES0_OWNADAP; + + /* success, advance the pointer */ + sc->rxdscr_add = nextrxd; + CS_ENTER(sc); + sc->rxdscr_onring++; + CS_EXIT(sc); + + return 0; +} + +static void +tulip_fillrxring(tulip_softc *sc) +{ + eth_pkt_t *pkt; + + while (1) { + CS_ENTER(sc); + if (sc->rxdscr_onring >= MINRXRING) { + CS_EXIT(sc); + break; + } + CS_EXIT(sc); + pkt = eth_alloc_pkt(sc); + if (pkt == NULL) { + /* could not allocate a buffer */ + break; + } + if (tulip_add_rcvbuf(sc, pkt) != 0) { + /* could not add buffer to ring */ + eth_free_pkt(sc, pkt); + break; + } + } +} + + +/* ********************************************************************* + * TULIP_RX_CALLBACK(sc, pkt) + * + * Receive callback routine. This routine is invoked when a + * buffer queued for receives is filled. In this simple driver, + * all we do is add the packet to a per-MAC queue for later + * processing, and try to put a new packet in the place of the one + * that was removed from the queue. + * + * Input parameters: + * sc - interface + * ptk - packet context (eth_pkt structure) + * + * Return value: + * nothing + ********************************************************************* */ +static void +tulip_rx_callback(tulip_softc *sc, eth_pkt_t *pkt) +{ + if (TULIP_DEBUG) show_packet('>', pkt); /* debug */ + + CS_ENTER(sc); + q_enqueue(&sc->rxqueue, &pkt->next); + CS_EXIT(sc); + sc->inpkts++; + + tulip_fillrxring(sc); +} + + +static void +tulip_procrxring(tulip_softc *sc) +{ + volatile rx_dscr *rxd; + eth_pkt_t *pkt; + eth_pkt_t *newpkt; + uint32_t flags; + + for (;;) { + rxd = (volatile rx_dscr *) sc->rxdscr_remove; + + flags = rxd->rxd_flags; + if (flags & M_RDES0_OWNADAP) { + /* end of ring, no more packets */ + break; + } + + pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufaddr1)); + + /* Drop error packets */ + if (flags & M_RDES0_ERRORSUM) { + xprintf("%s: rx error %04X\n", tulip_devname(sc), flags & 0xFFFF); + tulip_add_rcvbuf(sc, pkt); + goto next; + } + + /* Pass up the packet */ + pkt->length = G_RDES0_FRAMELEN(flags) - CRC_SIZE; + tulip_rx_callback(sc, pkt); + + /* put a buffer back on the ring to replace this one */ + newpkt = eth_alloc_pkt(sc); + if (newpkt) tulip_add_rcvbuf(sc, newpkt); + +next: + /* update the pointer, accounting for buffer wrap. */ + rxd++; + if (rxd == sc->rxdscr_end) + rxd = sc->rxdscr_start; + + sc->rxdscr_remove = (rx_dscr *) rxd; + CS_ENTER(sc); + sc->rxdscr_onring--; + CS_EXIT(sc); + } +} + + +static int +tulip_add_txbuf(tulip_softc *sc, eth_pkt_t *pkt) +{ + volatile tx_dscr *txd; + volatile tx_dscr *nexttxd; + uint32_t bufsize = 0; + + txd = sc->txdscr_add; + + /* Figure out where the next descriptor will go */ + nexttxd = (txd+1); + if (nexttxd == sc->txdscr_end) { + nexttxd = sc->txdscr_start; + bufsize = M_TDES1_ENDOFRING; + } + + /* If the next one is the same as our remove pointer, + the ring is considered full. (it actually has room for + one more, but we reserve the remove == add case for "empty") */ + + if (nexttxd == sc->txdscr_remove) return -1; + + bufsize |= V_TDES1_BUF1SIZE(pkt->length) | + M_TDES1_FIRSTSEG | M_TDES1_LASTSEG | M_TDES1_INTERRUPT; + if (pkt->flags & ETH_TX_SETUP) { + /* For a setup packet, FIRSTSEG and LASTSEG should be clear (!) */ + bufsize ^= M_TDES1_SETUP | M_TDES1_FIRSTSEG | M_TDES1_LASTSEG; + } + txd->txd_bufsize = bufsize; + txd->txd_bufaddr1 = PTR_TO_PCI(pkt->buffer); + txd->txd_bufaddr2 = 0; + txd->txd_flags = M_TDES0_OWNADAP; + + /* success, advance the pointer */ + sc->txdscr_add = nexttxd; + + return 0; +} + + +static int +tulip_transmit(tulip_softc *sc,eth_pkt_t *pkt) +{ + int rv; + + if (TULIP_DEBUG) show_packet('<', pkt); /* debug */ + + rv = tulip_add_txbuf(sc, pkt); + sc->outpkts++; + + WRITECSR(sc, R_CSR_TXPOLL, 1); + return rv; +} + + +static void +tulip_proctxring(tulip_softc *sc) +{ + volatile tx_dscr *txd; + eth_pkt_t *pkt; + uint32_t flags; + + for (;;) { + txd = (volatile tx_dscr *) sc->txdscr_remove; + + if (txd == sc->txdscr_add) { + /* ring is empty, no buffers to process */ + break; + } + + flags = txd->txd_flags; + if (flags & M_TDES0_OWNADAP) { + /* Reached a packet still being transmitted */ + break; + } + + /* Check for a completed setup packet */ + pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufaddr1)); + if (pkt->flags & ETH_TX_SETUP) { + if (sc->state == eth_state_setup) { + uint32_t opmode; + + /* check flag bits */ + opmode = READCSR(sc, R_CSR_OPMODE); + opmode |= M_CSR6_RXSTART; + WRITECSR(sc, R_CSR_OPMODE, opmode); + sc->inpkts = sc->outpkts = 0; + sc->state =eth_state_on; + } + pkt->flags &=~ ETH_TX_SETUP; + } + + /* Just free the packet */ + eth_free_pkt(sc, pkt); + + /* update the pointer, accounting for buffer wrap. */ + txd++; + if (txd == sc->txdscr_end) + txd = sc->txdscr_start; + + sc->txdscr_remove = (tx_dscr *) txd; + } +} + + +static void +tulip_initrings(tulip_softc *sc) +{ + volatile tx_dscr *txd; + volatile rx_dscr *rxd; + + /* Claim ownership of all descriptors for the driver */ + + for (txd = sc->txdscr_start; txd != sc->txdscr_end; txd++) + txd->txd_flags = 0; + for (rxd = sc->rxdscr_start; rxd != sc->rxdscr_end; rxd++) + rxd->rxd_flags = 0; + + /* Init the ring pointers */ + + sc->txdscr_add = sc->txdscr_remove = sc->txdscr_start; + sc->rxdscr_add = sc->rxdscr_remove = sc->rxdscr_start; + sc->rxdscr_onring = 0; + + /* Add stuff to the receive ring */ + + tulip_fillrxring(sc); +} + + +static int +tulip_init(tulip_softc *sc) +{ + /* Allocate descriptor rings */ + sc->rxdscrmem = KMALLOC(MAXRXDSCR*sizeof(rx_dscr), sizeof(rx_dscr)); + sc->txdscrmem = KMALLOC(MAXTXDSCR*sizeof(tx_dscr), sizeof(tx_dscr)); + + /* Allocate buffer pool */ + sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, CACHE_ALIGN); + eth_initfreelist(sc); + q_init(&sc->rxqueue); + + /* Fill in pointers to the rings */ + sc->rxdscr_start = (rx_dscr *) (sc->rxdscrmem); + sc->rxdscr_end = sc->rxdscr_start + MAXRXDSCR; + sc->rxdscr_add = sc->rxdscr_start; + sc->rxdscr_remove = sc->rxdscr_start; + sc->rxdscr_onring = 0; + + sc->txdscr_start = (tx_dscr *) (sc->txdscrmem); + sc->txdscr_end = sc->txdscr_start + MAXTXDSCR; + sc->txdscr_add = sc->txdscr_start; + sc->txdscr_remove = sc->txdscr_start; + + tulip_initrings(sc); + + return 0; +} + + +static void +tulip_resetrings(tulip_softc *sc) +{ + volatile tx_dscr *txd; + volatile rx_dscr *rxd; + eth_pkt_t *pkt; + + /* Free already-sent descriptors and buffers */ + tulip_proctxring(sc); + + /* Free any pending but unsent */ + txd = (volatile tx_dscr *) sc->txdscr_remove; + while (txd != sc->txdscr_add) { + txd->txd_flags &=~ M_TDES0_OWNADAP; + pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufaddr1)); + eth_free_pkt(sc, pkt); + + txd++; + if (txd == sc->txdscr_end) + txd = sc->txdscr_start; + } + sc->txdscr_add = sc->txdscr_remove; + + /* Discard any received packets as well as all free buffers */ + rxd = (volatile rx_dscr *) sc->rxdscr_remove; + while (rxd != sc->rxdscr_add) { + rxd->rxd_flags &=~ M_RDES0_OWNADAP; + pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufaddr1)); + eth_free_pkt(sc, pkt); + + rxd++; + if (rxd == sc->rxdscr_end) + rxd = sc->rxdscr_start; + CS_ENTER(sc); + sc->rxdscr_onring--; + CS_EXIT(sc); + } + + /* Reestablish the initial state. */ + tulip_initrings(sc); +} + + +/* CRCs */ + +#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */ + +static uint32_t +tulip_crc32(const uint8_t *databuf, unsigned int datalen) +{ + unsigned int idx, bit, data; + uint32_t crc; + + crc = 0xFFFFFFFFUL; + for (idx = 0; idx < datalen; idx++) + for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0); + return crc; +} + +#define tulip_mchash(mca) (tulip_crc32((mca), 6) & 0x1FF) + + +/* Serial ROM access */ + +/**************************************************************************** + * tulip_spin(sc, ns) + * + * Spin for a short interval (nominally in nanoseconds) + * + * Input Parameters: ns - minimum required nsec. + * + * The delay loop uses uncached PCI reads, each of which requires + * at least 3 PCI bus clocks (45 ns at 66 MHz) to complete. The + * actual delay will be longer (much longer if preempted). + ***************************************************************************/ + +#define PCI_MIN_DELAY 45 + +static void +tulip_spin(tulip_softc *sc, long nanoseconds) +{ + long delay; + volatile uint32_t t; + + for (delay = nanoseconds; delay > 0; delay -= PCI_MIN_DELAY) + t = READCSR(sc, R_CSR_BUSMODE); +} + + +/* + * Delays below are chosen to meet specs for NS93C64 (slow M variant). + * Current parts are faster. + * Reference: NS Memory Data Book, 1994 + */ + +#define SROM_SIZE 128 +#define SROM_MAX_CYCLES 32 + +#define SROM_CMD_BITS 3 +#define SROM_ADDR_BITS 6 + +#define K_SROM_READ_CMD 06 +#define K_SROM_WRITE_CMD 05 + +#define SROM_VENDOR_INDEX 0x00 +#define SROM_FORMAT_INDEX 0x12 +#define SROM_ADDR_INDEX 0x14 + +#define SROM_DEVICE0_INDEX 0x1A +#define SROM_LEAF0_OFFSET_INDEX 0x1B + +#define SROM_CRC_INDEX (SROM_SIZE-2) +/* Note recent chips supporting wake-on-lan have CRC in bytes 94, 95 */ + +#define SROM_WORD(rom,offset) ((rom)[offset] | ((rom)[offset+1] << 8)) + +static void +srom_idle_state(tulip_softc *sc) +{ + uint32_t csr9; + unsigned int i; + + csr9 = READCSR(sc, R_CSR_ROM_MII); + + csr9 |= M_CSR9_SROMCHIPSEL; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 100); /* CS setup (Tcss=100) */ + + /* Run the clock through the maximum number of pending read cycles */ + for (i = 0; i < SROM_MAX_CYCLES*2; i++) { + csr9 ^= M_CSR9_SROMCLOCK; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 1000); /* SK period (Fsk=0.5MHz) */ + } + + /* Deassert SROM Chip Select */ + csr9 &=~ M_CSR9_SROMCHIPSEL; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 50); /* CS recovery (Tsks=50) */ +} + +static void +srom_send_command_bit(tulip_softc *sc, unsigned int data) +{ + uint32_t csr9; + + csr9 = READCSR(sc, R_CSR_ROM_MII); + + /* Place the data bit on the bus */ + if (data == 1) + csr9 |= M_CSR9_SROMDATAIN; + else + csr9 &=~ M_CSR9_SROMDATAIN; + + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 360); /* setup: Tdis=200 */ + + /* Now clock the data into the SROM */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK); + tulip_spin(sc, 900); /* clock high, Tskh=500 */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 450); /* clock low, Tskl=250 */ + + /* Now clear the data bit */ + csr9 &=~ M_CSR9_SROMDATAIN; /* data invalid, Tidh=20 for SK^ */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 270); /* min cycle, 1/Fsk=2000 */ +} + +static uint16_t +srom_read_bit(tulip_softc *sc) +{ + uint32_t csr9; + + csr9 = READCSR(sc, R_CSR_ROM_MII); + + /* Generate a clock cycle before doing a read */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK); /* rising edge */ + tulip_spin(sc, 1000); /* clock high, Tskh=500, Tpd=1000 */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); /* falling edge */ + tulip_spin(sc, 1000); /* clock low, 1/Fsk=2000 */ + + csr9 = READCSR(sc, R_CSR_ROM_MII); + return ((csr9 & M_CSR9_SROMDATAOUT) != 0 ? 1 : 0); +} + +#define CMD_BIT_MASK (1 << (SROM_CMD_BITS+SROM_ADDR_BITS-1)) + +static uint16_t +srom_read_word(tulip_softc *sc, unsigned int index) +{ + uint16_t command, word; + uint32_t csr9; + unsigned int i; + + csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_SROMCHIPSEL; + + /* Assert the SROM CS line */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 100); /* CS setup, Tcss = 100 */ + + /* Send the read command to the SROM */ + command = (K_SROM_READ_CMD << SROM_ADDR_BITS) | index; + for (i = 0; i < SROM_CMD_BITS+SROM_ADDR_BITS; i++) { + srom_send_command_bit(sc, (command & CMD_BIT_MASK) != 0 ? 1 : 0); + command <<= 1; + } + + /* Now read the bits from the SROM (MSB first) */ + word = 0; + for (i = 0; i < 16; ++i) { + word <<= 1; + word |= srom_read_bit(sc); + } + + /* Clear the SROM CS Line, CS hold, Tcsh = 0 */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 &~ M_CSR9_SROMCHIPSEL); + + return word; +} + + +/**************************************************************************** + * srom_calc_crc() + * + * Calculate the CRC of the SROM and return it. We compute the + * CRC per Appendix A of the 21140A ROM/external register data + * sheet (EC-QPQWA-TE). + ***************************************************************************/ + +static uint16_t +srom_calc_crc(tulip_softc *sc, uint8_t srom[], int length) +{ + uint32_t crc = tulip_crc32(srom, length) ^ 0xFFFFFFFF; + + return (uint16_t)(crc & 0xFFFF); +} + +/**************************************************************************** + * srom_read_all(sc, uint8_t dest) + * + * Read the entire SROM into the srom array + * + * Input parameters: + * sc - tulip state + ***************************************************************************/ + +static int +srom_read_all(tulip_softc *sc, uint8_t dest[]) +{ + int i; + uint16_t crc, temp; + + WRITECSR(sc, R_CSR_ROM_MII, M_CSR9_SERROMSEL|M_CSR9_ROMREAD); + + srom_idle_state(sc); + + for (i = 0; i < SROM_SIZE/2; i++) { + temp = srom_read_word(sc, i); + dest[2*i] = temp & 0xFF; + dest[2*i+1] =temp >> 8; + } + + WRITECSR(sc, R_CSR_ROM_MII, 0); /* CS hold, Tcsh=0 */ + + crc = srom_calc_crc(sc, dest, SROM_CRC_INDEX); + if (crc != SROM_WORD(dest, SROM_CRC_INDEX)) { + crc = srom_calc_crc(sc, dest, 94); /* "alternative" */ + if (crc != SROM_WORD(dest, 94)) { + xprintf("%s: Invalid SROM CRC, calc %04x, stored %04x\n", + tulip_devname(sc), crc, SROM_WORD(dest, 94)); + return 0/*-1*/; + } + } + return 0; +} + +static int +srom_read_addr(tulip_softc *sc, uint8_t buf[]) +{ + uint8_t srom[SROM_SIZE]; + + if (srom_read_all(sc, srom) == 0) { + memcpy(buf, &srom[SROM_ADDR_INDEX], ENET_ADDR_LEN); + return 0; + } + + return -1; +} + + +/**************************************************************************** + * earom_read_all(sc, uint8_t dest) + * + * Read the entire Ethernet address ROM into the srom array (21040 only) + * + * Input parameters: + * sc - tulip state + ***************************************************************************/ + +static int +earom_read_all(tulip_softc *sc, uint8_t dest[]) +{ + int i; + uint32_t csr9; + + WRITECSR(sc, R_CSR_ROM_MII, 0); /* reset pointer */ + + for (i = 0; i < SROM_SIZE; i++) { + for (;;) { + csr9 = READCSR(sc, R_CSR_ROM_MII); + if ((csr9 & M_CSR9_DATANOTVALID) == 0) + break; + POLL(); /* XXX need a timeout */ + } + dest[i] = G_CSR9_ROMDATA(csr9); + } + + return 0; +} + +static int +earom_read_addr(tulip_softc *sc, uint8_t buf[]) +{ + uint8_t srom[SROM_SIZE]; + + if (earom_read_all(sc, srom) == 0) { + memcpy(buf, &srom[0], ENET_ADDR_LEN); + return 0; + } + + return -1; +} + + +static int +rom_read_all(tulip_softc *sc, uint8_t buf[]) +{ + if (sc->device == K_PCI_ID_DC21040) + return earom_read_all(sc, buf); + else + return srom_read_all(sc, buf); +} + +static int +rom_read_addr(tulip_softc *sc, uint8_t buf[]) +{ + if (sc->device == K_PCI_ID_DC21040) + return earom_read_addr(sc, buf); + else + return srom_read_addr(sc, buf); +} + +#if 0 +static void +rom_dump(uint8_t srom[]) +{ + int i; + + xprintf("DC21x4x: SROM data:"); + for (i = 0; i < SROM_SIZE; i++) { + if (i % 16 == 0) + xprintf("\n %02x: ", i); + xprintf(" %02x", srom[i]); + } + xprintf("\n"); +} +#else +#define rom_dump(srom) +#endif + + +/**************************************************************************** + * MII access utility routines + ***************************************************************************/ + +/* MII clock limited to 2.5 MHz, transactions end with MDIO tristated */ + +static void +mii_write_bits(tulip_softc *sc, uint32_t data, unsigned int count) +{ + uint32_t csr9; + uint32_t bitmask; + + csr9 = READCSR(sc, R_CSR_ROM_MII) &~ (M_CSR9_MDC | M_CSR9_MIIMODE); + + for (bitmask = 1 << (count-1); bitmask != 0; bitmask >>= 1) { + csr9 &=~ M_CSR9_MDO; + if ((data & bitmask) != 0) csr9 |= M_CSR9_MDO; + WRITECSR(sc, R_CSR_ROM_MII, csr9); + + tulip_spin(sc, 2000); /* setup */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC); + tulip_spin(sc, 2000); /* hold */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + } +} + +static void +mii_turnaround(tulip_softc *sc) +{ + uint32_t csr9; + + csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_MIIMODE; + + /* stop driving data */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 2000); /* setup */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC); + tulip_spin(sc, 2000); /* clock high */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + + /* read back and check for 0 here? */ +} + +/**************************************************************************** + * mii_read_register + * + * This routine reads a register from the PHY chip using the MII + * serial management interface. + * + * Input parameters: + * index - index of register to read (0-31) + * + * Return value: + * word read from register + ***************************************************************************/ + +static uint16_t +mii_read_register(tulip_softc *sc, unsigned int index) +{ + /* Send the command and address to the PHY. The sequence is + a synchronization sequence (32 1 bits) + a "start" command (2 bits) + a "read" command (2 bits) + the PHY addr (5 bits) + the register index (5 bits) + */ + uint32_t csr9; + uint16_t word; + int i; + + mii_write_bits(sc, 0xFF, 8); + mii_write_bits(sc, 0xFFFFFFFF, 32); + mii_write_bits(sc, MII_COMMAND_START, 2); + mii_write_bits(sc, MII_COMMAND_READ, 2); + mii_write_bits(sc, sc->mii_addr, 5); + mii_write_bits(sc, index, 5); + + mii_turnaround(sc); + + csr9 = (READCSR(sc, R_CSR_ROM_MII) &~ M_CSR9_MDC) | M_CSR9_MIIMODE; + word = 0; + + for (i = 0; i < 16; i++) { + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 2000); /* clock width low */ + WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC); + tulip_spin(sc, 2000); /* clock width high */ + WRITECSR(sc, R_CSR_ROM_MII, csr9); + tulip_spin(sc, 1000); /* output delay */ + word <<= 1; + if ((READCSR(sc, R_CSR_ROM_MII) & M_CSR9_MDI) != 0) + word |= 0x0001; + } + + return word; + + /* reset to output mode? */ +} + +/**************************************************************************** + * mii_write_register + * + * This routine writes a register in the PHY chip using the MII + * serial management interface. + * + * Input parameters: + * index - index of register to write (0-31) + * value - word to write + ***************************************************************************/ + +static void +mii_write_register(tulip_softc *sc, unsigned int index, uint16_t value) +{ + mii_write_bits(sc, 0xFF, 8); + mii_write_bits(sc, 0xFFFFFFFF, 32); + mii_write_bits(sc, MII_COMMAND_START, 2); + mii_write_bits(sc, MII_COMMAND_WRITE, 2); + mii_write_bits(sc, sc->mii_addr, 5); + mii_write_bits(sc, index, 5); + mii_write_bits(sc, MII_COMMAND_ACK, 2); + mii_write_bits(sc, value, 16); + + /* reset to input mode? */ +} + + +static int +mii_probe(tulip_softc *sc) +{ + int i; + uint16_t id1, id2; + + for (i = 0; i < 32; i++) { + sc->mii_addr = i; + id1 = mii_read_register(sc, MII_PHYIDR1); + id2 = mii_read_register(sc, MII_PHYIDR2); + if ((id1 != 0x0000 && id1 != 0xFFFF) || + (id2 != 0x0000 && id2 != 0xFFFF)) { + return 0; + } + } + return -1; +} + +#if 0 +#define OUI_NAT_SEMI 0x080017 +#define OUI_LEVEL_ONE 0x1E0400 /* 0x00207B, bit reversed and truncated */ + +static void +mii_dump(tulip_softc *sc, const char *label) +{ + int i; + uint16_t r; + uint32_t oui, part; + + xprintf("%s\n", label); + oui = 0; + for (i = 0; i <= 6; ++i) { + r = mii_read_register(sc, i); + if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r); + if (i == MII_PHYIDR1) { + oui = r << 6; + } + else if (i == MII_PHYIDR2) { + oui |= (r >> 10) & 0x3F; + part = (r >> 4) & 0x3F; + } + } + if (oui == OUI_NAT_SEMI) { /* DP83840, DP83840A */ + for (i = 0x15; i <= 0x19; ++i) { + r = mii_read_register(sc, i); + if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r); + } + } + else if (oui == OUI_LEVEL_ONE) { /* LXT970, etc. */ + for (i = 0x10; i <= 0x14; ++i) { + r = mii_read_register(sc, i); + if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r); + } + } +} +#else +#define mii_dump(sc,label) +#endif + + +/* The following functions are suitable for all tulips with MII + interfaces. */ + +static void +mii_set_speed(tulip_softc *sc, int speed, int autoneg) +{ + uint16_t control; + uint16_t pcr; + uint32_t opmode = 0; + + /* This is really just for NS DP83840/A. Needed? */ + pcr = mii_read_register(sc, 0x17); + pcr |= (0x400|0x100|0x40|0x20); + mii_write_register(sc, 0x17, pcr); + + control = mii_read_register(sc, MII_BMCR); + + if (!autoneg) { + control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + control &=~ (BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX); + } + + switch (speed) { + case ETHER_SPEED_10HDX: + default: + opmode = M_CSR6_SPEED_10_MII; + break; + case ETHER_SPEED_10FDX: + control |= BMCR_DUPLEX; + opmode = M_CSR6_SPEED_10_MII | M_CSR6_FULLDUPLEX; + break; + case ETHER_SPEED_100HDX: + control |= BMCR_SPEED100; + opmode = M_CSR6_SPEED_100_MII; + break; + case ETHER_SPEED_100FDX: + control |= BMCR_SPEED100 | BMCR_DUPLEX ; + opmode = M_CSR6_SPEED_100_MII | M_CSR6_FULLDUPLEX; + break; + } + + if (!autoneg) + mii_write_register(sc, MII_BMCR, control); + + opmode |= M_CSR6_MBO; +#if TULIP_TUNE + opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72); +#else + opmode |= M_CSR6_STOREFWD; +#endif + WRITECSR(sc, R_CSR_OPMODE, opmode); + mii_dump(sc, "setspeed PHY"); +} + +static void +mii_autonegotiate(tulip_softc *sc) +{ + uint16_t control, status, cap; + unsigned int timeout; + int linkspeed; + int autoneg; + + linkspeed = ETHER_SPEED_UNKNOWN; + + /* Read twice to clear latching bits */ + status = mii_read_register(sc, MII_BMSR); + status = mii_read_register(sc, MII_BMSR); + mii_dump(sc, "query PHY"); + + if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) == + (BMSR_AUTONEG | BMSR_LINKSTAT)) + control = mii_read_register(sc, MII_BMCR); + else { + /* reset the PHY */ + mii_write_register(sc, MII_BMCR, BMCR_RESET); + timeout = 3000; + for (;;) { + control = mii_read_register(sc, MII_BMCR); + if ((control && BMCR_RESET) == 0) break; + cfe_sleep(CFE_HZ/2); + timeout -= 500; + if (timeout <= 0) break; + } + if ((control & BMCR_RESET) != 0) { + xprintf("%s: PHY reset failed\n", tulip_devname(sc)); + return; + } + + status = mii_read_register(sc, MII_BMSR); + cap = ((status >> 6) & (ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD)) + | PSB_802_3; + mii_write_register(sc, MII_ANAR, cap); + control |= (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + + timeout = 3000; + for (;;) { + status = mii_read_register(sc, MII_BMSR); + if ((status & BMSR_ANCOMPLETE) != 0) break; + cfe_sleep(CFE_HZ/2); + timeout -= 500; + if (timeout <= 0) break; + } + mii_dump(sc, "done PHY"); + } + + xprintf("%s: Link speed: ", tulip_devname(sc)); + if ((status & BMSR_ANCOMPLETE) != 0) { + /* A link partner was negogiated... */ + + uint16_t remote = mii_read_register(sc, MII_ANLPAR); + + autoneg = 1; + if ((remote & ANLPAR_TXFD) != 0) { + xprintf("100BaseT FDX"); + linkspeed = ETHER_SPEED_100FDX; + } + else if ((remote & ANLPAR_TXHD) != 0) { + xprintf("100BaseT HDX"); + linkspeed = ETHER_SPEED_100HDX; + } + else if ((remote & ANLPAR_10FD) != 0) { + xprintf("10BaseT FDX"); + linkspeed = ETHER_SPEED_10FDX; + } + else if ((remote & ANLPAR_10HD) != 0) { + xprintf("10BaseT HDX"); + linkspeed = ETHER_SPEED_10HDX; + } + xprintf("\n"); + } + else { + /* no link partner negotiation */ + + autoneg = 0; + xprintf("Unknown, assuming 10BaseT\n"); + control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN); + mii_write_register(sc, MII_BMCR, control); + linkspeed = ETHER_SPEED_10HDX; + } + + if ((status & BMSR_LINKSTAT) == 0) + mii_write_register(sc, MII_BMCR, control); + mii_set_speed(sc, linkspeed, autoneg); + + status = mii_read_register(sc, MII_BMSR); /* clear latching bits */ + mii_dump(sc, "final PHY"); +} + + +/* Chip specific code */ + +static void +dc21143_set_speed(tulip_softc *sc, int speed) +{ + uint32_t opmode = 0; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + + switch (speed) { + case ETHER_SPEED_AUTO: + break; + case ETHER_SPEED_10HDX: + default: + WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_HD); + WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata); + opmode = M_CSR6_SPEED_10; + break; + case ETHER_SPEED_10FDX: + WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_FD); + WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata); + opmode = M_CSR6_SPEED_10 | M_CSR6_FULLDUPLEX; + break; + case ETHER_SPEED_100HDX: + WRITECSR(sc, R_CSR_SIAMODE1, 0); + WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata); + opmode = M_CSR6_SPEED_100; + break; + case ETHER_SPEED_100FDX: + WRITECSR(sc, R_CSR_SIAMODE1, 0); + WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata); + opmode = M_CSR6_SPEED_100 | M_CSR6_FULLDUPLEX; + break; + } + + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); + + opmode |= M_CSR6_MBO; +#if TULIP_TUNE + opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72); +#else + opmode |= M_CSR6_STOREFWD; +#endif + WRITECSR(sc, R_CSR_OPMODE, opmode); +} + +static void +dc21143_autonegotiate(tulip_softc *sc) +{ + uint32_t opmode; + uint32_t tempword; + int count; + int linkspeed; + + linkspeed = ETHER_SPEED_UNKNOWN; + + /* Program the media setup into the CSRs. */ + /* reset SIA */ + WRITECSR(sc, R_CSR_SIAMODE0, 0); + + /* set to speed_10, fullduplex to start_nway */ + opmode = + M_CSR6_SPEED_10 | + M_CSR6_FULLDUPLEX | + M_CSR6_MBO; + WRITECSR(sc, R_CSR_OPMODE, opmode); + + /* Choose advertised capabilities */ + tempword = + M_CSR14_100BASETHALFDUP | + M_CSR14_100BASETFULLDUP | + M_CSR14_HALFDUPLEX10BASET; + WRITECSR(sc, R_CSR_SIAMODE1, tempword); + + /* Enable autonegotiation */ + tempword |= M_CSR14_AUTONEGOTIATE | 0xFFFF; + WRITECSR(sc, R_CSR_SIAMODE1, tempword); + WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata); + WRITECSR(sc, R_CSR_OPMODE, opmode); + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); + + /* STATE check nway, poll until a valid 10/100mbs signal seen */ + WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS); /* try to clear this... */ + + /* (Re)start negotiation */ + tempword = READCSR(sc, R_CSR_SIASTATUS); + tempword &=~ M_CSR12_AUTONEGARBIT; + tempword |= V_CSR12_AUTONEGARBIT(0x1); + + for (count = 0; count <= 13; count++) { + tempword = READCSR(sc, R_CSR_STATUS); + if (tempword & M_CSR5_LINKPASS) + break; + cfe_sleep(CFE_HZ/10); + } + + if (count > 13) + xprintf("%s: Link autonegotiation failed\n", tulip_devname(sc)); + + /* STATE configure nway, check to see if any abilities common to us. + If they do, set to highest mode, if not, we will see if the partner + will do 100mb or 10mb - then set it */ + + tempword = READCSR(sc, R_CSR_SIASTATUS); + /* clear the autonegogiate complete bit */ + WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS); + + if (tempword & M_CSR12_LINKPARTNEG) { + /* A link partner was negogiated... */ + + xprintf("%s: Link speed: ", tulip_devname(sc)); + if (tempword & 0x01000000) { /* 100FD */ + xprintf("100BaseT FDX"); + linkspeed = ETHER_SPEED_100FDX; + } + else if (tempword & 0x00800000) { /* 100HD */ + xprintf("100BaseT HDX"); + linkspeed = ETHER_SPEED_100HDX; + } + else if (tempword & 0x00400000) { /* 10FD */ + xprintf("10BaseT FDX"); + linkspeed = ETHER_SPEED_10FDX; + } + else if (tempword & 0x00200000) { /* 10HD */ + xprintf("10BaseT HDX"); + linkspeed = ETHER_SPEED_10HDX; + } + xprintf("\n"); + } + else { + /* no link partner negotiation */ + /* disable link for 1.3 seconds to break any existing connections */ + + xprintf("%s: ", tulip_devname(sc)); + dc21143_set_speed(sc, ETHER_SPEED_10HDX); + cfe_sleep(CFE_HZ/8); + + tempword = READCSR(sc, R_CSR_SIASTATUS); + + if ((tempword & 0x02) == 0) { + /* 100 mb signal present set to 100mb */ + xprintf("No link partner... setting to 100BaseT HDX\n"); + linkspeed = ETHER_SPEED_100HDX; + } + else if ((tempword & 0x04) == 0) { + /* 10 mb signal present */ + xprintf("No link partner... setting to 10BaseT HDX\n"); + linkspeed = ETHER_SPEED_10HDX; + } + else { + /* couldn't determine line speed, so set to 10mbs */ + xprintf("Unknown; defaulting to 10BaseT HDX\n"); + linkspeed = ETHER_SPEED_10HDX; + } + } + + dc21143_set_speed(sc, linkspeed); +} + +static void +dc21143_set_loopback(tulip_softc *sc, int mode) +{ + uint32_t v; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + if (mode == ETHER_LOOPBACK_EXT) { + /* deal with CSRs 13-15 */ + } + cfe_sleep(CFE_HZ/10); /* check this */ + + /* Update the SIA registers */ + v = READCSR(sc, R_CSR_SIAMODE0); + WRITECSR(sc, R_CSR_SIAMODE0, v &~ 0xFFFF); + v = READCSR(sc, R_CSR_SIAMODE1); + WRITECSR(sc, R_CSR_SIAMODE1, v &~ 0xFFFF); + v = READCSR(sc, R_CSR_SIAMODE2); + WRITECSR(sc, R_CSR_SIAMODE2, v | 0xC000); /* WC of HCKR, RMP */ + if (mode == ETHER_LOOPBACK_OFF) + WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata); + else + WRITECSR(sc, R_CSR_SIAMODE2, (v &~ 0xFFFF) | M_CSR15_GP_AUIBNC); + + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); + + sc->loopback = mode; +} + +/* Known vendors with cards requiring special initialization. */ +#define K_PCI_VENDOR_COGENT 0x1109 /* inherited by Adaptec */ +#define K_PCI_VENDOR_PHOBOS 0x13D8 +#define K_PCI_VENDOR_ZNYZ 0x110D +#define K_PCI_VENDOR_KINGSTON 0x2646 + +static void +dc21143_hwinit(tulip_softc *sc, uint8_t srom[]) +{ + uint32_t v; + uint32_t csr6word, csr14word; + + if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_COGENT) { + /* Cogent/Adaptec MII (ANA-6911A). */ + sc->phy_type = MII; + WRITECSR(sc, R_CSR_SIAMODE2, 0x0821 << 16); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0001 << 16); + cfe_sleep(CFE_HZ/10); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0000 << 16); + cfe_sleep(CFE_HZ/2); + sc->gpdata = 0; + } + else if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_ZNYZ) { + /* Znyz 34xQ adapters */ + sc->phy_type = SYM; + + /* The ZX345Q with wake-on-LAN enabled apparently clears ANE and + TAS on power up (but not cold reset) */ + WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFFFFFF); + + /* The following is a reset workaround for QS/Kendin PHYs + as suggested by an Intel app note. Bit 0x40000 is the PHY + reset (low true) on Znyx cards. */ + WRITECSR(sc, R_CSR_SIAMODE2, + M_CSR15_GP_CONTROLWRITE | + 0xF0000 | /* all outputs */ + M_CSR15_GP_LED1 | + M_CSR15_GP_AUIBNC); + cfe_sleep(CFE_HZ/5); + WRITECSR(sc, R_CSR_SIAMODE2, 0x40000); /* release reset */ + cfe_sleep(CFE_HZ/5); + sc->gpdata = 0x40000 | M_CSR15_GP_AUIBNC; + } + else if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_KINGSTON) { + /* Kingston KNE100TX */ + sc->phy_type = MII; + sc->gpdata = 0; + } + else if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_PHOBOS) { + /* Phobos 430TX quad card */ + sc->phy_type = MII; +#if 0 /* per EEPROM */ + WRITECSR(sc, R_CSR_SIAMODE2, 0x080E << 16); + WRITECSR(sc, R_CSR_SIAMODE2, 0x000E << 16); + cfe_sleep(CFE_HZ/10); + sc->gpdata = 0x0E; +#else /* following Adaptec 21143 with MII interface */ + WRITECSR(sc, R_CSR_SIAMODE2, 0x0821 << 16); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0001 << 16); + cfe_sleep(CFE_HZ/10); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0000 << 16); + cfe_sleep(CFE_HZ/2); + sc->gpdata = 0; +#endif + } + else { + /* Most 21143 cards use the SYM interface. */ + sc->phy_type = SYM; + WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_CONFIG_GEPS_LEDS); + sc->gpdata = M_CSR15_DEFAULT_VALUE; + } + + if (sc->phy_type == MII) { + mii_probe(sc); + } + + /* CSR0 - bus mode */ +#if TULIP_TUNE + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + M_CSR0_READMULTENAB | M_CSR0_READLINEENAB | + M_CSR0_WRITEINVALENAB | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#else + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#endif +#ifdef __MIPSEB + v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */ +#endif + WRITECSR(sc, R_CSR_BUSMODE, v); + + /* CSR6 - operation mode */ + v = M_CSR6_PORTSEL | +#if TULIP_TUNE + V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) | +#else + M_CSR6_STOREFWD | +#endif + M_CSR6_MBO; + if (sc->phy_type == SYM) + v |= M_CSR6_PCSFUNC |M_CSR6_SCRAMMODE; + WRITECSR(sc, R_CSR_OPMODE, v); + + /* About to muck with the SIA, reset it.(?) */ + /* WRITECSR(sc, R_CSR_SIASTATUS, 0); */ + + /* Must shut off all transmit/receive in order to attempt to + achieve Full Duplex */ + csr6word = READCSR(sc, R_CSR_OPMODE); + WRITECSR(sc, R_CSR_OPMODE, csr6word &~ (M_CSR6_TXSTART | M_CSR6_RXSTART)); + csr6word = READCSR(sc, R_CSR_OPMODE); + + WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start)); + WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start)); + + if (sc->phy_type == MII) { + if (sc->linkspeed == ETHER_SPEED_AUTO) + mii_autonegotiate(sc); + else + mii_set_speed(sc, sc->linkspeed, 0); + } + else { + if (sc->linkspeed == ETHER_SPEED_AUTO) { + dc21143_autonegotiate(sc); + } + else { + /* disable autonegotiate so we can set full duplex to on */ + WRITECSR(sc, R_CSR_SIAMODE0, 0); + csr14word = READCSR(sc, R_CSR_SIAMODE1); + csr14word &=~ M_CSR14_AUTONEGOTIATE; + WRITECSR(sc, R_CSR_SIAMODE1, csr14word); + WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET); + + dc21143_set_speed(sc, sc->linkspeed); + } + } +} + + +static void +dc21140_set_speed(tulip_softc *sc, int speed, int autoneg) +{ + mii_set_speed(sc, speed, autoneg); +} + +static void +dc21140_set_loopback(tulip_softc *sc, int mode) +{ + if (mode == ETHER_LOOPBACK_EXT) { + xprintf("%s: external loopback mode NYI\n", tulip_devname(sc)); + mode = ETHER_LOOPBACK_OFF; + } + else if (mode != ETHER_LOOPBACK_INT) + mode = ETHER_LOOPBACK_OFF; + + sc->loopback = mode; +} + +static void +dc21140_hwinit(tulip_softc *sc, uint8_t srom[]) +{ + uint16_t leaf; + uint8_t gpr_control, gpr_data; + uint32_t v; + uint32_t opmode; + + if (srom[SROM_FORMAT_INDEX] == 0 || srom[SROM_FORMAT_INDEX] > 4) { + gpr_control = 0x1F; + gpr_data = 0x00; + sc->phy_type = MII; /* Most 21140 cards use MII */ + } + else { + leaf = SROM_WORD(srom, SROM_LEAF0_OFFSET_INDEX); + gpr_control = srom[leaf+2]; + /* XXX We should parse and check all the leaf info */ + if ((srom[leaf+4] & 0x80) == 0) { + gpr_data = 0x85; /* SYM, 100 Mb/s */ + sc->phy_type = SYM; + } + else { + gpr_data = 0x00; /* MII */ + sc->phy_type = MII; + } + } + + /* Assume that we will use MII or SYM interface */ + WRITECSR(sc, R_CSR_OPMODE, M_CSR6_PORTSEL); + RESET_ADAPTER(sc); + + WRITECSR(sc, R_CSR_GENPORT, M_CSR12_CONTROL | gpr_control); + WRITECSR(sc, R_CSR_GENPORT, gpr_data); /* setup PHY */ + + if (sc->phy_type == MII) { + mii_probe(sc); + } + + /* CSR0 - bus mode */ +#if TULIP_TUNE + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + M_CSR0_READMULTENAB | M_CSR0_READLINEENAB | + M_CSR0_WRITEINVALENAB | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#else + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#endif +#ifdef __MIPSEB + v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */ +#endif + WRITECSR(sc, R_CSR_BUSMODE, v); + + /* CSR6 - operation mode */ + v = M_CSR6_PORTSEL | +#if TULIP_TUNE + V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) | +#else + M_CSR6_STOREFWD | +#endif + M_CSR6_MBO; + WRITECSR(sc, R_CSR_OPMODE, v); + + /* Must shut off all transmit/receive in order to attempt to + achieve Full Duplex */ + opmode = READCSR(sc, R_CSR_OPMODE); + WRITECSR(sc, R_CSR_OPMODE, opmode &~ (M_CSR6_TXSTART | M_CSR6_RXSTART)); + opmode = READCSR(sc, R_CSR_OPMODE); + + WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start)); + WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start)); + + if (sc->phy_type == MII) { + if (sc->linkspeed == ETHER_SPEED_AUTO) + mii_autonegotiate(sc); + else + mii_set_speed(sc, sc->linkspeed, 0); + } + else { + /* XXX The 21140 requires a soft reset after changing PORTSEL. + For now, remain committed to the SYM port (100 Mb/s) */ + switch (sc->linkspeed) { + default: + sc->linkspeed = ETHER_SPEED_100HDX; /* for now */ + /* fall through */ + case ETHER_SPEED_100HDX: + opmode |= M_CSR6_SPEED_100; + break; + case ETHER_SPEED_100FDX: + opmode |= M_CSR6_SPEED_100 | M_CSR6_FULLDUPLEX; + break; + } + + /* XXX Need to reset and reinitialize if we choose SPEED_10 above */ + WRITECSR(sc, R_CSR_OPMODE, opmode); + } +} + + +static void +dc21041_set_speed(tulip_softc *sc, int speed) +{ + uint32_t opmode = 0; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + + /* For now, always force 10BT, HDX (21041, Table 3-62) */ + switch (speed) { + case ETHER_SPEED_10HDX: + default: + WRITECSR(sc, R_CSR_SIAMODE1, 0x7F3F); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0008); + opmode = M_CSR6_SPEED_10; + break; + } + + WRITECSR(sc, R_CSR_SIAMODE0, 0xEF00 | M_CSR13_CONN_NOT_RESET); + cfe_sleep(CFE_HZ/10); + + opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72); + WRITECSR(sc, R_CSR_OPMODE, opmode); +} + +static void +dc21041_set_loopback(tulip_softc *sc, int mode) +{ + /* For now, always assume 10BT */ + uint32_t mode0; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + cfe_sleep(CFE_HZ/10); /* check this */ + + /* Update the SIA registers */ + if (mode == ETHER_LOOPBACK_EXT) { + /* NB: this is really just internal but through the 10BT endec */ + WRITECSR(sc, R_CSR_SIAMODE1, 0x7A3F); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0008); + mode0 = 0; + } + else if (mode == ETHER_LOOPBACK_INT) { + /* MAC internal loopback, no SIA */ + WRITECSR(sc, R_CSR_SIAMODE1, 0x0000); + WRITECSR(sc, R_CSR_SIAMODE2, 0x000E); + mode0 = M_CSR13_CONN_AUI_10BT; + } + else { + mode = ETHER_LOOPBACK_OFF; + WRITECSR(sc, R_CSR_SIAMODE1, 0x7F3F); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0008); + mode0 = 0; + } + + WRITECSR(sc, R_CSR_SIAMODE0, 0xEF00 | mode0 | M_CSR13_CONN_NOT_RESET ); + + sc->loopback = mode; +} + +static void +dc21041_hwinit(tulip_softc *sc, uint8_t srom[]) +{ + uint32_t v; + + sc->phy_type = SRL; + + /* CSR0 - bus mode */ + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#ifdef __MIPSEB + v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */ +#endif + WRITECSR(sc, R_CSR_BUSMODE, v); + + WRITECSR(sc, R_CSR_INTMASK, 0); + + WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start)); + WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start)); + + /* For now, always force 10BT, HDX (21041, Table 3-62) */ + dc21041_set_speed(sc, ETHER_SPEED_10HDX); +} + + +static void +dc21040_set_speed(tulip_softc *sc, int speed) +{ + uint32_t opmode = 0; + + WRITECSR(sc, R_CSR_SIAMODE0, 0); + + /* For now, force 10BT, HDX unless FDX requested (21040, Table 3-53) */ + switch (speed) { + case ETHER_SPEED_10HDX: + default: + WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFF); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0000); + opmode = 0; + break; + case ETHER_SPEED_10FDX: + WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFD); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0000); + opmode = M_CSR6_FULLDUPLEX; + break; + } + + WRITECSR(sc, R_CSR_SIAMODE0, 0xEF00 | M_CSR13_CONN_NOT_RESET); + cfe_sleep(CFE_HZ/10); + + opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72); + WRITECSR(sc, R_CSR_OPMODE, opmode); +} + +static void +dc21040_set_loopback(tulip_softc *sc, int mode) +{ + WRITECSR(sc, R_CSR_SIAMODE0, 0); + cfe_sleep(CFE_HZ/10); /* check this */ + + /* Update the SIA registers */ + if (mode == ETHER_LOOPBACK_EXT) { + /* NB: this is on-chip loopback through the 10BT endec */ + WRITECSR(sc, R_CSR_SIAMODE1, 0xFEFB); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0008); + } + else if (mode == ETHER_LOOPBACK_INT) { + /* MAC internal loopback, no SIA */ + WRITECSR(sc, R_CSR_SIAMODE1, 0x0000); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0000); + } + else { + mode = ETHER_LOOPBACK_OFF; + WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFF); + WRITECSR(sc, R_CSR_SIAMODE2, 0x0000); + } + + WRITECSR(sc, R_CSR_SIAMODE0, 0x8F00 | M_CSR13_CONN_NOT_RESET ); + + sc->loopback = mode; +} + +static void +dc21040_hwinit(tulip_softc *sc, uint8_t srom[]) +{ + uint32_t v; + + sc->phy_type = SRL; + + /* CSR0 - bus mode */ + v = V_CSR0_SKIPLEN(0) | + V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) | + V_CSR0_BURSTLEN(K_CSR0_BURST32); +#ifdef __MIPSEB + v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */ +#endif + WRITECSR(sc, R_CSR_BUSMODE, v); + + WRITECSR(sc, R_CSR_INTMASK, 0); + + dc21040_set_speed(sc, sc->linkspeed); +} + + +static void +tulip_hwinit(tulip_softc *sc) +{ + if (sc->state == eth_state_uninit) { + uint8_t srom[SROM_SIZE]; + + /* Wake-on-LAN apparently powers up with PORTSEL = 1 */ + WRITECSR(sc, R_CSR_OPMODE, + READCSR(sc, R_CSR_OPMODE) &~ M_CSR6_PORTSEL); + + RESET_ADAPTER(sc); + sc->state = eth_state_off; + sc->bus_errors = 0; + + rom_read_all(sc, srom); /* XXX read just once? */ + rom_dump(srom); + + switch (sc->device) { + case K_PCI_ID_DC21040: + dc21040_hwinit(sc, srom); + break; + case K_PCI_ID_DC21041: + dc21041_hwinit(sc, srom); + break; + case K_PCI_ID_DC21140: + dc21140_hwinit(sc, srom); + break; + case K_PCI_ID_DC21143: + dc21143_hwinit(sc, srom); + break; + default: + break; + } + } +} + +static void +tulip_setaddr(tulip_softc *sc) +{ + int idx; + tulip_cam *cam; + eth_pkt_t *pkt; + + pkt = eth_alloc_pkt(sc); + if (pkt) { + pkt->length = CAM_SETUP_BUFFER_SIZE; + cam = (tulip_cam *) pkt->buffer; + +#ifdef __MIPSEB + cam->p.physical[0][0] = (((uint32_t) sc->hwaddr[0] << 8) | + (uint32_t) sc->hwaddr[1]) << 16; + cam->p.physical[0][1] = (((uint32_t) sc->hwaddr[2] << 8) | + (uint32_t) sc->hwaddr[3]) << 16; + cam->p.physical[0][2] = (((uint32_t) sc->hwaddr[4] << 8) | + (uint32_t) sc->hwaddr[5]) << 16; + for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) { + cam->p.physical[idx][0] = 0xFFFF0000; + cam->p.physical[idx][1] = 0xFFFF0000; + cam->p.physical[idx][2] = 0xFFFF0000; + } +#else + cam->p.physical[0][0] = ((uint32_t) sc->hwaddr[0]) | + (((uint32_t) sc->hwaddr[1]) << 8); + cam->p.physical[0][1] = ((uint32_t) sc->hwaddr[2]) | + (((uint32_t) sc->hwaddr[3]) << 8); + cam->p.physical[0][2] = ((uint32_t) sc->hwaddr[4]) | + (((uint32_t) sc->hwaddr[5]) << 8); + for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) { + cam->p.physical[idx][0] = 0x0000FFFF; + cam->p.physical[idx][1] = 0x0000FFFF; + cam->p.physical[idx][2] = 0x0000FFFF; + } +#endif + + pkt->flags |= ETH_TX_SETUP; + sc->state = eth_state_setup; + if (tulip_transmit(sc, pkt) != 0) { + xprintf("%s: failed setup\n", tulip_devname(sc)); + dumpstat(sc); + eth_free_pkt(sc, pkt); + } + } +} + +static void +tulip_setspeed(tulip_softc *sc, int speed) +{ + switch (sc->device) { + case K_PCI_ID_DC21040: + dc21040_set_speed(sc, speed); + break; + case K_PCI_ID_DC21041: + dc21041_set_speed(sc, speed); + break; + case K_PCI_ID_DC21140: + dc21140_set_speed(sc, speed, 0); + break; + case K_PCI_ID_DC21143: + dc21143_set_speed(sc, speed); + break; + default: + break; + } +} + +static void +tulip_setloopback(tulip_softc *sc, int mode) +{ + switch (sc->device) { + case K_PCI_ID_DC21040: + dc21040_set_loopback(sc, mode); + break; + case K_PCI_ID_DC21041: + dc21041_set_loopback(sc, mode); + break; + case K_PCI_ID_DC21140: + dc21140_set_loopback(sc, mode); + break; + case K_PCI_ID_DC21143: + dc21143_set_loopback(sc, mode); + break; + default: + break; + } + cfe_sleep(CFE_HZ/10); +} + + +static void +tulip_isr(void *arg) +{ + uint32_t status; + uint32_t csr5; + tulip_softc *sc = (tulip_softc *)arg; + +#if IPOLL + sc->interrupts++; +#endif + + for (;;) { + + /* Read the interrupt status. */ + csr5 = READCSR(sc, R_CSR_STATUS); + status = csr5 & ( + M_CSR5_RXINT | M_CSR5_RXBUFUNAVAIL | + M_CSR5_TXINT | M_CSR5_TXUNDERFLOW | + M_CSR5_FATALBUSERROR); + + /* if there are no more interrupts, leave now. */ + if (status == 0) break; + + /* Clear the pending interrupt. */ + WRITECSR(sc, R_CSR_STATUS, status); + + /* Now, test each unmasked bit in the interrupt register and + handle each interrupt type appropriately. */ + + if (status & M_CSR5_FATALBUSERROR) { + WRITECSR(sc, R_CSR_INTMASK, 0); + + xprintf("%s: bus error %02x\n", + tulip_devname(sc), G_CSR5_ERRORBITS(csr5)); + dumpstat(sc); + sc->bus_errors++; + if (sc->bus_errors >= 2) { + dumpcsrs(sc); + RESET_ADAPTER(sc); + sc->state = eth_state_off; + sc->bus_errors = 0; + } +#if IPOLL + else + WRITECSR(sc, R_CSR_INTMASK, sc->intmask); +#endif + } + + if (status & M_CSR5_RXINT) { +#if IPOLL + sc->rx_interrupts++; +#endif + tulip_procrxring(sc); + } + + if (status & M_CSR5_TXINT) { +#if IPOLL + sc->tx_interrupts++; +#endif + tulip_proctxring(sc); + } + + if (status & (M_CSR5_TXUNDERFLOW | M_CSR5_RXBUFUNAVAIL)) { + if (status & M_CSR5_TXUNDERFLOW) { + xprintf("%s: tx underrun, %08x\n", tulip_devname(sc), csr5); + /* Try to restart */ + WRITECSR(sc, R_CSR_TXPOLL, 1); + } + if (status & M_CSR5_RXBUFUNAVAIL) { + /* Try to restart */ + WRITECSR(sc, R_CSR_RXPOLL, 1); + } + } + } +} + + +static void +tulip_start(tulip_softc *sc) +{ + uint32_t opmode; + + tulip_hwinit(sc); + + WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start)); + WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start)); + + opmode = READCSR(sc, R_CSR_OPMODE); + opmode &=~ M_CSR6_OPMODE; /* no loopback */ + if (sc->loopback != ETHER_LOOPBACK_OFF) { + opmode &=~ M_CSR6_FULLDUPLEX; + opmode |= M_CSR6_PORTSEL; + if (sc->loopback == ETHER_LOOPBACK_EXT) + opmode |= M_CSR6_EXTLOOPBACK; + else + opmode |= M_CSR6_INTLOOPBACK; + } + + sc->intmask = 0; + WRITECSR(sc, R_CSR_INTMASK, 0); /* no interrupts */ + WRITECSR(sc, R_CSR_STATUS, 0x1FFFF); /* clear any pending */ + READCSR(sc, R_CSR_STATUS); /* push the write */ + + sc->interrupts = 0; + sc->rx_interrupts = sc->tx_interrupts = 0; + +#if IPOLL + cfe_request_irq(sc->irq, tulip_isr, sc, CFE_IRQ_FLAGS_SHARED, 0); + + sc->intmask = M_CSR7_RXINT | M_CSR7_TXINT | + M_CSR7_NORMALINT; + sc->intmask |= M_CSR7_FATALBUSERROR | M_CSR7_TXUNDERFLOW | + M_CSR7_ABNORMALINT; + WRITECSR(sc, R_CSR_INTMASK, sc->intmask); +#endif + + if (sc->loopback == ETHER_LOOPBACK_OFF) { + opmode |= M_CSR6_TXSTART; + WRITECSR(sc, R_CSR_OPMODE, opmode); + tulip_setaddr(sc); + } + else { + opmode |= M_CSR6_TXSTART | M_CSR6_RXSTART; + WRITECSR(sc, R_CSR_OPMODE, opmode); + } +} + +static void +tulip_stop(tulip_softc *sc) +{ + uint32_t opmode; + uint32_t status; + int count; + + WRITECSR(sc, R_CSR_INTMASK, 0); + sc->intmask = 0; +#if IPOLL + cfe_free_irq(sc->irq, 0); +#endif + WRITECSR(sc, R_CSR_STATUS, 0x1FFFF); + opmode = READCSR(sc, R_CSR_OPMODE); + opmode &=~ (M_CSR6_TXSTART | M_CSR6_RXSTART); + WRITECSR(sc, R_CSR_OPMODE, opmode); + + /* wait for any DMA activity to terminate */ + for (count = 0; count <= 13; count++) { + status = READCSR(sc, R_CSR_STATUS); + if ((status & (M_CSR5_RXPROCSTATE | M_CSR5_TXPROCSTATE)) == 0) + break; + cfe_sleep(CFE_HZ/10); + } + if (count > 13) { + xprintf("%s: idle state not achieved\n", tulip_devname(sc)); + dumpstat(sc); + RESET_ADAPTER(sc); + sc->state = eth_state_uninit; +#if 1 + sc->linkspeed = ETHER_SPEED_AUTO; +#endif + } + else if (sc->loopback != ETHER_LOOPBACK_OFF) { + tulip_setloopback(sc, ETHER_LOOPBACK_OFF); + opmode &=~ M_CSR6_OPMODE; + WRITECSR(sc, R_CSR_OPMODE, opmode); + } + + if (sc->outpkts > 1) { + /* heuristic: suppress stats for initial mode changes */ + xprintf("%s: %d sent, %d received, %d interrupts\n", + tulip_devname(sc), sc->outpkts, sc->inpkts, sc->interrupts); + xprintf(" %d rx interrupts, %d tx interrupts\n", + sc->rx_interrupts, sc->tx_interrupts); + } +} + + +/* ********************************************************************* + * ETH_PARSE_XDIGIT(c) + * + * Parse a hex digit, returning its value + * + * Input parameters: + * c - character + * + * Return value: + * hex value, or -1 if invalid + ********************************************************************* */ +static int +eth_parse_xdigit(char c) +{ + int digit; + + if ((c >= '0') && (c <= '9')) digit = c - '0'; + else if ((c >= 'a') && (c <= 'f')) digit = c - 'a' + 10; + else if ((c >= 'A') && (c <= 'F')) digit = c - 'A' + 10; + else digit = -1; + + return digit; +} + +/* ********************************************************************* + * ETH_PARSE_HWADDR(str,hwaddr) + * + * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte + * Ethernet address. + * + * Input parameters: + * str - string + * hwaddr - pointer to hardware address + * + * Return value: + * 0 if ok, else -1 + ********************************************************************* */ +static int +eth_parse_hwaddr(char *str, uint8_t *hwaddr) +{ + int digit1, digit2; + int idx = ENET_ADDR_LEN; + + while (*str && (idx > 0)) { + digit1 = eth_parse_xdigit(*str); + if (digit1 < 0) return -1; + str++; + if (!*str) return -1; + + if ((*str == ':') || (*str == '-')) { + digit2 = digit1; + digit1 = 0; + } + else { + digit2 = eth_parse_xdigit(*str); + if (digit2 < 0) return -1; + str++; + } + + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + + if ((*str == ':') || (*str == '-')) + str++; + } + return 0; +} + +/* ********************************************************************* + * ETH_INCR_HWADDR(hwaddr,incr) + * + * Increment a 6-byte Ethernet hardware address, with carries + * + * Input parameters: + * hwaddr - pointer to hardware address + * incr - desired increment + * + * Return value: + * none + ********************************************************************* */ +static void +eth_incr_hwaddr(uint8_t *hwaddr, unsigned incr) +{ + int idx; + int carry; + + idx = 5; + carry = incr; + while (idx >= 0 && carry != 0) { + unsigned sum = hwaddr[idx] + carry; + + hwaddr[idx] = sum & 0xFF; + carry = sum >> 8; + idx--; + } +} + + +/* ********************************************************************* + * Declarations for CFE Device Driver Interface routines + ********************************************************************* */ + +static int tulip_ether_open(cfe_devctx_t *ctx); +static int tulip_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tulip_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int tulip_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tulip_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tulip_ether_close(cfe_devctx_t *ctx); +#if 0 +static void tulip_ether_reset(void *softc); +#endif + +/* ********************************************************************* + * CFE Device Driver dispatch structure + ********************************************************************* */ + +const static cfe_devdisp_t tulip_ether_dispatch = { + tulip_ether_open, + tulip_ether_read, + tulip_ether_inpstat, + tulip_ether_write, + tulip_ether_ioctl, + tulip_ether_close, + NULL, /* tulip_ether_poll */ + NULL /* tulip_ether_reset */ +}; + +/* ********************************************************************* + * CFE Device Driver descriptor + ********************************************************************* */ + +const cfe_driver_t dc21143drv = { + "DC21x4x Ethernet", + "eth", + CFE_DEV_NETWORK, + &tulip_ether_dispatch, + tulip_ether_probe +}; + + +static int +tulip_ether_attach(cfe_driver_t *drv, + pcitag_t tag, int index, uint8_t hwaddr[]) +{ + tulip_softc *softc; + uint32_t device; + uint32_t class; + uint32_t reg; + phys_addr_t pa; + const char *devname; + char descr[100]; + uint8_t romaddr[ENET_ADDR_LEN]; + + device = pci_conf_read(tag, R_CFG_CFID); + class = pci_conf_read(tag, R_CFG_CFRV); + + reg = pci_conf_read(tag, R_CFG_CPMS); + + reg = pci_conf_read(tag, R_CFG_CFDD); + pci_conf_write(tag, R_CFG_CFDD, 0); + reg = pci_conf_read(tag, R_CFG_CFDD); + +#if 1 + /* Use memory space for the CSRs */ + pci_map_mem(tag, R_CFG_CBMA, PCI_MATCH_BITS, &pa); +#else + /* Use i/o space for the CSRs */ + pci_map_io(tag, R_CFG_CBIO, PCI_MATCH_BITS, &pa); +#endif + + softc = (tulip_softc *) KMALLOC(sizeof(tulip_softc), 0); + if (softc == NULL) { + xprintf("DC21x4x: No memory to complete probe\n"); + return 0; + } + memset(softc, 0, sizeof(*softc)); + + softc->membase = (uint32_t)pa; + softc->irq = pci_conf_read(tag, R_CFG_CFIT) & 0xFF; + + softc->tag = tag; + softc->device = PCI_PRODUCT(device); + softc->revision = PCI_REVISION(class); + softc->devctx = NULL; + +#if 1 + softc->linkspeed = ETHER_SPEED_AUTO; /* select autonegotiation */ +#else + softc->linkspeed = ETHER_SPEED_100FDX; /* 100 Mbps, full duplex */ +#endif + softc->loopback = ETHER_LOOPBACK_OFF; + memcpy(softc->hwaddr, hwaddr, ENET_ADDR_LEN); + + tulip_init(softc); + + /* Prefer address in srom */ + if (rom_read_addr(softc, romaddr) == 0) { + memcpy(softc->hwaddr, romaddr, ENET_ADDR_LEN); + } + + softc->state = eth_state_uninit; + + switch (PCI_PRODUCT(device)) { + case K_PCI_ID_DC21040: + devname = "DC21040"; break; + case K_PCI_ID_DC21041: + devname = "DC21041"; break; + case K_PCI_ID_DC21140: + devname = "DC21140"; break; + case K_PCI_ID_DC21143: + devname = "DC21143"; break; + default: + devname = "DC21x4x"; break; + } + + xsprintf(descr, "%s Ethernet at 0x%X (%02X-%02X-%02X-%02X-%02X-%02X)", + devname, softc->membase, + softc->hwaddr[0], softc->hwaddr[1], softc->hwaddr[2], + softc->hwaddr[3], softc->hwaddr[4], softc->hwaddr[5]); + + cfe_attach(drv, softc, NULL, descr); + return 1; +} + + +/* ********************************************************************* + * TULIP_ETHER_PROBE(drv,probe_a,probe_b,probe_ptr) + * + * Probe and install drivers for all DC21x4x Ethernet controllers. + * For each, create a context structure and attach to the + * specified network device. + * + * Input parameters: + * drv - driver descriptor + * probe_a - not used + * probe_b - not used + * probe_ptr - string pointer to hardware address for the first + * MAC, in the form xx:xx:xx:xx:xx:xx + * + * Return value: + * nothing + ********************************************************************* */ +static void +tulip_ether_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + int index; + int n; + uint8_t hwaddr[ENET_ADDR_LEN]; + + if (probe_ptr) + eth_parse_hwaddr((char *) probe_ptr, hwaddr); + else { + /* use default address 40-00-00-10-11-11 */ + hwaddr[0] = 0x40; hwaddr[1] = 0x00; hwaddr[2] = 0x00; + hwaddr[3] = 0x10; hwaddr[4] = 0x11; hwaddr[5] = 0x11; + } + + n = 0; + index = 0; + for (;;) { + pcitag_t tag; + pcireg_t device; + + if (pci_find_class(PCI_CLASS_NETWORK, index, &tag) != 0) + break; + + index++; + + device = pci_conf_read(tag, R_CFG_CFID); + if (PCI_VENDOR(device) == K_PCI_VENDOR_DEC) { +#if 0 /* this currently (2.1.1) generates a bad code in PIC mode */ + switch (PCI_PRODUCT(device)) { + case K_PCI_ID_DC21040: + case K_PCI_ID_DC21041: + case K_PCI_ID_DC21140: + case K_PCI_ID_DC21143: + tulip_ether_attach(drv, tag, n, hwaddr); + n++; + eth_incr_hwaddr(hwaddr, 1); + break; + default: + break; + } +#else + if (PCI_PRODUCT(device) == K_PCI_ID_DC21040 || + PCI_PRODUCT(device) == K_PCI_ID_DC21041 || + PCI_PRODUCT(device) == K_PCI_ID_DC21140 || + PCI_PRODUCT(device) == K_PCI_ID_DC21143) { + + tulip_ether_attach(drv, tag, n, hwaddr); + n++; + eth_incr_hwaddr(hwaddr, 1); + } +#endif + } + } +} + + +/* The functions below are called via the dispatch vector for the 21x4x. */ + +/* ********************************************************************* + * TULIP_ETHER_OPEN(ctx) + * + * Open the Ethernet device. The MAC is reset, initialized, and + * prepared to receive and send packets. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_open(cfe_devctx_t *ctx) +{ + tulip_softc *softc = ctx->dev_softc; + + if (softc->state == eth_state_on) + tulip_stop(softc); + + softc->devctx = ctx; + tulip_start(softc); + +#if XPOLL + tulip_isr(softc); +#endif + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_READ(ctx,buffer) + * + * Read a packet from the Ethernet device. If no packets are + * available, the read will succeed but return 0 bytes. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tulip_softc *softc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + +#if XPOLL + tulip_isr(softc); +#endif + + if (softc->state != eth_state_on) return -1; + + CS_ENTER(softc); + pkt = (eth_pkt_t *) q_deqnext(&(softc->rxqueue)); + CS_EXIT(softc); + + if (pkt == NULL) { + buffer->buf_retlen = 0; + return 0; + } + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + blockcopy(buffer->buf_ptr, pkt->buffer, blen); + buffer->buf_retlen = blen; + + eth_free_pkt(softc, pkt); + tulip_fillrxring(softc); + +#if XPOLL + tulip_isr(softc); +#endif + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_INPSTAT(ctx,inpstat) + * + * Check for received packets on the Ethernet device + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * inpstat - pointer to input status structure + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + tulip_softc *softc = ctx->dev_softc; + +#if XPOLL + tulip_isr(softc); +#endif + + if (softc->state != eth_state_on) return -1; + + /* We avoid an interlock here because the result is a hint and an + interrupt cannot turn a non-empty queue into an empty one. */ + inpstat->inp_status = (q_isempty(&(softc->rxqueue))) ? 0 : 1; + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_WRITE(ctx,buffer) + * + * Write a packet to the Ethernet device. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tulip_softc *softc = ctx->dev_softc; + eth_pkt_t *pkt; + int blen; + +#if XPOLL + tulip_isr(softc); +#endif + + if (softc->state != eth_state_on) return -1; + + pkt = eth_alloc_pkt(softc); + if (!pkt) return CFE_ERR_NOMEM; + + blen = buffer->buf_length; + if (blen > pkt->length) blen = pkt->length; + + blockcopy(pkt->buffer, buffer->buf_ptr, blen); + pkt->length = blen; + + if (tulip_transmit(softc, pkt) != 0) { + eth_free_pkt(softc,pkt); + return CFE_ERR_IOERR; + } + +#if XPOLL + tulip_isr(softc); +#endif + + return 0; +} + +/* ********************************************************************* + * TULIP_ETHER_IOCTL(ctx,buffer) + * + * Do device-specific I/O control operations for the device + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * buffer - pointer to buffer descriptor. + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tulip_softc *softc = ctx->dev_softc; + int *argp; + int mode; + int speed; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_ETHER_GETHWADDR: + memcpy(buffer->buf_ptr, softc->hwaddr, sizeof(softc->hwaddr)); + return 0; + + case IOCTL_ETHER_SETHWADDR: + return -1; /* not supported */ + + case IOCTL_ETHER_GETSPEED: + argp = (int *) buffer->buf_ptr; + *argp = softc->linkspeed; + return 0; + + case IOCTL_ETHER_SETSPEED: + tulip_stop(softc); + tulip_resetrings(softc); + speed = *((int *) buffer->buf_ptr); + tulip_setspeed(softc, speed); + tulip_start(softc); + softc->state = eth_state_on; + return 0; + + case IOCTL_ETHER_GETLINK: + argp = (int *) buffer->buf_ptr; + *argp = softc->linkspeed; + return 0; + + case IOCTL_ETHER_GETLOOPBACK: + *((int *) buffer) = softc->loopback; + return 0; + + case IOCTL_ETHER_SETLOOPBACK: + tulip_stop(softc); + tulip_resetrings(softc); + mode = *((int *) buffer->buf_ptr); + softc->loopback = ETHER_LOOPBACK_OFF; /* default */ + if (mode == ETHER_LOOPBACK_INT || mode == ETHER_LOOPBACK_EXT) { + tulip_setloopback(softc, mode); + } + tulip_start(softc); + softc->state = eth_state_on; + return 0; + + default: + return -1; + } +} + +/* ********************************************************************* + * TULIP_ETHER_CLOSE(ctx) + * + * Close the Ethernet device. + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * + * Return value: + * status, 0 = ok + ********************************************************************* */ +static int +tulip_ether_close(cfe_devctx_t *ctx) +{ + tulip_softc *softc = ctx->dev_softc; + + softc->state = eth_state_off; + tulip_stop(softc); + + /* resynchronize descriptor rings */ + tulip_resetrings(softc); + + softc->devctx = NULL; + return 0; +} + + +#if 0 +/* ********************************************************************* + * TULIP_ETHER_POLL(ctx,ticks) + * + * TBD + * + * Input parameters: + * ctx - device context (includes ptr to our softc) + * ticks- current time in ticks + * + * Return value: + * nothing + ********************************************************************* */ + +static void +tulip_ether_poll(cfe_devctx_t *ctx, int64_t ticks) +{ +} + +/* ********************************************************************* + * TULIP_ETHER_RESET(softc) + * + * This routine is called when CFE is restarted after a + * program exits. We can clean up pending I/Os here. + * + * Input parameters: + * softc - pointer to tulip_softc + * + * Return value: + * nothing + ********************************************************************* */ + +static void +tulip_ether_reset(void *softc) +{ + tulip_softc *sc = (tulip_softc *)softc; + + /* Turn off the Ethernet interface. */ + + RESET_ADAPTER(sc); +} +#endif diff --git a/cfe/cfe/dev/dp83815.h b/cfe/cfe/dev/dp83815.h new file mode 100644 index 0000000..1d50422 --- /dev/null +++ b/cfe/cfe/dev/dp83815.h @@ -0,0 +1,559 @@ +/* + * Register and bit definitions for the National Semiconductor + * DP83815 10/100 Integrated Ethernet MAC and PHY. + * Reference: + * DP83815 10/100 Mb/s Integrated PCI Ethernet Media Access + * Controller and Physical Layer (MacPhyter) + * Hardware Reference Manual, Revision 1.0. + * National Semiconductor Corp., December 2000 + */ +#ifndef _DP83815_H_ +#define _DP83815_H_ + +#define _DD_MAKEMASK1(n) (1 << (n)) +#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n)) +#define _DD_MAKEVALUE(v,n) ((v) << (n)) +#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n)) + + +/* PCI Configuration Register offsets (MacPhyter nomenclature) */ + +#define R_CFGID PCI_ID_REG +#define K_PCI_VENDOR_NSC 0x100B +#define K_PCI_ID_DP83815 0x0020 + +#define R_CFGCS PCI_COMMAND_STATUS_REG +#define R_CFGRID PCI_CLASS_REG +#define R_CFGLAT PCI_BHLC_REG + +#define R_CFGIOA PCI_MAPREG(0) +#define R_CFGMA PCI_MAPREG(1) + +#define R_CFGSID PCI_SUBSYS_ID_REG +#define R_CFGROM PCI_MAPREG_ROM +#define R_CAPPTR PCI_CAPLISTPTR_REG +#define R_CFGINT PCI_BPARAM_INTERRUPT_REG + +/* Power management capability */ +#define R_PMCAP 0x40 +#define R_PMCSR 0x44 + + +/* MacPhyter Operational Register offsets */ + +#define R_CR 0x00 +#define R_CFG 0x04 +#define R_MEAR 0x08 +#define R_PTSCR 0x0C +#define R_ISR 0x10 +#define R_IMR 0x14 +#define R_IER 0x18 +#define R_TXDP 0x20 +#define R_TXCFG 0x24 +#define R_RXDP 0x30 +#define R_RXCFG 0x34 +#define R_CCSR 0x3C +#define R_WCSR 0x40 +#define R_PCR 0x44 +#define R_RFCR 0x48 +#define R_RFDR 0x4C +#define R_BRAR 0x50 +#define R_BRDR 0x54 +#define R_SRR 0x58 +#define R_MIBC 0x5C +#define R_MIB(n) (0x60+4*(n)) + +/* MacPhyter MIB Registers */ + +#define R_MIB_RXErroredPkts R_MIB(0) +#define R_MIB_RXFCSErrors R_MIB(1) +#define R_MIB_RXMsdPktErrors R_MIB(2) +#define R_MIB_RXFAErrors R_MIB(3) +#define R_MIB_RXSymbolErrors R_MIB(4) +#define R_MIB_RXFrameTooLong R_MIB(5) +#define R_MIB_TXSQEErrors R_MIB(6) + +#define N_MIB_REGISTERS 7 + + +/* MacPhyter Internal PHY Register offsets */ + +#define R_BMCR 0x80 +#define R_BMSR 0x84 +#define R_PHYIDR1 0x88 +#define R_PHYIDR2 0x8C +#define R_ANAR 0x90 +#define R_ANLPAR 0x94 +#define R_ANER 0x98 +#define R_ANNPTR 0x9C +#define R_PHYSTS 0xC0 +#define R_MICR 0xC4 +#define R_MISR 0xC8 +#define R_FCSCR 0xD0 +#define R_RECR 0xD4 +#define R_PHYCR 0xE4 +#define R_TBTSCR 0xE8 + +/* Undocumented, updated for CVNG (SRR=0x0302) parts */ + +#define R_PGSEL 0xCC +#define R_PMDCSR 0xE4 /* R_PHYCR */ +#define R_DSPCFG 0xF4 +#define R_SDCFG 0xF8 +#define R_TSTDAT 0xFC + + +/* 0x00 CR: Command Register */ + +#define M_CR_TXE _DD_MAKEMASK1(0) +#define M_CR_TXD _DD_MAKEMASK1(1) +#define M_CR_RXE _DD_MAKEMASK1(2) +#define M_CR_RXD _DD_MAKEMASK1(3) +#define M_CR_TXR _DD_MAKEMASK1(4) +#define M_CR_RXR _DD_MAKEMASK1(5) +#define M_CR_SWI _DD_MAKEMASK1(7) +#define M_CR_RST _DD_MAKEMASK1(8) + + +/* 0x04 CFG: Configuration and Media Status Register */ + +#define M_CFG_BEM _DD_MAKEMASK1(0) +#define M_CFG_BROM_DIS _DD_MAKEMASK1(2) +#define M_CFG_PESEL _DD_MAKEMASK1(3) +#define M_CFG_EXD _DD_MAKEMASK1(4) +#define M_CFG_POW _DD_MAKEMASK1(5) +#define M_CFG_SB _DD_MAKEMASK1(6) +#define M_CFG_REQALG _DD_MAKEMASK1(7) +#define M_CFG_EUPHCOMP _DD_MAKEMASK1(8) +#define M_CFG_PHY_DIS _DD_MAKEMASK1(9) +#define M_CFG_PHY_RST _DD_MAKEMASK1(10) +#define M_CFG_EXT_PHY _DD_MAKEMASK1(12) + +#define S_CFG_ANEG_SEL 13 +#define M_CFG_ANEG_SEL _DD_MAKEMASK(3,S_CFG_ANEG_SEL) +#define V_CFG_ANEG_SEL(x) _DD_MAKEVALUE(x,S_CFG_ANEG_SEL) +#define G_CFG_ANEG_SEL(x) _DD_GETVALUE(x,S_CFG_ANEG_SEL,M_CFG_ANEG_SEL) + +#define K_ANEG_10H 0x0 +#define K_ANEG_100H 0x2 +#define K_ANEG_10F 0x4 +#define K_ANEG_100F 0x6 +#define K_ANEG_10HF 0x1 +#define K_ANEG_10H_100H 0x3 +#define K_ANEG_100HF 0x5 +#define K_ANEG_10HF_100HF 0x7 +#define K_ANEG_ALL 0x7 + +#define M_CFG_PAUSE_ADV _DD_MAKEMASK1(16) +#define M_CFG_PINT_ACEN _DD_MAKEMASK1(17) + +#define S_CFG_PHY_CFG 18 +#define M_CFG_PHY_CFG _DD_MAKEMASK(6,S_CFG_PHY_CFG) + +#define M_CFG_ANEG_DN _DD_MAKEMASK1(27) +#define M_CFG_POL _DD_MAKEMASK1(28) +#define M_CFG_FDUP _DD_MAKEMASK1(29) +#define M_CFG_SPEED100 _DD_MAKEMASK1(30) +#define M_CFG_LNKSTS _DD_MAKEMASK1(31) +#define M_CFG_LNKSUMMARY (M_CFG_LNKSTS | M_CFG_SPEED100 | M_CFG_FDUP) + + +/* 0x08 MEAR: EEPROM Access Register (see 4.2.4 for EEPROM Map) */ + +#define M_MEAR_EEDI _DD_MAKEMASK1(0) +#define M_MEAR_EEDO _DD_MAKEMASK1(1) +#define M_MEAR_EECLK _DD_MAKEMASK1(2) +#define M_MEAR_EESEL _DD_MAKEMASK1(3) +#define M_MEAR_MDIO _DD_MAKEMASK1(4) +#define M_MEAR_MDDIR _DD_MAKEMASK1(5) +#define M_MEAR_MDC _DD_MAKEMASK1(6) + + +/* 0x0C PTSCR: PCI Test Control Register */ + +#define M_PTSCR_EEBIST_FAIL _DD_MAKEMASK1(0) +#define M_PTSCR_EEBIST_EN _DD_MAKEMASK1(1) +#define M_PTSCR_EELOAD_EN _DD_MAKEMASK1(2) +#define M_PTSCR_RBIST_RXFFAIL _DD_MAKEMASK1(3) +#define M_PTSCR_RBIST_TXFAIL _DD_MAKEMASK1(4) +#define M_PTSCR_RBIST_RXFAIL _DD_MAKEMASK1(5) +#define M_PTSCR_RBIST_DONE _DD_MAKEMASK1(6) +#define M_PTSCR_RBIST_EN _DD_MAKEMASK1(7) +#define M_PTSCR_MBZ8 _DD_MAKEMASK1(8) +#define M_PTSCR_MBZ9 _DD_MAKEMASK1(9) +#define M_PTSCR_RBIST_RST _DD_MAKEMASK1(10) +#define M_PTSCR_MBZ12 _DD_MAKEMASK1(12) + + +/* 0x10 ISR: Interrupt Status Register */ +/* 0x14 IMR: Interrupt Mask Register */ + +#define M_INT_RXOK _DD_MAKEMASK1(0) +#define M_INT_RXDESC _DD_MAKEMASK1(1) +#define M_INT_RXERR _DD_MAKEMASK1(2) +#define M_INT_RXEARLY _DD_MAKEMASK1(3) +#define M_INT_RXIDLE _DD_MAKEMASK1(4) +#define M_INT_RXORN _DD_MAKEMASK1(5) +#define M_INT_TXOK _DD_MAKEMASK1(6) +#define M_INT_TXDESC _DD_MAKEMASK1(7) +#define M_INT_TXERR _DD_MAKEMASK1(8) +#define M_INT_TXIDLE _DD_MAKEMASK1(9) +#define M_INT_TXURN _DD_MAKEMASK1(10) +#define M_INT_MIB _DD_MAKEMASK1(11) +#define M_INT_SWI _DD_MAKEMASK1(12) +#define M_INT_PME _DD_MAKEMASK1(13) +#define M_INT_PHY _DD_MAKEMASK1(14) +#define M_INT_HIBERR _DD_MAKEMASK1(15) +#define M_INT_RXSOVR _DD_MAKEMASK1(16) +#define M_INT_RTABT _DD_MAKEMASK1(20) +#define M_INT_RMABT _DD_MAKEMASK1(21) +#define M_INT_SSERR _DD_MAKEMASK1(22) +#define M_INT_DPERR _DD_MAKEMASK1(23) +#define M_INT_RXRCMP _DD_MAKEMASK1(24) +#define M_INT_TXRCMP _DD_MAKEMASK1(25) + + +/* 0x18 IER: Interrupt Enable Register */ + +#define M_IER_IE _DD_MAKEMASK1(0) + + +/* 0x20 TXDP: Transmit Descriptor Pointer Register */ + + +/* 0x24 TXCFG: Transmit Configuration Register */ + +#define S_TXCFG_DRTH 0 +#define M_TXCFG_DRTH _DD_MAKEMASK(6,S_TXCFG_DRTH) +#define V_TXCFG_DRTH(x) _DD_MAKEVALUE(x,S_TXCFG_DRTH) +#define G_TXCFG_DRTH(x) _DD_GETVALUE(x,S_TXCFG_DRTH,M_TXCFG_DRTH) + +#define S_TXCFG_FLTH 8 +#define M_TXCFG_FLTH _DD_MAKEMASK(6,S_TXCFG_FLTH) +#define V_TXCFG_FLTH(x) _DD_MAKEVALUE(x,S_TXCFG_FLTH) +#define G_TXCFG_FLTH(x) _DD_GETVALUE(x,S_TXCFG_FLTH,M_TXCFG_FLTH) + +#define S_TXCFG_MXDMA 20 +#define M_TXCFG_MXDMA _DD_MAKEMASK(3,S_TXCFG_MXDMA) +#define V_TXCFG_MXDMA(x) _DD_MAKEVALUE(x,S_TXCFG_MXDMA) +#define G_TXCFG_MXDMA(x) _DD_GETVALUE(x,S_TXCFG_MXDMA,M_TXCFG_MXDMA) + +/* Max DMA burst size (bytes) - RX also */ +#define K_MXDMA_512 0x0 +#define K_MXDMA_4 0x1 +#define K_MXDMA_8 0x2 +#define K_MXDMA_16 0x3 +#define K_MXDMA_32 0x4 +#define K_MXDMA_64 0x5 +#define K_MXDMA_128 0x6 +#define K_MXDMA_256 0x7 + +#define M_TXCFG_ECRETRY _DD_MAKEMASK1(23) + +#define S_TXCFG_IFG 26 +#define M_TXCFG_IFG _DD_MAKEMASK(2,S_TXCFG_IFG) +#define V_TXCFG_IFG(x) _DD_MAKEVALUE(x,S_TXCFG_IFG) +#define G_TXCFG_IFG(x) _DD_GETVALUE(x,S_TXCFG_IFG,M_TXCFG_IFG) + +#define M_TXCFG_ATP _DD_MAKEMASK1(28) +#define M_TXCFG_MLB _DD_MAKEMASK1(29) +#define M_TXCFG_HBI _DD_MAKEMASK1(30) +#define M_TXCFG_CSI _DD_MAKEMASK1(31) + + +/* 0x30 RXDP: Receive Descriptor Pointer Register */ + + +/* 0x34 RXCFG: Receive Configuration Register */ + +#define S_RXCFG_DRTH 1 +#define M_RXCFG_DRTH _DD_MAKEMASK(5,S_RXCFG_DRTH) +#define V_RXCFG_DRTH(x) _DD_MAKEVALUE(x,S_RXCFG_DRTH) +#define G_RXCFG_DRTH(x) _DD_GETVALUE(x,S_RXCFG_DRTH,M_RXCFG_DRTH) + +#define S_RXCFG_MXDMA 20 +#define M_RXCFG_MXDMA _DD_MAKEMASK(3,S_RXCFG_MXDMA) +#define V_RXCFG_MXDMA(x) _DD_MAKEVALUE(x,S_RXCFG_MXDMA) +#define G_RXCFG_MXDMA(x) _DD_GETVALUE(x,S_RXCFG_MXDMA,M_RXCFG_MXDMA) + +#define M_RXCFG_ALP _DD_MAKEMASK1(27) +#define M_RXCFG_ATX _DD_MAKEMASK1(28) +#define M_RXCFG_ARP _DD_MAKEMASK1(30) +#define M_RXCFG_AEP _DD_MAKEMASK1(31) + + +/* 0x3C CCSR: CLKRUN Control/Status Register */ + +#define M_CCSR_CLKRUN_EN _DD_MAKEMASK1(0) +#define M_CCSR_PMEEN _DD_MAKEMASK1(8) +#define M_CCSR_PMESTS _DD_MAKEMASK1(15) + + +/* 0x40 WCSR: Wake Command/Status Register */ + +#define M_WCSR_WKPHY _DD_MAKEMASK1(0) +#define M_WCSR_WKUCP _DD_MAKEMASK1(1) +#define M_WCSR_WKMCP _DD_MAKEMASK1(2) +#define M_WCSR_WKBCP _DD_MAKEMASK1(3) +#define M_WCSR_WKARP _DD_MAKEMASK1(4) +#define M_WCSR_WKPAT0 _DD_MAKEMASK1(5) +#define M_WCSR_WKPAT1 _DD_MAKEMASK1(6) +#define M_WCSR_WKPAT2 _DD_MAKEMASK1(7) +#define M_WCSR_WKPAT3 _DD_MAKEMASK1(8) +#define M_WCSR_WKMAG _DD_MAKEMASK1(9) +#define M_WCSR_MPSOE _DD_MAKEMASK1(10) +#define M_WCSR_SOHACK _DD_MAKEMASK1(20) +#define M_WCSR_PHYINT _DD_MAKEMASK1(22) +#define M_WCSR_UCASTR _DD_MAKEMASK1(23) +#define M_WCSR_MCASTR _DD_MAKEMASK1(24) +#define M_WCSR_BCASTR _DD_MAKEMASK1(25) +#define M_WCSR_ARPR _DD_MAKEMASK1(26) +#define M_WCSR_PATM0 _DD_MAKEMASK1(27) +#define M_WCSR_PATM1 _DD_MAKEMASK1(28) +#define M_WCSR_PATM2 _DD_MAKEMASK1(29) +#define M_WCSR_PATM3 _DD_MAKEMASK1(30) +#define M_WCSR_MPR _DD_MAKEMASK1(31) + + +/* 0x44 PCR: Pause Control/Status Register */ + +#define S_PCR_PAUSE_CNT 0 +#define M_PCR_PAUSE_CNT _DD_MAKEMASK(16,S_PCR_PAUSE_CNT) +#define V_PCR_PAUSE_CNT(x) _DD_MAKEVALUE(x,S_PCR_PAUSE_CNT) +#define G_PCR_PAUSE_CNT(x) _DD_GETVALUE(x,S_PCR_PAUSE_CNT,M_PCR_PAUSE_CNT) + +#define M_PCR_MLD_EN _DD_MAKEMASK1(16) +#define M_PCR_PSNEG _DD_MAKEMASK1(21) +#define M_PCR_PS_RCVD _DD_MAKEMASK1(22) +#define M_PCR_PS_ACT _DD_MAKEMASK1(23) +#define M_PCR_PS_DA _DD_MAKEMASK1(29) +#define M_PCR_PS_MCAST _DD_MAKEMASK1(30) +#define M_PCR_PSEN _DD_MAKEMASK1(31) + + +/* 0x48 RFCR: Receive Filter/Match Control Register */ + + +#define S_RFCR_RFADDR 0 +#define M_RFCR_RFADDR _DD_MAKEMASK(10,S_RFCR_RFADDR) +#define V_RFCR_RFADDR(x) _DD_MAKEVALUE(x,S_RFCR_RFADDR) +#define G_RFCR_RFADDR(x) _DD_GETVALUE(x,S_RFCR_RFADDR,M_RFCR_RFADDR) + +#define K_RFCR_PMATCH_ADDR 0x000 +#define K_RFCR_PCOUNT_ADDR 0x006 +#define K_RFCR_FILTER_ADDR 0x200 + +#define M_RFCR_ULM _DD_MAKEMASK1(19) +#define M_RFCR_UHEN _DD_MAKEMASK1(20) +#define M_RFCR_MHEN _DD_MAKEMASK1(21) +#define M_RFCR_AARP _DD_MAKEMASK1(22) +#define M_RFCR_APAT0 _DD_MAKEMASK1(23) +#define M_RFCR_APAT1 _DD_MAKEMASK1(24) +#define M_RFCR_APAT2 _DD_MAKEMASK1(25) +#define M_RFCR_APAT3 _DD_MAKEMASK1(26) +#define M_RFCR_APAT (M_RFCR_APAT0 | M_RFCR_APAT1 | \ + M_RFCR_APAT2 | M_RFCR_APAT3 ) +#define M_RFCR_APM _DD_MAKEMASK1(27) +#define M_RFCR_AAU _DD_MAKEMASK1(28) +#define M_RFCR_AAM _DD_MAKEMASK1(29) +#define M_RFCR_AAB _DD_MAKEMASK1(30) +#define M_RFCR_RFEN _DD_MAKEMASK1(31) + + +/* 0x4C RFDR: Receive Filter/Match Data Register */ + +#define S_RFDR_RFDATA 0 +#define M_RFDR_RFDATA _DD_MAKEMASK(16,S_RFDR_RFDATA) +#define V_RFDR_RFDATA(x) _DD_MAKEVALUE(x,S_RFDR_RFDATA) +#define G_RFDR_RFDATA(x) _DD_GETVALUE(x,S_RFDR_RFDATA,M_RFDR_RFDATA) + +#define S_RFDR_BMASK 16 +#define M_RFDR_BMASK _DD_MAKEMASK(2,S_RFDR_BMASK) +#define V_RFDR_BMASK(x) _DD_MAKEVALUE(x,S_RFDR_BMASK) +#define G_RFDR_BMASK(x) _DD_GETVALUE(x,S_RFDR_BMASK,M_RFDR_BMASK) + + +/* 0x50 BRAR: Boot ROM Address Register */ + +#define S_BRAR_ADDR 0 +#define M_BRAR_ADDR _DD_MAKEMASK(16,S_BRAR_ADDR) +#define V_BRAR_ADDR(x) _DD_MAKEVALUE(x,S_BRAR_ADDR) +#define G_BRAR_ADDR(x) _DD_GETVALUE(x,S_BRAR_ADDR,M_BRAR_ADDR) + +#define M_BRAR_AUTOINC _DD_MAKEMASK1(31) + + +/* 0x54 BRDR: Boot ROM Data Register */ + + +/* 0x58 SRR: Silicon Revision Register */ + +#define S_SRR_REV 0 +#define M_SRR_REV _DD_MAKEMASK(16,S_SRR_REV) +#define V_SRR_REV(x) _DD_MAKEVALUE(x,S_SRR_REV) +#define G_SRR_REV(x) _DD_GETVALUE(x,S_SRR_REV,M_SRR_REV) + +#define K_REV_CVNG 0x00000302 +#define K_REV_DVNG_UJB 0x00000403 + + +/* 0x5C MIBC: Management Information Base Control Register */ + +#define M_MIBC_WRN _DD_MAKEMASK1(0) +#define M_MIBC_FRZ _DD_MAKEMASK1(1) +#define M_MIBC_ACLR _DD_MAKEMASK1(2) +#define M_MIBC_MIBS _DD_MAKEMASK1(3) + + +/* MIB Counters */ + +/* 0x60 RXErroredPkts */ +/* 0x64 RXFCSErrors */ +/* 0x68 RXMsdPktErrors */ +/* 0x6C RXFAErrors */ +/* 0x70 RXSymbolErrors */ +/* 0x74 RXFrameTooLong */ +/* 0x78 TXSQEErrors */ + + +/* See ../net/mii.h for fields of standard (MII) PHY registers */ + +#define K_83815_PHYID1 0x2000 +#define K_83815_PHYID2 0x5C21 + +#define K_ANNPTR_NULL 0x0001 + + +/* 0xC0 PHYSTS: PHY Status Register */ + +#define PHYSTS_RXERRLATCH 0x2000 +#define PHYSTS_POLARITYSTAT 0x1000 +#define PHYSTS_FALSECARRLATCH 0x0800 +#define PHYSTS_SIGNALDETECT 0x0400 +#define PHYSTS_DESCRAMBLOCK 0x0200 +#define PHYSTS_PAGERECVD 0x0100 +#define PHYSTS_MIIINT 0x0080 +#define PHYSTS_REMOTEFAULT 0x0040 +#define PHYSTS_JABBERDET 0x0020 +#define PHYSTS_ANCOMPLETE 0x0010 +#define PHYSTS_LOOPBACK 0x0008 +#define PHYSTS_DUPLEX 0x0004 +#define PHYSTS_SPEED10 0x0002 +#define PHYSTS_LINKSTAT 0x0001 + + +/* 0xC4 MICR: MII Interrupt Control Register */ + +#define MICR_INTEN 0x0002 +#define MICR_TINT 0x0001 + + +/* 0xC8 MISR: MII Interrupt Status and Misc. Control Register */ + +#define MISR_MINT 0x8000 +#define MISR_MSKLINK 0x4000 +#define MISR_MSKJAB 0x2000 +#define MISR_MSKRF 0x1000 +#define MISR_MSKANC 0x0800 +#define MISR_MSKFHF 0x0400 +#define MISR_MSKRHF 0x0200 + + +/* 0xD0 FCSCR: False Carrier Sense Counter Register */ + +#define FCSCR_FCSCNT 0x00FF + + +/* 0xD4 RECR: Receiver Error Counter Register */ + +#define RECR_RXERCNT 0x00FF + + +/* 0xD8 PCSR: 100 Mb/s PCS Configuration and Status Register */ + +#define PCSR_BYP4B5B 0x1000 +#define PCSR_FREECLK 0x0800 +#define PCSR_TQEN 0x0400 +#define PCSR_SDFORCEB 0x0200 +#define PCSR_SDOPTION 0x0100 +#define PCSR_FORCE100OK 0x0020 +#define PCSR_NRZIBYPASS 0x0004 + + +/* 0xE4 PHYCR: PHY Control Register */ + +#define PHYCR_PSR15 0x0800 +#define PHYCR_BISTSTATUS 0x0400 +#define PHYCR_BISTSTART 0x0200 +#define PHYCR_BPSTRETCH 0x0100 +#define PHYCR_PAUSESTS 0x0080 +#define PHYCR_PHYADDR 0x001F + + +/* 0xE8 TBTSCR: 10Base-T Status/Control Register */ + +#define TBTSCR_LPBK10DIS 0x0100 +#define TBTSCR_LPDIS 0x0080 +#define TBTSCR_FORCELINK10 0x0040 +#define TBTSCR_FORCEPOLCOR 0x0020 +#define TBTSCR_POLARITY 0x0010 +#define TBTSCR_AUTOPOLDIS 0x0008 +#define TBTSCR_HBDIS 0x0002 +#define TBTSCR_JABBERDIS 0x0001 + + +/* MacPhyter Transmit and Receive Descriptors */ + +/* Common Command/Status Fields */ +#define S_DES1_SIZE 0 +#define M_DES1_SIZE _DD_MAKEMASK(12,S_DES1_SIZE) +#define V_DES1_SIZE(x) _DD_MAKEVALUE(x,S_DES1_SIZE) +#define G_DES1_SIZE(x) _DD_GETVALUE(x,S_DES1_SIZE,M_DES1_SIZE) + +#define M_DES1_OK _DD_MAKEMASK1(27) +#define M_DES1_INTR _DD_MAKEMASK1(29) +#define M_DES1_MORE _DD_MAKEMASK1(30) +#define M_DES1_OWN _DD_MAKEMASK1(31) + +/* Transmit Command/Status Bits */ +#define S_DES1_CCNT 16 +#define M_DES1_CCNT _DD_MAKEMASK(4,S_DES1_CCNT) +#define V_DES1_CCNT(x) _DD_MAKEVALUE(x,S_DES1_CCNT) +#define G_DES1_CCNT(x) _DD_GETVALUE(x,S_DES1_CCNT,M_DES1_CCNT) + +#define M_DES1_EC _DD_MAKEMASK1(20) +#define M_DES1_OWC _DD_MAKEMASK1(21) +#define M_DES1_ED _DD_MAKEMASK1(22) +#define M_DES1_TD _DD_MAKEMASK1(23) +#define M_DES1_CRS _DD_MAKEMASK1(24) +#define M_DES1_TFU _DD_MAKEMASK1(25) +#define M_DES1_TXA _DD_MAKEMASK1(26) +#define M_DES1_SUPCRC _DD_MAKEMASK1(28) + +/* Receive Command/Status Bits */ +#define M_DES1_COL _DD_MAKEMASK1(16) +#define M_DES1_LBP _DD_MAKEMASK1(17) +#define M_DES1_FAE _DD_MAKEMASK1(18) +#define M_DES1_CRCE _DD_MAKEMASK1(19) +#define M_DES1_ISE _DD_MAKEMASK1(20) +#define M_DES1_RUNT _DD_MAKEMASK1(21) +#define M_DES1_LONG _DD_MAKEMASK1(22) +#define M_DES1_RX_ERRORS (M_DES1_CRCE | \ + M_DES1_COL | M_DES1_FAE | M_DES1_ISE | \ + M_DES1_RUNT | M_DES1_LONG | M_DES1_RXO) + +#define S_DES1_DEST 23 +#define M_DES1_DEST _DD_MAKEMASK(2,S_DES1_DEST) +#define V_DES1_DEST(x) _DD_MAKEVALUE(x,S_DES1_DEST) +#define G_DES1_DEST(x) _DD_GETVALUE(x,S_DES1_DEST,M_DES1_DEST) + +#define K_DEST_REJECT 0 +#define K_DEST_UNICAST 1 +#define K_DEST_MULTICAST 2 +#define K_DEST_BROADCAST 3 + +#define M_DES1_RXO _DD_MAKEMASK1(25) +#define M_DES1_RXA _DD_MAKEMASK1(26) +#define M_DES1_INCCRC _DD_MAKEMASK1(28) + +#endif /* _DP83815_H_ */ diff --git a/cfe/cfe/dev/ns16550.h b/cfe/cfe/dev/ns16550.h new file mode 100644 index 0000000..b603ccc --- /dev/null +++ b/cfe/cfe/dev/ns16550.h @@ -0,0 +1,143 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NS16550 Serial Port definitions File: ns16550.h + * + * This defines the hardware registers of 16550 compatible UARTs + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* + * NS16550 UART registers + */ + +#ifndef _NS16550_H_ +#define _NS16550_H_ + +#ifndef NS16550_HZ +#define NS16550_HZ 1843200 +#endif + +/* + * NS16550 UART registers + */ + +/* Register definitions */ + +#define R_UART_DATA 0 +#define R_UART_IER 1 +#define R_UART_IIR 2 +#define R_UART_FIFO R_UART_IIR +#define R_UART_CFCR 3 +#define R_UART_MCR 4 +#define R_UART_LSR 5 +#define R_UART_MSR 6 +#define R_UART_SCR 7 + +/* 16 bit baud rate divisor (lower byte in UART_DATA, upper in UART_IER) */ +#define BRTC(x) (NS16550_HZ / (16*(x))) + +/* interrupt enable register */ +#define IER_ERXRDY 0x1 /* int on rx ready */ +#define IER_ETXRDY 0x2 /* int on tx ready */ +#define IER_ERLS 0x4 /* int on line status change */ +#define IER_EMSC 0x8 /* int on modem status change */ + +/* interrupt identification register */ +#define IIR_IMASK 0xf /* mask */ +#define IIR_RXTOUT 0xc /* receive timeout */ +#define IIR_RLS 0x6 /* receive line status */ +#define IIR_RXRDY 0x4 /* receive ready */ +#define IIR_TXRDY 0x2 /* transmit ready */ +#define IIR_NOPEND 0x1 /* nothing */ +#define IIR_MLSC 0x0 /* modem status */ +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ + +/* fifo control register */ +#define FIFO_ENABLE 0x01 /* enable fifo */ +#define FIFO_RCV_RST 0x02 /* reset receive fifo */ +#define FIFO_XMT_RST 0x04 /* reset transmit fifo */ +#define FIFO_DMA_MODE 0x08 /* enable dma mode */ +#define FIFO_TRIGGER_1 0x00 /* trigger at 1 char */ +#define FIFO_TRIGGER_4 0x40 /* trigger at 4 chars */ +#define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */ +#define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */ + +/* character format control register */ +#define CFCR_DLAB 0x80 /* divisor latch */ +#define CFCR_SBREAK 0x40 /* send break */ +#define CFCR_PZERO 0x30 /* zero parity */ +#define CFCR_PONE 0x20 /* one parity */ +#define CFCR_PEVEN 0x10 /* even parity */ +#define CFCR_PODD 0x00 /* odd parity */ +#define CFCR_PENAB 0x08 /* parity enable */ +#define CFCR_STOPB 0x04 /* 2 stop bits */ +#define CFCR_8BITS 0x03 /* 8 data bits */ +#define CFCR_7BITS 0x02 /* 7 data bits */ +#define CFCR_6BITS 0x01 /* 6 data bits */ +#define CFCR_5BITS 0x00 /* 5 data bits */ + +/* modem control register */ +#define MCR_LOOPBACK 0x10 /* loopback */ +#define MCR_IENABLE 0x08 /* output 2 = int enable */ +#define MCR_DRS 0x04 /* output 1 = xxx */ +#define MCR_RTS 0x02 /* enable RTS */ +#define MCR_DTR 0x01 /* enable DTR */ + +/* line status register */ +#define LSR_RCV_FIFO 0x80 /* error in receive fifo */ +#define LSR_TSRE 0x40 /* transmitter empty */ +#define LSR_TXRDY 0x20 /* transmitter ready */ +#define LSR_BI 0x10 /* break detected */ +#define LSR_FE 0x08 /* framing error */ +#define LSR_PE 0x04 /* parity error */ +#define LSR_OE 0x02 /* overrun error */ +#define LSR_RXRDY 0x01 /* receiver ready */ +#define LSR_RCV_MASK 0x1f + +/* modem status register */ +#define MSR_DCD 0x80 /* DCD active */ +#define MSR_RI 0x40 /* RI active */ +#define MSR_DSR 0x20 /* DSR active */ +#define MSR_CTS 0x10 /* CTS active */ +#define MSR_DDCD 0x08 /* DCD changed */ +#define MSR_TERI 0x04 /* RI changed */ +#define MSR_DDSR 0x02 /* DSR changed */ +#define MSR_DCTS 0x01 /* CTS changed */ + +#endif /* _NS16550_H_ */ diff --git a/cfe/cfe/dev/pci_devs.c b/cfe/cfe/dev/pci_devs.c new file mode 100644 index 0000000..a1ba789 --- /dev/null +++ b/cfe/cfe/dev/pci_devs.c @@ -0,0 +1,79 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PCI device selection and initialization File: pci_devs.c + * + * These are the routines to include the PCI drivers and to hook any + * devices with special configuration requirements.. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#if CFG_PCI +#include "sbmips.h" +#include "lib_types.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "dev_ide.h" +#include "env_subr.h" + +extern cfe_driver_t pciidedrv; /* PCI IDE controller */ +extern cfe_driver_t dc21143drv; /* Tulip Ethernet */ +extern cfe_driver_t dp83815drv; /* MacPhyter Ethernet */ +#if CFG_DOWNLOAD +extern cfe_driver_t bcm1250drv; /* BCM1250 as a device */ +#endif +extern cfe_driver_t ns16550pci_uart; /* PCI serial port */ + +void pci_add_devices(int init_pci); +void pci_add_devices(int init_pci) +{ + if (init_pci) { + cfe_add_device(&pciidedrv,0,IDE_PROBE_MASTER_TYPE(IDE_DEVTYPE_DISK),NULL); + cfe_add_device(&dc21143drv,0,0,env_getenv("TULIP0_HWADDR")); + cfe_add_device(&dp83815drv,0,0,NULL); + +#if CFG_DOWNLOAD + /* Access to bcm1250 in PCI device mode */ + cfe_add_device(&bcm1250drv,0,0,NULL); +#endif + cfe_add_device(&ns16550pci_uart,0,0,0); + } +} +#endif /* CFG_PCI */ + diff --git a/cfe/cfe/hosttools/Makefile b/cfe/cfe/hosttools/Makefile new file mode 100644 index 0000000..2f04639 --- /dev/null +++ b/cfe/cfe/hosttools/Makefile @@ -0,0 +1,12 @@ + +CC = gcc +CFLAGS = -I ../include + +all : mkbootimage installboot + +mkbootimage : mkbootimage.c + $(CC) $(CFLAGS) -o mkbootimage mkbootimage.c + +installboot : installboot.c + $(CC) $(CFLAGS) -o installboot installboot.c + diff --git a/cfe/cfe/hosttools/README b/cfe/cfe/hosttools/README new file mode 100644 index 0000000..7976c6d --- /dev/null +++ b/cfe/cfe/hosttools/README @@ -0,0 +1,49 @@ + +This directory contains some "host tools" that may be useful for +porting CFE. + +MKBOOTIMAGE +----------- + +The 'mkbootimage' program is used to attach a CFE boot block to +an image file. Boot blocks are used on block-structured devices +such as disks and CD-ROM. + +The boot block contains information to help CFE locate the boot +loader program and verify its validity. To create boot file, +link your boot loader to be executable within CFE's boot +environment (it should be a binary file, not an ELF file). + +Convert the file to a boot block using: + + mkbootimage [-EB] [-EL] myfile.elf myfile.boot + +Supply the -EB or -EL switch to configure the target endianness, +since the values in the boot block are endian-specific. + + +INSTALLBOOT +----------- + +Once you have a boot file, the 'installboot' program can +insert the boot file into a simulated disk file (such as the +file that you can use with the IDE emulation in the +BCM12500's functional simulator). The 'installboot' program +installs your boot file into a disk image file starting at +the first sector, preserving the beginning part of the boot +sector where the the boot block lives. + +Install the boot block using: + + installboot myfile.boot my_disk_image.dsk + +Where the "my_disk_image.dsk" is the simulated disk file for +the functional simulator. + +installboot could probably be ported to the target OS to +install boot blocks on raw disk devices. + + + + + diff --git a/cfe/cfe/hosttools/installboot.c b/cfe/cfe/hosttools/installboot.c new file mode 100644 index 0000000..2f61415 --- /dev/null +++ b/cfe/cfe/hosttools/installboot.c @@ -0,0 +1,352 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Boot program installer File: installboot.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This program converts a binary file (bootstrap program) + * into a boot block by prepending the boot block sector + * to the program. It generates the appropriate + * boot block checksums and such. The resulting file may + * be used by installboot (for example) to put into a disk + * image for the simulator. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include +#include + +typedef unsigned long long uint64_t; +typedef unsigned long uint32_t; + +#include "cfe_bootblock.h" +#include +#include +#include +#include + +#define roundup(x,align) (((x)+(align)-1)&~((align)-1)) +#define howmany(x,align) (((x)+(align)-1)/(align)) + +static int verbose = 0; +static int big_endian = 1; +static int swapflg = 1; +static unsigned long bootcode_offset = 2; +static unsigned long bootsect_offset = 1; + +static void usage(void) +{ + fprintf(stderr,"usage: installboot [-bootsect ] [-bootcode ]\n" + " [-v] [-EB] [-EL] bootloaderfile.bin devicefile\n\n"); + fprintf(stderr,"This program installs a boot block onto a disk. Typically, installboot\n" + "is used to install sibyl or other OS bootloaders. The binary you install\n" + "should be a raw program (not ELF) located to run in CFE's boot area\n" + "at address 0x2000_0000. The devicefile should be the name of the raw device\n" + "such as /dev/hda on Linux.\n\n" + "Care must be taken when choosing the values for -bootsect and -bootcode\n" + "not to interfere with other partitions on your disk. When partitioning,\n" + "it's a good idea to reserve 3 cylinders at the beginning of the disk for\n" + "the boot loader.\n\n" + "-bootsect nn specifies that the boot sector will be placed on sector 'nn'\n" + "-bootcode nn specifies that the boot program itself will be placed\n" + " on sectors starting with 'nn'. The boot sector will point\n" + " to this sector.\n"); + + exit(1); +} + +static void bswap32(uint32_t *ptr) +{ + unsigned char b; + unsigned char *bptr; + + if (swapflg) { + bptr = (unsigned char *) ptr; + b = bptr[0]; bptr[0] = bptr[3]; bptr[3] = b; + b = bptr[1]; bptr[1] = bptr[2]; bptr[2] = b; + } +} + +static void bswap64(uint64_t *ptr) +{ + unsigned char b; + unsigned char *bptr; + + bptr = (unsigned char *) ptr; + + if (swapflg) { + b = bptr[0]; bptr[0] = bptr[7]; bptr[7] = b; + b = bptr[1]; bptr[1] = bptr[6]; bptr[6] = b; + b = bptr[2]; bptr[2] = bptr[5]; bptr[5] = b; + b = bptr[3]; bptr[3] = bptr[4]; bptr[4] = b; + } +} + + +static void bswap_bootblock(struct boot_block *bb) +{ + int idx; + + for (idx = 59; idx <= 63; idx++) { + bswap64(&(bb->bb_data[idx])); + } +} + +static void do_checksum(void *ptr,int length,uint32_t *csptr,int swap) +{ + uint32_t *p; + uint32_t chksum = 0; + uint32_t d; + + p = (uint32_t *) ptr; + + length /= sizeof(uint32_t); + + while (length) { + d = *p; + if (swap) bswap32(&d); + chksum += d; + p++; + length--; + } + + if (swap) bswap32(&chksum); + + *csptr = chksum; +} + + +static void dumpbootblock(struct boot_block *bb) +{ + int idx; + + fprintf(stderr,"Magic Number: %016llX\n", + bb->bb_magic); + fprintf(stderr,"Boot code offset: %llu\n", + (unsigned long long)bb->bb_secstart); + fprintf(stderr,"Boot code size: %u\n", + (uint32_t) (bb->bb_secsize & BOOT_SECSIZE_MASK)); + fprintf(stderr,"Header checksum: %08X\n", + (uint32_t) (bb->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK)); + fprintf(stderr,"Header version: %d\n", + (uint32_t) ((bb->bb_hdrinfo & BOOT_HDR_VER_MASK) >> BOOT_HDR_VER_SHIFT)); + fprintf(stderr,"Data checksum: %08X\n", + (uint32_t) ((bb->bb_secsize & BOOT_DATA_CHECKSUM_MASK) >> BOOT_DATA_CHECKSUM_SHIFT)); + fprintf(stderr,"Architecture info: %08X\n", + (uint32_t) (bb->bb_archinfo & BOOT_ARCHINFO_MASK)); + fprintf(stderr,"\n"); + + for (idx = 59; idx <= 63; idx++) { + fprintf(stderr,"Word %d = %016llX\n",idx,bb->bb_data[idx]); + } +} + +static int host_is_little(void) +{ + unsigned long var = 1; + unsigned char *pvar = (unsigned char *) &var; + + return (*pvar == 1); +} + +int main(int argc, char *argv[]) +{ + int fh; + long bootsize; + long bootbufsize; + unsigned char *bootcode; + struct boot_block bootblock; + uint32_t datacsum,hdrcsum; + int host_le; + + while ((argc > 1) && (argv[1][0] == '-')) { + if (strcmp(argv[1],"-v") == 0) { + verbose = 1; + } + else if (strcmp(argv[1],"-EB") == 0) { + big_endian = 1; + } + else if (strcmp(argv[1],"-EL") == 0) { + big_endian = 0; + } + else if (strcmp(argv[1],"-bootsect") == 0) { + char *tmp_ptr; + argv++; + argc--; + if (argc == 1) { + fprintf(stderr,"-bootsect requires an argument\n"); + exit(1); + } + bootsect_offset = strtoul(argv[1], &tmp_ptr, 0); + bootcode_offset = bootsect_offset + 1; /* default if -bootcode not specified */ + if (*tmp_ptr) { + fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]); + exit(1); + } + } + else if (strcmp(argv[1],"-bootcode") == 0) { + char *tmp_ptr; + argv++; + argc--; + if (argc == 1) { + fprintf(stderr,"-bootcode requires an argument\n"); + exit(1); + } + bootcode_offset = strtoul(argv[1], &tmp_ptr, 0); + if (*tmp_ptr) { + fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]); + exit(1); + } + } + else { + fprintf(stderr,"Invalid switch: %s\n",argv[1]); + exit(1); + } + argv++; + argc--; + } + + /* + * We need to swap things around if the host and + * target are different endianness + */ + + swapflg = 0; + host_le = host_is_little(); + + if (big_endian && host_is_little()) swapflg = 1; + if ((big_endian == 0) && !(host_is_little())) swapflg = 1; + + fprintf(stderr,"Host is %s-endian.\n",host_le ? "little" : "big"); + fprintf(stderr,"Target is %s-endian.\n",big_endian ? "big" : "little"); + + if (argc != 3) { + usage(); + } + + /* + * Read in the boot file + */ + + fh = open(argv[1],O_RDONLY); + if (fh < 0) { + perror(argv[1]); + } + + bootsize = lseek(fh,0L,SEEK_END); + lseek(fh,0L,SEEK_SET); + + bootbufsize = roundup(bootsize,BOOT_BLOCK_BLOCKSIZE); + + bootcode = malloc(bootbufsize); + if (bootcode == NULL) { + perror("malloc"); + exit(1); + } + memset(bootcode,0,bootbufsize); + if (read(fh,bootcode,bootsize) != bootsize) { + perror("read"); + exit(1); + } + + close(fh); + + /* + * Construct the boot block + */ + + + /* Checksum the boot code */ + do_checksum(bootcode,bootbufsize,&datacsum,1); + bswap32(&datacsum); + + + /* fill in the boot block fields, and checksum the boot block */ + bootblock.bb_magic = BOOT_MAGIC_NUMBER; + bootblock.bb_hdrinfo = (((uint64_t) BOOT_HDR_VERSION) << BOOT_HDR_VER_SHIFT); + bootblock.bb_secstart = (bootcode_offset * 512); + bootblock.bb_secsize = ((uint64_t) bootbufsize) | + (((uint64_t) datacsum) << BOOT_DATA_CHECKSUM_SHIFT); + bootblock.bb_archinfo = 0; /* XXX */ + + do_checksum(&(bootblock.bb_magic),BOOT_BLOCK_SIZE,&hdrcsum,0); + bootblock.bb_hdrinfo |= (uint64_t) hdrcsum; + + if (verbose) dumpbootblock(&bootblock); + + bswap_bootblock(&bootblock); + + /* + * Now write the output file + */ + + fh = open(argv[2],O_RDWR|O_CREAT,S_IREAD|S_IWRITE); + if (fh < 0) { + perror(argv[2]); + exit(1); + } + + fprintf(stderr,"Installing boot block\n"); + if (lseek(fh, bootsect_offset * 512, SEEK_SET) != (bootsect_offset * 512)) { + perror(argv[2]); + exit(1); + } + if (write(fh,&bootblock,sizeof(bootblock)) != sizeof(bootblock)) { + perror(argv[2]); + exit(1); + } + fprintf(stderr,"Installing bootstrap program\n"); + if (lseek(fh, bootcode_offset * 512, SEEK_SET) != (bootcode_offset * 512)) { + perror(argv[2]); + exit(1); + } + if (write(fh,bootcode,bootbufsize) != bootbufsize) { + perror(argv[2]); + exit(1); + } + + close(fh); + + fprintf(stderr,"Done. %s installed on %s\n",argv[1],argv[2]); + + exit(0); + + +} + diff --git a/cfe/cfe/hosttools/makereg.c b/cfe/cfe/hosttools/makereg.c new file mode 100644 index 0000000..0ff53e1 --- /dev/null +++ b/cfe/cfe/hosttools/makereg.c @@ -0,0 +1,481 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Register Table Generator File: makereg.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * Warning: don't eat your lunch before reading this program. + * It's nasty! + * + * This program generates tables of SOC registers and values + * that are easy for us to display. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__CYGWIN__) +#define TEXTMODE "t" +#else +#define TEXTMODE "" +#endif + +typedef struct Cons { + char *str; + int num; +} CONS; + +typedef struct RegInfo { + unsigned long reg_mask; + char *reg_agent; + int reg_agentidx; + char *reg_addr; + char *reg_inst; + char *reg_subinst; + char *reg_printfunc; + char *reg_description; +} REGINFO; + +typedef struct ConstInfo { + char *name; + unsigned int value; +} CONSTINFO; + +#define MAXCONST 64 +CONSTINFO constants[MAXCONST]; +int constcnt = 0; + +#define MAXREGS 2000 +REGINFO allregs[MAXREGS]; +int regcnt = 0; + +int maskcnt = 0; + +#define MAXAGENTS 32 +char *agentnames[MAXAGENTS]; +int agentcnt; + +#define CMD_AGENT 1 +#define CMD_ENDAGENT 2 + +CONS commands[] = { + {"!agent",CMD_AGENT}, + {"!endagent",CMD_ENDAGENT}, + {NULL,0}}; + + +int assoc(CONS *list,char *str) +{ + while (list->str) { + if (strcmp(list->str,str) == 0) return list->num; + list++; + } + + return -1; +} + +char *gettoken(char **ptr) +{ + char *p = *ptr; + char *ret; + + /* skip white space */ + + while (*p && isspace(*p)) p++; + ret = p; + + /* check for end of string */ + + if (!*p) { + *ptr = p; + return NULL; + } + + /* skip non-whitespace */ + + while (*p) { + if (isspace(*p)) break; + + /* do quoted strings */ + + if (*p == '"') { + p++; + ret = p; + while (*p && (*p != '"')) p++; + if (*p == '"') *p = '\0'; + } + + p++; + + } + + if (*p) { + *p++ = '\0'; + } + *ptr = p; + + return ret; +} + +static int readline(FILE *str,char *dest,int destlen) +{ + char *x; + + for (;;) { + if (!fgets(dest,destlen,str)) return -1; + if (x = strchr(dest,'\n')) *x = '\0'; + if (dest[0] == '\0') continue; + if (dest[0] == ';') continue; + break; + } + + return 0; +} + + +static void fatal(char *str,char *val) +{ + fprintf(stderr,"fatal error: %s %s\n",str,val ? val : ""); + exit(1); +} + +static unsigned int newmask(void) +{ + int res; + + res = maskcnt; + + if (maskcnt == 32) { + fatal("Out of mask bits",NULL); + } + + maskcnt++; + + return 1<= 0) && (rmax < 100)) { + char *atext,*subinst,*pfunc,*descr; + + if (regline[0] == '!') break; + + ptr = regline; + atext = gettoken(&ptr); + subinst = gettoken(&ptr); + pfunc = gettoken(&ptr); + descr = gettoken(&ptr); + + if (!descr) { + fatal("Missing fields for ",atext); + } + + regs[rmax].reg_addr = strdup(atext); + regs[rmax].reg_subinst = strdup(subinst); + regs[rmax].reg_printfunc = strdup(pfunc); + regs[rmax].reg_description = strdup(descr); + regs[rmax].reg_mask = 0; + rmax++; + } + + if (rmax == 100) fatal("Too many registers in section ",agentname); + + inst = strtok(instances,","); + + cumlmask = 0; + while (inst) { + char defname[100]; + unsigned int curmask; + + sprintf(defname,"SOC_AGENT_%s%s", + agentname,inst[0] == '*' ? "" : inst); + + curmask = newmask(); + cumlmask |= curmask; + + addconst(defname,curmask); + + for (idx = 0; idx < rmax; idx++) { + char descr[100]; + char atext[200]; + + macroexpand(regs[idx].reg_addr,inst,atext); +#if 0 + strcpy(descr,agentname); + if (inst[0] != '*') { + strcat(descr,inst); + } + strcat(descr," "); + if (regs[idx].reg_subinst[0] != '*') { + strcat(descr,regs[idx].reg_subinst); + strcat(descr," "); + } + strcat(descr,regs[idx].reg_description); +#else + strcpy(descr,regs[idx].reg_description); +#endif + + addreg(agentname, + agentidx, + curmask, + atext, + inst, + regs[idx].reg_subinst, + regs[idx].reg_printfunc, + descr); + } + inst = strtok(NULL,","); + } + + if (instances[0] != '*') { + sprintf(cumlname,"SOC_AGENT_%s",agentname); + addconst(cumlname,cumlmask); + } +} + +static void docommand(FILE *str,char *line) +{ + char *cmd; + + cmd = gettoken(&line); + if (!cmd) return; + + switch (assoc(commands,cmd)) { + case CMD_AGENT: + doagentcmd(str,line); + break; + default: + fatal("Invalid command",cmd); + break; + } + +} + +static int ingestfile(FILE *str) +{ + char line[500]; + + while (readline(str,line,sizeof(line)) >= 0) { + if (line[0] == '!') { + docommand(str,line); + } + else { + fatal("Command string required before register data",NULL); + } + } +} + + +void saveincfile(char *fname) +{ + FILE *str; + int idx; + + str = fopen(fname,"w" TEXTMODE); + if (!str) { + perror(fname); + exit(1); + } + + fprintf(str,"\n\n"); + + fprintf(str,"#ifndef %s\n",constants[0].name); + for (idx = 0; idx < constcnt; idx++) { + fprintf(str,"#define %s 0x%08X\n",constants[idx].name, + constants[idx].value); + } + fprintf(str,"#endif\n"); + + fprintf(str,"\n\n"); + + fprintf(str,"#ifdef _CFE_\n"); + fprintf(str,"#ifdef __ASSEMBLER__\n"); + fprintf(str,"\t.globl socstatetable\n"); + fprintf(str,"socstatetable:\n"); + for (idx = 0; idx < regcnt; idx++) { + fprintf(str,"\t\t.word 0x%08X,%s\n", + allregs[idx].reg_mask,allregs[idx].reg_addr); + } + fprintf(str,"\t\t.word 0,0\n"); + fprintf(str,"#endif\n"); + + fprintf(str,"\n\n"); + fprintf(str,"#ifndef __ASSEMBLER__\n"); + + /* Addr Agent Inst Subinst Mask Printfunc Descr */ + + fprintf(str,"char *socagents[] = {\n"); + for (idx = 0; idx < agentcnt; idx++) { + fprintf(str,"\t\"%s\",\n",agentnames[idx]); + } + fprintf(str,"\tNULL};\n\n"); + + fprintf(str,"const socreg_t socregs[] = {\n"); + for (idx = 0; idx < regcnt; idx++) { + fprintf(str," {%s,%d,\"%s\",\"%s\",\n 0x%08X,%s,\"%s\"},\n", + allregs[idx].reg_addr, + allregs[idx].reg_agentidx, + allregs[idx].reg_inst, + allregs[idx].reg_subinst, + allregs[idx].reg_mask, + allregs[idx].reg_printfunc, + allregs[idx].reg_description); + } + fprintf(str," {0,0,NULL,NULL,0,NULL,NULL}};\n\n"); + + fprintf(str,"#endif\n"); + fprintf(str,"#endif\n"); + fclose(str); +} + +int main(int argc,char *argv[]) +{ + FILE *str; + int idx; + + if (argc != 3) { + fprintf(stderr,"usage: makereg inputfile outputfile\n"); + exit(1); + } + + str = fopen(argv[1],"r" TEXTMODE); + + if (!str) { + perror(argv[1]); + exit(1); + } + + ingestfile(str); + + fclose(str); + + fprintf(stderr,"Total registers: %d\n",regcnt); + + saveincfile(argv[2]); + + exit(0); + return 0; +} diff --git a/cfe/cfe/hosttools/memconfig.c b/cfe/cfe/hosttools/memconfig.c new file mode 100644 index 0000000..3d84b05 --- /dev/null +++ b/cfe/cfe/hosttools/memconfig.c @@ -0,0 +1,654 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Memory Config Utility File: memconfig.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This host tool lets you enter DRAM parameters and run CFE's + * standard memory configuration to calculate the relevant timing + * parameters. It's a good way to see what CFE would have done, + * to find bogus timing calculations. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include +#include + +/* ********************************************************************* + * Basic types + ********************************************************************* */ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +/* ********************************************************************* + * SB1250 stuff + ********************************************************************* */ + +#include "sb1250_defs.h" +#include "sb1250_mc.h" +#include "sb1250_draminit.h" +#include "sb1250_regs.h" +#include "sb1250_scd.h" + +/* ********************************************************************* + * BCD macros + ********************************************************************* */ + +#define DECTO10THS(x) ((((x) >> 4)*10)+((x) & 0x0F)) + +/* ********************************************************************* + * Global defaults + ********************************************************************* */ + +#define MIN_tMEMCLK DRT10(8,0) +#define tROUNDTRIP DRT10(2,5) + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef struct encvalue_s { + char *name; + uint8_t val; +} encvalue_t; + +typedef struct spdbyte_s { + char *name; + uint8_t *data; + int decimal; + encvalue_t *values; + char *units; + char *description; + char *deflt; +} spdbyte_t; + +#define SPD_DEC_BCD 1 +#define SPD_DEC_QTR 2 +#define SPD_ENCODED 3 +#define SPD_ENCODED2 4 + +/* ********************************************************************* + * Globals + ********************************************************************* */ + + +uint8_t spd[64] = {0}; /* SPD data */ +uint8_t mintmemclk = MIN_tMEMCLK; /* Default value: 8.0ns */ +uint8_t roundtrip = tROUNDTRIP; /* Default value: 2.5ns */ +uint8_t dramtype = JEDEC; /* Regular DDR SDRAMs */ +uint8_t plldiv = 10; /* 500 MHz using 100Mhz refclk */ +uint8_t refclk = 100; /* 100Mhz reference clock */ +uint8_t portintlv = 0; /* no port interleaving */ + +uint8_t addrskew = 0xF; +uint8_t dqoskew = 0x8; +uint8_t dqiskew = 0x8; +uint8_t addrdrive = 0xF; +uint8_t datadrive = 0xF; +uint8_t clkdrive = 0; + +uint64_t mc0_mclkcfg; /* Value programmed by draminit */ +uint64_t mc0_timing1; /* Value programmed by draminit */ +uint64_t smbus0_start = 0; /* Rememberd SMBus register value */ +uint64_t smbus0_cmd = 0; /* Rememberd SMBus register value */ + +extern int sb1250_refclk; /* from draminit - reference clock */ +extern int dram_cas_latency; /* from draminit - calc'd cas latency */ +extern int dram_tMemClk; /* from draminit - calc'd tMemClk */ + +draminittab_t inittab[16]; /* our init tab */ + +int debug = 0; + +/* ********************************************************************* + * Parameter and value tables + ********************************************************************* */ + +encvalue_t caslatencies[] = { + {"3.5",JEDEC_CASLAT_35}, + {"3.0",JEDEC_CASLAT_30}, + {"2.5",JEDEC_CASLAT_25}, + {"2.0",JEDEC_CASLAT_20}, + {"1.5",JEDEC_CASLAT_15}, + {"1.0",JEDEC_CASLAT_10}, + {NULL,0}}; + +encvalue_t refreshrates[] = { + {"64",JEDEC_RFSH_64khz}, + {"256",JEDEC_RFSH_256khz}, + {"128",JEDEC_RFSH_128khz}, + {"32",JEDEC_RFSH_32khz}, + {"16",JEDEC_RFSH_16khz}, + {"8",JEDEC_RFSH_8khz}, + {NULL,0}}; + +encvalue_t modattribs[] = { + {"none",0}, + {"reg",JEDEC_ATTRIB_REG}, + {"diffclk",0x20}, + {NULL,0}}; + +encvalue_t dramtypes[] = { + {"jedec",JEDEC}, + {"fcram",FCRAM}, + {"sgram",SGRAM}, + {NULL,0}}; + +spdbyte_t spdfields[] = { + {"mintmemclk",&mintmemclk,SPD_DEC_BCD,NULL,"ns","Minimum value for tMEMCLK","8.0"}, + {"roundtrip", &roundtrip, SPD_DEC_BCD,NULL,"ns","Round trip time from CLK to returned DQS","2.5"}, + {"plldiv", &plldiv, 0,NULL,"","PLL Ratio (System Config Register)","10"}, + {"refclk", &refclk, 0,NULL,"Mhz","Reference clock, usually 100Mhz","100"}, +// {"portintlv", &portintlv, 0,NULL,"","Port interleave (1=on)","0"}, + {"memtype", &dramtype, SPD_ENCODED,dramtypes,"","Memory type (jedec, fcram, sgram)","jedec"}, + {"rows", &spd[JEDEC_SPD_ROWS],0,NULL,"","[3 ] Number of row bits","13"}, + {"cols", &spd[JEDEC_SPD_COLS],0,NULL,"","[4 ] Number of column bits","9"}, + {"banks", &spd[JEDEC_SPD_BANKS],0,NULL,"","[17] Number of banks","4"}, + {"tCK25", &spd[JEDEC_SPD_tCK25],SPD_DEC_BCD,NULL,"ns","[9 ] tCK value for CAS Latency 2.5","7.5"}, + {"tCK20", &spd[JEDEC_SPD_tCK20],SPD_DEC_BCD,NULL,"ns","[23] tCK value for CAS Latency 2.0","0"}, + {"tCK10", &spd[JEDEC_SPD_tCK10],SPD_DEC_BCD,NULL,"ns","[25] tCK value for CAS Latency 1.0","0"}, + {"rfsh", &spd[JEDEC_SPD_RFSH],SPD_ENCODED,refreshrates,"","[12] Refresh rate (KHz)","8"}, + {"caslat", &spd[JEDEC_SPD_CASLATENCIES],SPD_ENCODED2,caslatencies,"","[18] CAS Latencies supported","2.5"}, + {"attrib", &spd[JEDEC_SPD_ATTRIBUTES],SPD_ENCODED,modattribs,"","[21] Module attributes","none"}, + {"tRAS", &spd[JEDEC_SPD_tRAS],0,NULL,"ns","[30]","45"}, + {"tRP", &spd[JEDEC_SPD_tRP],SPD_DEC_QTR,NULL,"ns","[27]","20.0"}, + {"tRRD", &spd[JEDEC_SPD_tRRD],SPD_DEC_QTR,NULL,"ns","[28]","15.0"}, + {"tRCD", &spd[JEDEC_SPD_tRCD],SPD_DEC_QTR,NULL,"ns","[29]","20.0"}, + {"tRFC", &spd[JEDEC_SPD_tRFC],0,NULL,"ns","[42]","0"}, + {"tRC", &spd[JEDEC_SPD_tRC],0,NULL,"ns","[41]","0"}, + + {"addrskew", &addrskew, 0, NULL, "","Address Skew","0x0F"}, + {"dqoskew", &dqoskew, 0, NULL, "","DQO Skew","0x08"}, + {"dqikew", &dqiskew, 0, NULL, "","DQI Skew","0x08"}, + {"addrdrive", &addrdrive, 0, NULL, "","Address Drive","0x0F"}, + {"datadrive", &datadrive, 0, NULL, "","Data Drive","0x0F"}, + {"clkdrive", &clkdrive, 0, NULL, "","Clock Drive","0"}, + {NULL,0,0,NULL,NULL,NULL,NULL}}; + +char *lookupstr(encvalue_t *ev,uint8_t val) +{ + while (ev->name) { + if (ev->val == val) return ev->name; + ev++; + } + return "unknown"; +} + +uint64_t sbreadcsr(uint64_t reg) +{ + uint64_t val = 0; + + if (debug) printf("READ %08X\n",(uint32_t) reg); + + switch ((uint32_t) reg) { + case A_SCD_SYSTEM_REVISION: + val = V_SYS_PART(0x1250) | V_SYS_WID(0) | V_SYS_REVISION(1) | 0xFF; + break; + case A_SCD_SYSTEM_CFG: + val = V_SYS_PLL_DIV(plldiv); + break; + case A_SMB_STATUS_0: + val = 0; + break; + case A_SMB_CMD_0: + val = smbus0_cmd; + break; + case A_SMB_START_0: + val = smbus0_start; + break; + case A_SMB_DATA_0: + val = spd[smbus0_cmd & 0x3F]; + break; + } + return val; +} + +void sbwritecsr(uint64_t reg,uint64_t val) +{ + if (debug) printf("WRITE %08X %016llX\n",(uint32_t) reg,val); + + switch ((uint32_t) reg) { + case A_MC_REGISTER(0,R_MC_MCLK_CFG): + mc0_mclkcfg = val; + break; + case A_MC_REGISTER(0,R_MC_TIMING1): + mc0_timing1 = val; + break; + case A_SMB_CMD_0: + smbus0_cmd = val; + break; + case A_SMB_START_0: + smbus0_start = val; + break; + } +} + + +int procfield(char *txt) +{ + int num = 0; + int a,b; + spdbyte_t *sf; + encvalue_t *ev; + char *x; + char *tok; + + x = strchr(txt,'='); + if (!x) { + printf("Fields must be specified as 'name=value'\n"); + exit(1); + } + *x++ = '\0'; + + sf = spdfields; + while (sf->name) { + if (strcmp(sf->name,txt) == 0) break; + sf++; + } + + if (sf->name == NULL) { + printf("Invalid field name: %s\n",txt); + return -1; + } + + if (memcmp(x,"0x",2) == 0) { + sscanf(x+2,"%x",&num); + } + else { + if (strchr(x,'.')) { + if (sscanf(x,"%d.%d",&a,&b) != 2) { + printf("%s: invalid number: %s\n",sf->name,x); + return -1; + } + } + else { + a = atoi(x); + b = 0; + } + + switch (sf->decimal) { + case SPD_DEC_BCD: + if ((b < 0) || (b > 9)) { + printf("%s: Invalid BCD number: %s\n",sf->name,x); + return -1; + } + num = (a*16)+b; + break; + case SPD_DEC_QTR: + if ((b != 0) && (b != 25) && (b != 50) && (b != 75)) { + printf("%s: Invalid 2-bit fraction number: %s\n",sf->name,x); + printf("(number after decimal should be 0,25,50,75)\n"); + exit(1); + } + num = (a*4)+(b/25); + break; + case SPD_ENCODED: + ev = sf->values; + while (ev->name) { + if (strcmp(ev->name,x) == 0) break; + ev++; + } + if (!ev->name) { + printf("%s: Invalid value. Valid values are: ",x); + ev = sf->values; + while (ev->name) { printf("%s ",ev->name); ev++; } + printf("\n"); + return -1; + } + num = ev->val; + break; + case SPD_ENCODED2: + tok = strtok(x," ,"); + num = 0; + while (tok) { + ev = sf->values; + while (ev->name) { + if (strcmp(ev->name,tok) == 0) break; + ev++; + } + if (!ev->name) { + printf("%s: Invalid value. Valid values are: ",tok); + ev = sf->values; + while (ev->name) { printf("%s ",ev->name); ev++; } + printf("\n"); + return -1; + } + num |= ev->val; + tok = strtok(NULL," ,"); + } + break; + default: + num = a; + break; + } + } + + *(sf->data) = num; + + return 0; +} + +void interactive(void) +{ + spdbyte_t *sf; + char field[100]; + char ask[100]; + char prompt[100]; + char *x; + + sf = spdfields; + + printf("%-65.65s: Value\n","Parameter"); + printf("%-65.65s: -----\n","-----------------------------------------------------------------"); + + while (sf->name) { + for (;;) { + x = prompt; + x += sprintf(x,"%s (%s", sf->name,sf->description); + if (sf->units && sf->units[0]) { + if (sf->description && sf->description[0]) x += sprintf(x,", "); + x += sprintf(x,"%s",sf->units); + } + x += sprintf(x,"): [%s]", sf->deflt); + printf("%-65.65s: ",prompt); + + fgets(ask,sizeof(ask),stdin); + if ((x = strchr(ask,'\n'))) *x = '\0'; + if (ask[0] == 0) strcpy(ask,sf->deflt); + sprintf(field,"%s=%s",sf->name,ask); + if (procfield(field) < 0) continue; + break; + } + sf++; + } + + printf("\n\n"); +} + +int swcnt = 0; +char *swnames[32]; + +int proc_args(int argc,char *argv[]) +{ + int inidx,outidx; + + outidx = 1; + + for (inidx = 1; inidx < argc; inidx++) { + if (argv[inidx][0] != '-') { + argv[outidx++] = argv[inidx]; + } + else { + swnames[swcnt] = argv[inidx]; + swcnt++; + } + } + + return outidx; +} + +int swisset(char *x) +{ + int idx; + + for (idx = 0; idx < swcnt; idx++) { + if (strcmp(x,swnames[idx]) == 0) return 1; + } + return 0; +} + +void dumpmclkcfg(uint64_t val) +{ + printf("clk_ratio = %d\n",G_MC_CLK_RATIO(val)); + printf("ref_rate = %d\n",G_MC_REF_RATE(val)); + +} + +void dumptiming1(uint64_t val) +{ + printf("w2rIdle = %d\n",(val & M_MC_w2rIDLE_TWOCYCLES) ? 1 : 0); + printf("r2rIdle = %d\n",(val & M_MC_r2rIDLE_TWOCYCLES) ? 1 : 0); + printf("r2wIdle = %d\n",(val & M_MC_r2wIDLE_TWOCYCLES) ? 1 : 0); + printf("tCrD = %d\n",(int)G_MC_tCrD(val)); + printf("tCrDh = %d\n",(val & M_MC_tCrDh) ? 1 : 0); + printf("tFIFO = %d\n",(int)G_MC_tFIFO(val)); + printf("tCwD = %d\n",(int)G_MC_tCwD(val)); + + printf("tRP = %d\n",(int)G_MC_tRP(val)); + printf("tRRD = %d\n",(int)G_MC_tRRD(val)); + printf("tRCD = %d\n",(int)G_MC_tRCD(val)); + + printf("tRFC = %d\n",(int)G_MC_tRFC(val)); + printf("tRCw = %d\n",(int)G_MC_tRCw(val)); + printf("tRCr = %d\n",(int)G_MC_tRCr(val)); + printf("tCwCr = %d\n",(int)G_MC_tCwCr(val)); +} + +int main(int argc,char *argv[]) +{ + spdbyte_t *sf; + uint8_t t; + int idx; + int mclk; + draminittab_t *init; + + spd[JEDEC_SPD_MEMTYPE] = JEDEC_MEMTYPE_DDRSDRAM2; + spd[JEDEC_SPD_ROWS] = 13; + spd[JEDEC_SPD_COLS] = 9; + spd[JEDEC_SPD_BANKS] = 2; + spd[JEDEC_SPD_SIDES] = 1; + spd[JEDEC_SPD_WIDTH] = 72; + + argc = proc_args(argc,argv); + + if ((argc == 1) && !swisset("-i")) { + printf("usage: memconfig name=value name=value ...\n"); + printf("\n"); + printf("Available fields: "); + sf = spdfields; + while (sf->name) { + printf("%s ",sf->name); + sf++; + } + printf("\n"); + exit(1); + } + + if (swisset("-i")) { + interactive(); + } + else { + for (idx = 1; idx < argc; idx++) { + if (procfield(argv[idx]) < 0) exit(1); + } + } + + debug = swisset("-d"); + + printf("-------Memory Parameters---------\n"); + + sf = spdfields; + while (sf->name) { + char buffer[64]; + char *p = buffer; + + t = *(sf->data); + printf("%-10.10s = 0x%02X ",sf->name,t); + switch (sf->decimal) { + case SPD_DEC_BCD: + p += sprintf(p,"(%d.%d)", + t >> 4, t & 0x0F); + break; + case SPD_DEC_QTR: + p += sprintf(p,"(%d.%02d)", + t/4,(t&3)*25); + break; + case SPD_ENCODED: + p += sprintf(p,"(%s)",lookupstr(sf->values,t)); + break; + default: + p += sprintf(p,"(%d)",t); + break; + } + + p += sprintf(p," %s",sf->units); + printf("%-16.16s %s\n",buffer,sf->description); + sf++; + } + + printf("\n"); + + init = &inittab[0]; + memset(inittab,0,sizeof(inittab)); + + init->gbl.gbl_type = MCR_GLOBALS; + init->gbl.gbl_intlv_ch = portintlv; + init++; + + init->cfg.cfg_type = MCR_CHCFG; + init->cfg.cfg_chan = 0; + init->cfg.cfg_mintmemclk = mintmemclk; + init->cfg.cfg_dramtype = dramtype; + init->cfg.cfg_pagepolicy = CASCHECK; + init->cfg.cfg_blksize = BLKSIZE32; + init->cfg.cfg_intlv_cs = NOCSINTLV; + init->cfg.cfg_ecc = 0; + init->cfg.cfg_roundtrip = roundtrip; + init++; + + init->clk.clk_type = MCR_CLKCFG; + init->clk.clk_addrskew = addrskew; + init->clk.clk_dqoskew = dqoskew; + init->clk.clk_dqiskew = dqiskew; + init->clk.clk_addrdrive = addrdrive; + init->clk.clk_datadrive = datadrive; + init->clk.clk_clkdrive = clkdrive; + init++; + + init->geom.geom_type = MCR_GEOM; + init->geom.geom_csel = 0; + init->geom.geom_rows = spd[JEDEC_SPD_ROWS]; + init->geom.geom_cols = spd[JEDEC_SPD_COLS]; + init->geom.geom_banks = spd[JEDEC_SPD_BANKS]; + init++; + +#if 0 + init->tmg.tmg_type = MCR_TIMING; + init->tmg.tmg_tCK = spd[JEDEC_SPD_tCK25]; + init->tmg.tmg_rfsh = spd[JEDEC_SPD_RFSH]; + init->tmg.tmg_caslatency = spd[JEDEC_SPD_CASLATENCIES]; + init->tmg.tmg_attributes = spd[JEDEC_SPD_ATTRIBUTES]; + init->tmg.tmg_tRAS = spd[JEDEC_SPD_tRAS]; + init->tmg.tmg_tRP = spd[JEDEC_SPD_tRP]; + init->tmg.tmg_tRRD = spd[JEDEC_SPD_tRRD]; + init->tmg.tmg_tRCD = spd[JEDEC_SPD_tRCD]; + init->tmg.tmg_tRFC = spd[JEDEC_SPD_tRFC]; + init->tmg.tmg_tRC = spd[JEDEC_SPD_tRC]; + init++; +#else + init->spd.spd_type = MCR_SPD; + init->spd.spd_csel = 0; + init->spd.spd_flags = 0; + init->spd.spd_smbuschan = 0; + init->spd.spd_smbusdev = 0x50; + init++; +#endif + + init->mcr.mcr_type = MCR_EOT; + + + sb1250_refclk = (int) refclk; + + sb1250_dram_init(inittab); + + + printf("-----Memory Timing Register Values-----\n"); + printf("System Clock %dMHz\n",plldiv*refclk/2); + printf("CAS latency %d.%d\n",dram_cas_latency>>1,(dram_cas_latency&1)?5:0); + printf("tMemClk %d.%d ns\n",dram_tMemClk/10,dram_tMemClk%10); + mclk = (plldiv*refclk)*10/2/((int)G_MC_CLK_RATIO(mc0_mclkcfg)); + printf("MCLK Freq %d.%dMHz\n",mclk/10,mclk%10); + printf("\n"); + printf("MC_TIMING1 = %016llX\n",mc0_timing1); + printf("MCLK_CONFIG = %016llX\n",mc0_mclkcfg); + printf("\n"); + + printf("-----Memory Timing Register Fields-----\n"); + dumptiming1(mc0_timing1); + + printf("-----Memory Clock Config Register Fields-----\n"); + dumpmclkcfg(mc0_mclkcfg); + + printf("---Done!---\n"); + + printf("%s ",argv[0]); + sf = spdfields; + while (sf->name) { + char buffer[64]; + char *p = buffer; + + t = *(sf->data); + + p += sprintf(p,"%s=",sf->name); + switch (sf->decimal) { + case SPD_DEC_BCD: + p += sprintf(p,"%d.%d", + t >> 4, t & 0x0F); + break; + case SPD_DEC_QTR: + p += sprintf(p,"%d.%02d", + t/4,(t&3)*25); + break; + case SPD_ENCODED: + default: + p += sprintf(p,"0x%02X",t); + break; + } + + printf("%s ",buffer); + sf++; + } + + printf("\n"); + + return 0; +} diff --git a/cfe/cfe/hosttools/mkbootimage.c b/cfe/cfe/hosttools/mkbootimage.c new file mode 100644 index 0000000..862f8ed --- /dev/null +++ b/cfe/cfe/hosttools/mkbootimage.c @@ -0,0 +1,314 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Boot block generator File: mkbootimage.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This program converts a binary file (bootstrap program) + * into a boot block by prepending the boot block sector + * to the program. It generates the appropriate + * boot block checksums and such. The resulting file may + * be used by installboot (for example) to put into a disk + * image for the simulator. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include +#include + +typedef unsigned long long uint64_t; +typedef unsigned long uint32_t; + +#include "cfe_bootblock.h" +#include +#include +#include +#include + +#define roundup(x,align) (((x)+(align)-1)&~((align)-1)) +#define howmany(x,align) (((x)+(align)-1)/(align)) + +static int verbose = 0; +static int big_endian = 1; +static int swapflg = 1; +static unsigned long sector_offset = 0; + +static void usage(void) +{ + fprintf(stderr,"usage: mkbootimage [-S ] [-v] [-EB] [-EL] inputfile outputfile\n"); + exit(1); +} + +static void bswap32(uint32_t *ptr) +{ + unsigned char b; + unsigned char *bptr; + + if (swapflg) { + bptr = (unsigned char *) ptr; + b = bptr[0]; bptr[0] = bptr[3]; bptr[3] = b; + b = bptr[1]; bptr[1] = bptr[2]; bptr[2] = b; + } +} + +static void bswap64(uint64_t *ptr) +{ + unsigned char b; + unsigned char *bptr; + + bptr = (unsigned char *) ptr; + + if (swapflg) { + b = bptr[0]; bptr[0] = bptr[7]; bptr[7] = b; + b = bptr[1]; bptr[1] = bptr[6]; bptr[6] = b; + b = bptr[2]; bptr[2] = bptr[5]; bptr[5] = b; + b = bptr[3]; bptr[3] = bptr[4]; bptr[4] = b; + } +} + + +static void bswap_bootblock(struct boot_block *bb) +{ + int idx; + + for (idx = 59; idx <= 63; idx++) { + bswap64(&(bb->bb_data[idx])); + } +} + +static void do_checksum(void *ptr,int length,uint32_t *csptr,int swap) +{ + uint32_t *p; + uint32_t chksum = 0; + uint32_t d; + + p = (uint32_t *) ptr; + + length /= sizeof(uint32_t); + + while (length) { + d = *p; + if (swap) bswap32(&d); + chksum += d; + p++; + length--; + } + + if (swap) bswap32(&chksum); + + *csptr = chksum; +} + + +static void dumpbootblock(struct boot_block *bb) +{ + int idx; + + fprintf(stderr,"Magic Number: %016llX\n", + bb->bb_magic); + fprintf(stderr,"Boot code offset: %llu\n", + (unsigned long long)bb->bb_secstart); + fprintf(stderr,"Boot code size: %u\n", + (uint32_t) (bb->bb_secsize & BOOT_SECSIZE_MASK)); + fprintf(stderr,"Header checksum: %08X\n", + (uint32_t) (bb->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK)); + fprintf(stderr,"Header version: %d\n", + (uint32_t) ((bb->bb_hdrinfo & BOOT_HDR_VER_MASK) >> BOOT_HDR_VER_SHIFT)); + fprintf(stderr,"Data checksum: %08X\n", + (uint32_t) ((bb->bb_secsize & BOOT_DATA_CHECKSUM_MASK) >> BOOT_DATA_CHECKSUM_SHIFT)); + fprintf(stderr,"Architecture info: %08X\n", + (uint32_t) (bb->bb_archinfo & BOOT_ARCHINFO_MASK)); + fprintf(stderr,"\n"); + + for (idx = 59; idx <= 63; idx++) { + fprintf(stderr,"Word %d = %016llX\n",idx,bb->bb_data[idx]); + } +} + +static int host_is_little(void) +{ + unsigned long var = 1; + unsigned char *pvar = (unsigned char *) &var; + + return (*pvar == 1); +} + +int main(int argc, char *argv[]) +{ + int fh; + long bootsize; + long bootbufsize; + unsigned char *bootcode; + struct boot_block bootblock; + uint32_t datacsum,hdrcsum; + int host_le; + + while ((argc > 1) && (argv[1][0] == '-')) { + if (strcmp(argv[1],"-v") == 0) { + verbose = 1; + } + else if (strcmp(argv[1],"-EB") == 0) { + big_endian = 1; + } + else if (strcmp(argv[1],"-EL") == 0) { + big_endian = 0; + } + else if (strcmp(argv[1],"-S") == 0) { + char *tmp_ptr; + argv++; + argc--; + if (argc == 1) { + fprintf(stderr,"-S requires an argument\n"); + exit(1); + } + sector_offset = strtoul(argv[1], &tmp_ptr, 0); + if (*tmp_ptr) { + fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]); + exit(1); + } + } + else { + fprintf(stderr,"Invalid switch: %s\n",argv[1]); + exit(1); + } + argv++; + argc--; + } + + /* + * We need to swap things around if the host and + * target are different endianness + */ + + swapflg = 0; + host_le = host_is_little(); + + if (big_endian && host_is_little()) swapflg = 1; + if ((big_endian == 0) && !(host_is_little())) swapflg = 1; + + fprintf(stderr,"Host is %s-endian.\n",host_le ? "little" : "big"); + fprintf(stderr,"Target is %s-endian.\n",big_endian ? "big" : "little"); + + if (argc != 3) { + usage(); + } + + /* + * Read in the boot file + */ + + fh = open(argv[1],O_RDONLY); + if (fh < 0) { + perror(argv[1]); + } + + bootsize = lseek(fh,0L,SEEK_END); + lseek(fh,0L,SEEK_SET); + + bootbufsize = roundup(bootsize,BOOT_BLOCK_BLOCKSIZE); + + bootcode = malloc(bootbufsize); + if (bootcode == NULL) { + perror("malloc"); + exit(1); + } + memset(bootcode,0,bootbufsize); + if (read(fh,bootcode,bootsize) != bootsize) { + perror("read"); + exit(1); + } + + close(fh); + + /* + * Construct the boot block + */ + + + /* Checksum the boot code */ + do_checksum(bootcode,bootbufsize,&datacsum,1); + bswap32(&datacsum); + + + /* fill in the boot block fields, and checksum the boot block */ + bootblock.bb_magic = BOOT_MAGIC_NUMBER; + bootblock.bb_hdrinfo = (((uint64_t) BOOT_HDR_VERSION) << BOOT_HDR_VER_SHIFT); + bootblock.bb_secstart = BOOT_BLOCK_BLOCKSIZE + (sector_offset * 512); + bootblock.bb_secsize = ((uint64_t) bootbufsize) | + (((uint64_t) datacsum) << BOOT_DATA_CHECKSUM_SHIFT); + bootblock.bb_archinfo = 0; /* XXX */ + + do_checksum(&(bootblock.bb_magic),BOOT_BLOCK_SIZE,&hdrcsum,0); + bootblock.bb_hdrinfo |= (uint64_t) hdrcsum; + + if (verbose) dumpbootblock(&bootblock); + + bswap_bootblock(&bootblock); + + /* + * Now write the output file + */ + + fh = open(argv[2],O_RDWR|O_CREAT,S_IREAD|S_IWRITE); + if (fh < 0) { + perror(argv[2]); + exit(1); + } + if (lseek(fh, sector_offset * 512, SEEK_SET) != (sector_offset * 512)) { + perror(argv[2]); + exit(1); + } + if (write(fh,&bootblock,sizeof(bootblock)) != sizeof(bootblock)) { + perror(argv[2]); + exit(1); + } + if (write(fh,bootcode,bootbufsize) != bootbufsize) { + perror(argv[2]); + exit(1); + } + + close(fh); + + fprintf(stderr,"%s -> %s : OK\n",argv[1],argv[2]); + + exit(0); + + +} + diff --git a/cfe/cfe/hosttools/mkflashimage.c b/cfe/cfe/hosttools/mkflashimage.c new file mode 100644 index 0000000..84ec77c --- /dev/null +++ b/cfe/cfe/hosttools/mkflashimage.c @@ -0,0 +1,347 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash Image generator File: mkflashimage.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This program sticks a header on the front of a binary + * file making it suitable for use with the 'flash' command + * in CFE. The header contains the CFE version # and board + * type, a CRC, and other info to help prevent us from + * flashing bad stuff onto a board. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include +#include + +#ifndef _SYS_INT_TYPES_H +typedef unsigned char uint8_t; +typedef unsigned long long uint64_t; +typedef unsigned long uint32_t; +#endif + +#include "cfe_flashimage.h" +#include +#include +#include +#include + + +static int verbose = 0; +static int big_endian = 1; +static int both_endian = 0; +int mlong64 = 0; +char boardname[32]; + +/* + * This is the offset in the flash where the little-endian image goes + * if we're making a bi-endian flash. + */ + +#define CFE_BIENDIAN_LE_OFFSET (1024*1024) + +static void usage(void) +{ + fprintf(stderr,"usage: mkflashimage [-v] [-EB] [-EL] [-64] [-B boardname] [-V v.v.v] binfile outfile\n"); + fprintf(stderr,"\n"); + fprintf(stderr," mkflashimage [-v] -EX [-64] [-B boardname] [-V v.v.v] BE-binfile LE-binfile outfile\n"); + fprintf(stderr," (this variant used for making bi-endian flash files)\n"); + exit(1); +} + + +static int host_is_little(void) +{ + unsigned long var = 1; + unsigned char *pvar = (unsigned char *) &var; + + return (*pvar == 1); +} + +#define CRC32_POLY 0xEDB88320UL /* CRC-32 Poly */ + +static unsigned int +crc32(const unsigned char *databuf, unsigned int datalen) +{ + unsigned int idx, bit, data, crc = 0xFFFFFFFFUL; + + for (idx = 0; idx < datalen; idx++) { + for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) { + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CRC32_POLY : 0); + } + } + + return crc; +} + + +void stuff_be32(uint8_t *dest,unsigned int src) +{ + *dest++ = (src >> 24) & 0xFF; + *dest++ = (src >> 16) & 0xFF; + *dest++ = (src >> 8) & 0xFF; + *dest++ = (src >> 0) & 0xFF; +} + +int main(int argc, char *argv[]) +{ + int fh; + int flashsize; + unsigned char *flashcode; + cfe_flashimage_t header; + int host_le; + int majver,minver,ecover; + uint32_t crc; + uint32_t flags; + char *outfile; + + majver = minver = ecover = 0; + boardname[0] = 0; + + while ((argc > 1) && (argv[1][0] == '-')) { + if (strcmp(argv[1],"-v") == 0) { + verbose = 1; + } + else if (strcmp(argv[1],"-EX") == 0) { + if (verbose) fprintf(stderr,"[Image file will be marked Bi-Endian]\n"); + both_endian = 1; + } + else if (strcmp(argv[1],"-EB") == 0) { + if (verbose) fprintf(stderr,"[Image file will be marked Big-Endian]\n"); + big_endian = 1; + } + else if (strcmp(argv[1],"-EL") == 0) { + if (verbose) fprintf(stderr,"[Image file will be marked Little-Endian]\n"); + big_endian = 0; + } + else if (strcmp(argv[1],"-64") == 0) { + if (verbose) fprintf(stderr,"[Image file will be marked 64-bit]\n"); + mlong64 = 1; + } + else if (strcmp(argv[1],"-B") == 0) { + argc--; + argv++; + strcpy(boardname,argv[1]); + if (verbose) fprintf(stderr,"[Board name: %s]\n",boardname); + } + else if (strcmp(argv[1],"-V") == 0) { + argc--; + argv++; + sscanf(argv[1],"%d.%d.%d",&majver,&minver,&ecover); + if (verbose) fprintf(stderr,"[Image version: %d.%d.%d]\n",majver,minver,ecover); + } + else { + fprintf(stderr,"Invalid switch: %s\n",argv[1]); + exit(1); + } + argv++; + argc--; + } + + /* + * We need to swap things around if the host and + * target are different endianness + */ + + host_le = host_is_little(); + + if (verbose) { + fprintf(stderr,"Host is %s-endian.\n",host_le ? "little" : "big"); + if (both_endian) { + fprintf(stderr,"Target is bi-endian.\n"); + } + else { + fprintf(stderr,"Target is %s-endian.\n",big_endian ? "big" : "little"); + } + } + + if ((both_endian && (argc != 4)) || (!both_endian && (argc != 3))) { + usage(); + } + + /* + * Read in the boot file(s) + */ + + flags = 0; + + if (both_endian) { + int be_size; + + flags |= (CFE_IMAGE_EB | CFE_IMAGE_EL); + + if (verbose) fprintf(stderr,"Reading: %s\n",argv[2]); + + fh = open(argv[2],O_RDONLY); + if (fh < 0) { + perror(argv[2]); + } + + flashsize = lseek(fh,0L,SEEK_END); + lseek(fh,0L,SEEK_SET); + + flashcode = malloc(flashsize+CFE_BIENDIAN_LE_OFFSET); + if (flashcode == NULL) { + perror("malloc"); + exit(1); + } + memset(flashcode,0xFF,flashsize+CFE_BIENDIAN_LE_OFFSET); + + if (read(fh,flashcode+CFE_BIENDIAN_LE_OFFSET,flashsize) != flashsize) { + perror("read"); + exit(1); + } + + close(fh); + + if (memcmp(flashcode+CFE_BIENDIAN_LE_OFFSET,CFE_IMAGE_SEAL,4) == 0) { + fprintf(stderr,"File '%s' already has an image header.\n",argv[2]); + exit(1); + } + + flashsize += CFE_BIENDIAN_LE_OFFSET; /* actual file size */ + + if (verbose) fprintf(stderr,"Reading: %s\n",argv[1]); + + fh = open(argv[1],O_RDONLY); + if (fh < 0) { + perror(argv[1]); + exit(1); + } + + be_size = lseek(fh,0L,SEEK_END); + lseek(fh,0L,SEEK_SET); + if (be_size > CFE_BIENDIAN_LE_OFFSET) { + fprintf(stderr,"File '%s' will not fit within first %d bytes of flash image\n", + argv[1],CFE_BIENDIAN_LE_OFFSET); + close(fh); + exit(1); + } + + if (read(fh,flashcode,be_size) != be_size) { + perror("read"); + exit(1); + } + + close(fh); + + outfile = argv[3]; + + } + else { + if (big_endian) flags |= CFE_IMAGE_EB; + else flags |= CFE_IMAGE_EL; + + fh = open(argv[1],O_RDONLY); + if (fh < 0) { + perror(argv[1]); + exit(1); + } + + flashsize = lseek(fh,0L,SEEK_END); + lseek(fh,0L,SEEK_SET); + + flashcode = malloc(flashsize); + if (flashcode == NULL) { + perror("malloc"); + exit(1); + } + memset(flashcode,0,flashsize); + if (read(fh,flashcode,flashsize) != flashsize) { + perror("read"); + exit(1); + } + + close(fh); + + if (memcmp(flashcode,CFE_IMAGE_SEAL,4) == 0) { + fprintf(stderr,"File '%s' already has an image header.\n",argv[1]); + exit(1); + } + + outfile = argv[2]; + } + + + /* + * Construct the flash header + */ + + if (mlong64) flags |= CFE_IMAGE_MLONG64; + crc = crc32(flashcode,flashsize); + + memset(&header,0,sizeof(header)); + memcpy(header.seal,CFE_IMAGE_SEAL,sizeof(header.seal)); + stuff_be32(header.flags,flags); + stuff_be32(header.size,flashsize); + stuff_be32(header.crc,crc); + header.majver = majver; + header.minver = minver; + header.ecover = ecover; + header.miscver = 0; + strcpy(header.boardname,boardname); + + /* + * Now write the output file + */ + + fh = open(outfile,O_RDWR|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE|S_IRGRP|S_IWGRP|S_IROTH); + if (fh < 0) { + perror(outfile); + exit(1); + } + if (write(fh,&header,sizeof(header)) != sizeof(header)) { + perror(outfile); + exit(1); + } + if (write(fh,flashcode,flashsize) != flashsize) { + perror(outfile); + exit(1); + } + + fprintf(stderr,"Wrote %d bytes to %s\n",sizeof(header)+flashsize,outfile); + + close(fh); + + exit(0); + + +} + diff --git a/cfe/cfe/hosttools/mkpcidb.c b/cfe/cfe/hosttools/mkpcidb.c new file mode 100644 index 0000000..fe7d314 --- /dev/null +++ b/cfe/cfe/hosttools/mkpcidb.c @@ -0,0 +1,157 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PCI Table Generator File: mkpcidb.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This program munges the PCI table into a form that uses + * fewer embedded pointers. Pointers are evil for the + * relocatable version of CFE since they chew up valuable + * initialized data segment space, and we only have + * 64KB of that. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include + +typedef unsigned short pci_vendor_id_t; +typedef unsigned short pci_product_id_t; + +struct pci_knowndev { + pci_vendor_id_t vendor; + pci_product_id_t product; + int flags; + char *vendorname, *productname; +}; + +#include "../pci/pcidevs.h" +#define PCI_KNOWNDEV_NOPROD 0x01 +#include "../pci/pcidevs_data.h" + + + +struct pci_knowndev2 { + pci_vendor_id_t vendor; + pci_product_id_t product; + int flags; + int vendorname; + int productname; +}; + +#define MAXPCIDEVS 5000 +#define MAXSTRINGTABLE (1024*1024) + +struct pci_knowndev2 knowndevs[MAXPCIDEVS]; +char stringtable[MAXSTRINGTABLE]; +int curstringptr = 0; + +int allocstring(char *string) +{ + int ptr; + + if (!string) return -1; + + ptr = curstringptr; + strcpy(&stringtable[ptr],string); + curstringptr += strlen(string)+1; + return ptr; +} + +int main(int argc,char *argv[]) +{ + struct pci_knowndev2 *outdev; + const struct pci_knowndev *indev; + int cnt = 0; + int idx; + + indev = pci_knowndevs; + outdev = knowndevs; + cnt = 0; + + while (indev->vendorname) { + outdev->vendor = indev->vendor; + outdev->product = indev->product; + outdev->flags = indev->flags; + outdev->vendorname = allocstring(indev->vendorname); + outdev->productname = allocstring(indev->productname); + cnt++; + indev++; + outdev++; + } + + outdev->vendor = 0; + outdev->product = 0; + outdev->flags = 0; + outdev->vendorname = -1; + outdev->productname = -1; + cnt++; + + fprintf(stderr,"%d total devices (%d bytes), %d bytes of strings\n", + cnt,cnt*sizeof(struct pci_knowndev2),curstringptr); + + printf("\n\n\n"); + printf("const static struct pci_knowndev2 _pci_knowndevs[] __attribute__ ((section (\".text\"))) = {\n"); + for (idx = 0; idx < cnt; idx++) { + printf("\t{0x%04X,0x%04X,0x%08X,%d,%d},\n", + knowndevs[idx].vendor, + knowndevs[idx].product, + knowndevs[idx].flags, + knowndevs[idx].vendorname, + knowndevs[idx].productname); + } + printf("};\n\n\n"); + printf("const static char _pci_knowndevs_text[] __attribute__ ((section (\".text\"))) = {\n"); + for (idx = 0; idx < curstringptr; idx++) { + if ((idx % 16) == 0) printf("\t"); + printf("0x%02X,",stringtable[idx]); + if ((idx % 16) == 15) printf("\n"); + } + printf("0};\n\n"); + + printf("static const struct pci_knowndev2 *pci_knowndevs = _pci_knowndevs;\n"); + printf("static const char *pci_knowndevs_text = _pci_knowndevs_text;\n"); + printf("#define PCI_STRING_NULL (-1)\n"); + printf("#define PCI_STRING(x) (&pci_knowndevs_text[(x)])\n\n"); + + + + exit(0); +} + + diff --git a/cfe/cfe/include/cfe.h b/cfe/cfe/include/cfe.h new file mode 100755 index 0000000..013fb13 --- /dev/null +++ b/cfe/cfe/include/cfe.h @@ -0,0 +1,101 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * CFE version # and prototypes File: cfe.h + * + * CFE's version # temporarily lives here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Version number + ********************************************************************* */ + +#define CFE_VER_MAJOR CFE_VER_MAJ +#define CFE_VER_MINOR CFE_VER_MIN +#define CFE_VER_BUILD CFE_VER_ECO + +/* Numbers must not exceed 255 */ +#define BCM63XX_MAJOR 106 +#define BCM63XX_MINOR 24 + +/* ********************************************************************* + * Some runtime startup parameters + ********************************************************************* */ +#if !defined(__ASSEMBLER__) +extern unsigned cfe_startflags; +#endif + +#define CFE_INIT_USER 0x0000FFFF /* these are BSP-specific flags */ +#define CFE_INIT_SAFE 0x00010000 /* "Safe mode" */ +#define CFE_INIT_PCI 0x00020000 /* Initialize PCI */ +#define CFE_LDT_SLAVE 0x00040000 /* Select LDT slave mode */ + +/* ********************************************************************* + * Other constants + ********************************************************************* */ + +#define CFE_MAX_HANDLE 64 /* max file handles */ + +#if !defined(__ASSEMBLER__) + +/* ********************************************************************* + * prototypes + ********************************************************************* */ + +void board_console_init(void); +void board_device_init(void); +void board_final_init(void); +void board_device_reset(void); +#define CFE_BUFFER_CONSOLE "buffer" +int cfe_set_console(char *); +int cfe_set_envdevice(char *); +void cfe_restart(void); +void cfe_command_loop(void); +void cfe_leds(unsigned int val); +void cfe_ledstr(const char *str); +void cfe_launch(unsigned long ept); +void cfe_start(unsigned long ept); +void cfe_warmstart(unsigned long long); +#define SETLEDS(x) cfe_ledstr(x) +const char *cfe_errortext(int err); + +#endif diff --git a/cfe/cfe/include/cfe_autoboot.h b/cfe/cfe/include/cfe_autoboot.h new file mode 100644 index 0000000..603803b --- /dev/null +++ b/cfe/cfe/include/cfe_autoboot.h @@ -0,0 +1,71 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Automatic OS bootstrap File: cfe_autoboot.h + * + * This module handles OS bootstrap stuff. We use this version + * to do "automatic" booting; walking down a list of possible boot + * options, trying them until something good happens. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#define CFE_AUTOBOOT_END 0 +#define CFE_AUTOBOOT_NETWORK 1 +#define CFE_AUTOBOOT_DISK 2 +#define CFE_AUTOBOOT_RAW 3 + +typedef struct cfe_autoboot_method_s { + queue_t ab_qblock; + int ab_type; + int ab_flags; + char *ab_dev; + char *ab_loader; + char *ab_filesys; + char *ab_file; +} cfe_autoboot_method_t; + +#define CFE_AUTOFLG_POLLCONSOLE 1 /* boot can be interrupted */ +#define CFE_AUTOFLG_TRYFOREVER 2 /* keep trying forever */ + +int cfe_autoboot(char *dev,int flags); +int cfe_add_autoboot(int type,int flags,char *dev,char *loader,char *filesys,char *file); + + diff --git a/cfe/cfe/include/cfe_boot.h b/cfe/cfe/include/cfe_boot.h new file mode 100644 index 0000000..93c3c6d --- /dev/null +++ b/cfe/cfe/include/cfe_boot.h @@ -0,0 +1,58 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Bootstrap prototypes File: cfe_boot.h + * + * Prototypes for main bootstrap routines + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define BOOT_START_ADDRESS 0x20000000 /* VA of boot area */ +#define BOOT_AREA_SIZE (256*1024) /* 256K */ + + + + diff --git a/cfe/cfe/include/cfe_bootblock.h b/cfe/cfe/include/cfe_bootblock.h new file mode 100644 index 0000000..c3a93f0 --- /dev/null +++ b/cfe/cfe/include/cfe_bootblock.h @@ -0,0 +1,129 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Boot Block File: cfe_bootblock.h + * + * The structure of the boot block used on block-style devices + * like disks and CDROMs + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* + * CFE boot block, modeled loosely on Alpha. + * + * It consists of: + * + * BSD disk label + * + * Boot block info (5 u_int_64s) + * + * The boot block portion looks like: + * + * + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | BOOT_MAGIC_NUMBER | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | Flags | Reserved | Vers | Header Checksum | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | Secondary Loader Location (bytes) | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | Loader Checksum | Size of loader (bytes) | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | Reserved | Architecture Information | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * Boot block fields should always be read as 64-bit numbers. + * + */ + + +struct boot_block { + uint64_t bb_data[64]; /* data (disklabel, also as below) */ +}; +#define bb_magic bb_data[59] /* magic number */ +#define bb_hdrinfo bb_data[60] /* header checksum, ver, flags */ +#define bb_secstart bb_data[61] /* secondary start (bytes) */ +#define bb_secsize bb_data[62] /* secondary size (bytes) */ +#define bb_archinfo bb_data[63] /* architecture info */ + +#define BOOT_BLOCK_OFFSET 0 /* offset of boot block. */ +#define BOOT_BLOCK_BLOCKSIZE 512 /* block size for sec. size/start, + * and for boot block itself + */ +#define BOOT_BLOCK_SIZE 40 /* 5 64-bit words */ + +/* + * This is the highest block number that we look at when + * searching for a valid boot block + */ +#define BOOT_BLOCK_MAXLOC 16 + +/* + * Fields within the boot block + */ +#define _U64(x) ((uint64_t) x) +#define BOOT_MAGIC_NUMBER _U64(0x43465631424f4f54) +#define BOOT_HDR_CHECKSUM_MASK _U64(0x00000000FFFFFFFF) +#define BOOT_HDR_VER_MASK _U64(0x000000FF00000000) +#define BOOT_HDR_VER_SHIFT 32 +#define BOOT_HDR_FLAGS_MASK _U64(0xFF00000000000000) +#define BOOT_SECSIZE_MASK _U64(0x00000000FFFFFFFF) +#define BOOT_DATA_CHECKSUM_MASK _U64(0xFFFFFFFF00000000) +#define BOOT_DATA_CHECKSUM_SHIFT 32 +#define BOOT_ARCHINFO_MASK _U64(0x00000000FFFFFFFF) + +#define BOOT_HDR_VERSION 1 + +#define CHECKSUM_BOOT_DATA(data,len,cksum) \ + do { \ + uint32_t *_ptr = (uint32_t *) (data); \ + uint32_t _cksum; \ + int _i; \ + \ + _cksum = 0; \ + for (_i = 0; \ + _i < ((len) / sizeof (uint32_t)); \ + _i++) \ + _cksum += _ptr[_i]; \ + *(cksum) = _cksum; \ + } while (0) + + diff --git a/cfe/cfe/include/cfe_console.h b/cfe/cfe/include/cfe_console.h new file mode 100755 index 0000000..7ee1056 --- /dev/null +++ b/cfe/cfe/include/cfe_console.h @@ -0,0 +1,92 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Console prototypes File: cfe_console.c + * + * Prototypes for routines dealing with the console. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define VKEY(x) (0x100|(x)) +#define VKEY_UP VKEY(1) +#define VKEY_DOWN VKEY(2) +#define VKEY_LEFT VKEY(3) +#define VKEY_RIGHT VKEY(4) +#define VKEY_PGUP VKEY(5) +#define VKEY_PGDN VKEY(6) +#define VKEY_HOME VKEY(7) +#define VKEY_END VKEY(8) +#define VKEY_F1 VKEY(0x10) +#define VKEY_F2 VKEY(0x11) +#define VKEY_F3 VKEY(0x12) +#define VKEY_F4 VKEY(0x13) +#define VKEY_F5 VKEY(0x14) +#define VKEY_F6 VKEY(0x15) +#define VKEY_F7 VKEY(0x16) +#define VKEY_F8 VKEY(0x17) +#define VKEY_F9 VKEY(0x18) +#define VKEY_F10 VKEY(0x19) +#define VKEY_F11 VKEY(0x1A) +#define VKEY_F12 VKEY(0x1B) +#define VKEY_ESC 27 + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int console_open(char *name); +int console_close(void); +int console_read(char *buffer,int length); +int console_write(char *buffer,int length); +int console_status(void); +int console_readkey(void); +int console_readline(char *prompt,char *str,int len); +int console_readline_noedit(char *prompt,char *str,int len); +int console_readline(char *prompt,char *str,int len); +extern char *console_name; +extern int console_handle; +void console_log(const char *tmplt,...); + + diff --git a/cfe/cfe/include/cfe_devfuncs.h b/cfe/cfe/include/cfe_devfuncs.h new file mode 100644 index 0000000..207c4a6 --- /dev/null +++ b/cfe/cfe/include/cfe_devfuncs.h @@ -0,0 +1,76 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device function prototypes File: cfe_devfuncs.h + * + * This module contains prototypes for cfe_devfuncs.c, a set + * of wrapper routines to the IOCB interface. This file, + * along with cfe_devfuncs.c, can be incorporated into programs + * that need to call CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#define CFE_EPTSEAL 0x43464531 +#if (CFG_BIENDIAN) && defined(__MIPSEB) +#define CFE_EPTSEAL_REV 0x31454643 +#endif + +#define CFE_APISEAL 0xBFC004E0 +#define CFE_APIENTRY 0xBFC00500 + + + +#ifndef __ASSEMBLER__ +int cfe_open(char *name); +int cfe_close(int handle); +int cfe_readblk(int handle,cfe_offset_t offset,unsigned char *buffer,int length); +int cfe_read(int handle,unsigned char *buffer,int length); +int cfe_writeblk(int handle,cfe_offset_t offset,unsigned char *buffer,int length); +int cfe_write(int handle,unsigned char *buffer,int length); +int cfe_ioctl(int handle,unsigned int ioctlnum,unsigned char *buffer,int length,int *retlen, + cfe_offset_t offset); +int cfe_inpstat(int handle); +int cfe_getenv(char *name,char *dest,int destlen); +long long cfe_getticks(void); +int cfe_exit(int warm,int code); +int cfe_flushcache(int flg); +int cfe_getdevinfo(char *name); +int cfe_flushcache(int); +#endif diff --git a/cfe/cfe/include/cfe_device.h b/cfe/cfe/include/cfe_device.h new file mode 100644 index 0000000..f90b167 --- /dev/null +++ b/cfe/cfe/include/cfe_device.h @@ -0,0 +1,118 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device manager definitions File: cfe_device.h + * + * Structures, constants, etc. for the device manager, which keeps + * track of installed devices in CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_DEVICE_H +#define _CFE_DEVICE_H + +#include "lib_queue.h" + +typedef struct cfe_devdisp_s cfe_devdisp_t; + + +/* + * The Device structure defines a particular instance of a device. + * They are generated as a result of calling the cfe_attach call. + */ + +typedef struct cfe_device_s { + queue_t dev_next; + char *dev_fullname; + void *dev_softc; + int dev_class; + const cfe_devdisp_t *dev_dispatch; + int dev_opencount; + char *dev_description; +} cfe_device_t; + +/* + * This is what gets returned from the OPEN call + */ +typedef struct cfe_devctx_s { + cfe_device_t *dev_dev; + void *dev_softc; + void *dev_openinfo; +} cfe_devctx_t; + + +/* + * This defines a given device class. Even though there are + * three identical MACs, there is only one of these. + */ + +struct cfe_devdisp_s { + int (*dev_open)(cfe_devctx_t *ctx); + int (*dev_read)(cfe_devctx_t *ctx,iocb_buffer_t *buffer); + int (*dev_inpstat)(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); + int (*dev_write)(cfe_devctx_t *ctx,iocb_buffer_t *buffer); + int (*dev_ioctl)(cfe_devctx_t *ctx,iocb_buffer_t *buffer); + int (*dev_close)(cfe_devctx_t *ctx); + void (*dev_poll)(cfe_devctx_t *ctx,int64_t ticks); + void (*dev_reset)(void *softc); /* called when device is closed, so no devctx_t */ +}; + + + +typedef struct cfe_driver_s { + char *drv_description; /* Description of device for SHOW commands */ + char *drv_bootname; /* Device's name prefix for open() */ + int drv_class; + const cfe_devdisp_t *drv_dispatch; + void (*drv_probe)(struct cfe_driver_s *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); +} cfe_driver_t; + +char *cfe_device_name(cfe_devctx_t *ctx); +void cfe_attach(cfe_driver_t *devname,void *softc,char *bootinfo,char *description); +int cfe_attach_idx(cfe_driver_t *drv,int idx,void *softc,char *bootinfo,char *description); +cfe_device_t *cfe_finddev(char *name); +void cfe_attach_init(void); +#define cfe_add_device(devdescr,a,b,ptr) (devdescr)->drv_probe(devdescr,a,b,ptr) +void cfe_device_reset(void); + +#endif diff --git a/cfe/cfe/include/cfe_error.h b/cfe/cfe/include/cfe_error.h new file mode 100644 index 0000000..9c564e1 --- /dev/null +++ b/cfe/cfe/include/cfe_error.h @@ -0,0 +1,110 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Error codes File: cfe_error.h + * + * CFE's global error code list is here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + + +#define CFE_OK 0 +#define CFE_ERR -1 /* generic error */ +#define CFE_ERR_INV_COMMAND -2 +#define CFE_ERR_EOF -3 +#define CFE_ERR_IOERR -4 +#define CFE_ERR_NOMEM -5 +#define CFE_ERR_DEVNOTFOUND -6 +#define CFE_ERR_DEVOPEN -7 +#define CFE_ERR_INV_PARAM -8 +#define CFE_ERR_ENVNOTFOUND -9 +#define CFE_ERR_ENVREADONLY -10 + +#define CFE_ERR_NOTELF -11 +#define CFE_ERR_NOT32BIT -12 +#define CFE_ERR_WRONGENDIAN -13 +#define CFE_ERR_BADELFVERS -14 +#define CFE_ERR_NOTMIPS -15 +#define CFE_ERR_BADELFFMT -16 +#define CFE_ERR_BADADDR -17 + +#define CFE_ERR_FILENOTFOUND -18 +#define CFE_ERR_UNSUPPORTED -19 + +#define CFE_ERR_HOSTUNKNOWN -20 + +#define CFE_ERR_TIMEOUT -21 + +#define CFE_ERR_PROTOCOLERR -22 + +#define CFE_ERR_NETDOWN -23 +#define CFE_ERR_NONAMESERVER -24 + +#define CFE_ERR_NOHANDLES -25 +#define CFE_ERR_ALREADYBOUND -26 + +#define CFE_ERR_CANNOTSET -27 +#define CFE_ERR_NOMORE -28 +#define CFE_ERR_BADFILESYS -29 +#define CFE_ERR_FSNOTAVAIL -30 + +#define CFE_ERR_INVBOOTBLOCK -31 +#define CFE_ERR_WRONGDEVTYPE -32 +#define CFE_ERR_BBCHECKSUM -33 +#define CFE_ERR_BOOTPROGCHKSUM -34 + +#define CFE_ERR_LDRNOTAVAIL -35 + +#define CFE_ERR_NOTREADY -36 + +#define CFE_ERR_GETMEM -37 +#define CFE_ERR_SETMEM -38 + +#define CFE_ERR_NOTCONN -39 +#define CFE_ERR_ADDRINUSE -40 + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#define CFE_ERR_INTR -41 +#define CFE_ERR_BADIMAGE -42 +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + + diff --git a/cfe/cfe/include/cfe_fileops.h b/cfe/cfe/include/cfe_fileops.h new file mode 100644 index 0000000..f119037 --- /dev/null +++ b/cfe/cfe/include/cfe_fileops.h @@ -0,0 +1,109 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Filesystem dispatch defs File: cfe_fileops.h + * + * CFE supports multiple access methods to files on boot + * media. This module contains the dispatch table structures + * for "file systems". + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define FILE_SEEK_BEGINNING 0 +#define FILE_SEEK_CURRENT 1 + +#define FILE_MODE_READ 1 +#define FILE_MODE_WRITE 2 + +/* These flags should not conflict with the loader arg flags (see cfe_loadargs_t) */ +#define FSYS_TYPE_NETWORK 0x40000000 + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define BDINIT(ops,fsctx,name) (ops)->init((fsctx),(name)) +#define BDOPEN(ops,ref,fsctx,name) (ops)->open((ref),(fsctx),(name),FILE_MODE_READ) +#define BDOPEN2(ops,ref,fsctx,name,mode) (ops)->open((ref),(fsctx),(name),(mode)) +#define BDOPEN_WR(ops,ref,fsctx,name) (ops)->open((ref),(fsctx),(name),FILE_MODE_WRITE) +#define BDREAD(ops,ref,buf,len) (ops)->read((ref),(buf),(len)) +#define BDWRITE(ops,ref,buf,len) (ops)->write((ref),(buf),(len)) +#define BDCLOSE(ops,ref) (ops)->close((ref)) +#define BDUNINIT(ops,ref) (ops)->uninit((ref)) +#define BDSEEK(ops,ref,offset,how) (ops)->seek((ref),(offset),(how)) + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct fileio_dispatch_s { + const char *method; + unsigned int loadflags; + int (*init)(void **fsctx,void *device); + int (*open)(void **ref,void *fsctx,char *filename,int mode); + int (*read)(void *ref,uint8_t *buf,int len); + int (*write)(void *ref,uint8_t *buf,int len); + int (*seek)(void *ref,int offset,int how); + void (*close)(void *ref); + void (*uninit)(void *devctx); +} fileio_dispatch_t; + +typedef struct fileio_ctx_s { + const fileio_dispatch_t *ops; + void *fsctx; +} fileio_ctx_t; + +const fileio_dispatch_t *cfe_findfilesys(const char *name); + +int fs_init(char *fsname,fileio_ctx_t **fsctx,void *device); +int fs_uninit(fileio_ctx_t *); +int fs_open(fileio_ctx_t *,void **ref,char *filename,int mode); +int fs_close(fileio_ctx_t *,void *ref); +int fs_read(fileio_ctx_t *,void *ref,uint8_t *buffer,int len); +int fs_write(fileio_ctx_t *,void *ref,uint8_t *buffer,int len); +int fs_seek(fileio_ctx_t *,void *ref,int offset,int how); +int fs_hook(fileio_ctx_t *fsctx,char *fsname); + + diff --git a/cfe/cfe/include/cfe_flashimage.h b/cfe/cfe/include/cfe_flashimage.h new file mode 100644 index 0000000..4e4647c --- /dev/null +++ b/cfe/cfe/include/cfe_flashimage.h @@ -0,0 +1,64 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash Image defs File: cfe_flashimage.h + * + * This file contains stuff that describes the image header on + * the front of our flash images. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +typedef struct cfe_flashimage_s { + uint8_t seal[4]; /* CFE1 */ + uint8_t flags[4]; /* Various flags, always big-endian */ + uint8_t size[4]; /* Image size, in bytes, always big-endian */ + uint8_t crc[4]; /* CRC-32, always big-endian */ + uint8_t boardname[32]; /* Board name */ + uint8_t majver,minver,ecover,miscver; /* Firmware version */ + uint8_t reserved[12]; /* not used just yet */ +} cfe_flashimage_t; /* should be 64 bytes */ + + +#define CFE_IMAGE_SEAL "CFE1" +#define CFE_IMAGE_EB 0x00000001 +#define CFE_IMAGE_EL 0x00000002 +#define CFE_IMAGE_MLONG64 0x00000004 + diff --git a/cfe/cfe/include/cfe_iocb.h b/cfe/cfe/include/cfe_iocb.h new file mode 100644 index 0000000..bc62078 --- /dev/null +++ b/cfe/cfe/include/cfe_iocb.h @@ -0,0 +1,211 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB definitions File: cfe_iocb.h + * + * This module describes CFE's IOCB structure, the main + * data structure used to communicate API requests with CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _CFE_IOCB_H +#define _CFE_IOCB_H + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_CMD_FW_GETINFO 0 +#define CFE_CMD_FW_RESTART 1 +#define CFE_CMD_FW_BOOT 2 +#define CFE_CMD_FW_CPUCTL 3 +#define CFE_CMD_FW_GETTIME 4 +#define CFE_CMD_FW_MEMENUM 5 +#define CFE_CMD_FW_FLUSHCACHE 6 + +#define CFE_CMD_DEV_GETHANDLE 9 +#define CFE_CMD_DEV_ENUM 10 +#define CFE_CMD_DEV_OPEN 11 +#define CFE_CMD_DEV_INPSTAT 12 +#define CFE_CMD_DEV_READ 13 +#define CFE_CMD_DEV_WRITE 14 +#define CFE_CMD_DEV_IOCTL 15 +#define CFE_CMD_DEV_CLOSE 16 +#define CFE_CMD_DEV_GETINFO 17 + +#define CFE_CMD_ENV_ENUM 20 +#define CFE_CMD_ENV_GET 22 +#define CFE_CMD_ENV_SET 23 +#define CFE_CMD_ENV_DEL 24 + +#define CFE_CMD_MAX 32 + +#define CFE_CMD_VENDOR_USE 0x8000 /* codes above this are for customer use */ + +#define CFE_MI_RESERVED 0 /* memory is reserved, do not use */ +#define CFE_MI_AVAILABLE 1 /* memory is available */ + +#define CFE_FLG_WARMSTART 0x00000001 +#define CFE_FLG_FULL_ARENA 0x00000001 +#define CFE_FLG_ENV_PERMANENT 0x00000001 + +#define CFE_CPU_CMD_START 1 +#define CFE_CPU_CMD_STOP 0 + +#define CFE_STDHANDLE_CONSOLE 0 + +#define CFE_DEV_NETWORK 1 +#define CFE_DEV_DISK 2 +#define CFE_DEV_FLASH 3 +#define CFE_DEV_SERIAL 4 +#define CFE_DEV_CPU 5 +#define CFE_DEV_NVRAM 6 +#define CFE_DEV_CLOCK 7 +#define CFE_DEV_OTHER 8 +#define CFE_DEV_MASK 0x0F + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 +#define CFE_CACHE_FLUSH_L2 16 +#define CFE_CACHE_INVAL_RANGE 32 +#define CFE_CACHE_FLUSH_RANGE 64 + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +#define unsigned signed /* Kludge to get unsigned size-shaped type. */ +typedef __SIZE_TYPE__ cfe_int_t; +#undef unsigned +typedef __SIZE_TYPE__ cfe_uint_t; +typedef unsigned long long cfe_offset_t; +typedef long long cfe_int64_t; +typedef unsigned char *cfe_ptr_t; + +typedef struct iocb_buffer_s { + cfe_offset_t buf_offset; /* offset on device (bytes) */ + cfe_ptr_t buf_ptr; /* pointer to a buffer */ + cfe_uint_t buf_length; /* length of this buffer */ + cfe_uint_t buf_retlen; /* returned length (for read ops) */ + cfe_uint_t buf_ioctlcmd; /* IOCTL command (used only for IOCTLs) */ +} iocb_buffer_t; + +#define buf_devflags buf_ioctlcmd /* returned device info flags */ + +typedef struct iocb_inpstat_s { + cfe_uint_t inp_status; /* 1 means input available */ +} iocb_inpstat_t; + +typedef struct iocb_envbuf_s { + int enum_idx; /* 0-based enumeration index */ + cfe_ptr_t name_ptr; /* name string buffer */ + cfe_int_t name_length; /* size of name buffer */ + cfe_ptr_t val_ptr; /* value string buffer */ + cfe_int_t val_length; /* size of value string buffer */ +} iocb_envbuf_t; + +typedef struct iocb_cpuctl_s { + cfe_uint_t cpu_number; /* cpu number to control */ + cfe_uint_t cpu_command; /* command to issue to CPU */ + cfe_uint_t start_addr; /* CPU start address */ + cfe_uint_t gp_val; /* starting GP value */ + cfe_uint_t sp_val; /* starting SP value */ + cfe_uint_t a1_val; /* starting A1 value */ +} iocb_cpuctl_t; + +typedef struct iocb_time_s { + long long ticks; /* current time in ticks */ +} iocb_time_t; + +typedef struct iocb_exitstat_s { + cfe_int_t status; +} iocb_exitstat_t; + +typedef struct iocb_meminfo_s { + cfe_int_t mi_idx; /* 0-based enumeration index */ + cfe_int_t mi_type; /* type of memory block */ + cfe_int64_t mi_addr; /* physical start address */ + cfe_int64_t mi_size; /* block size */ +} iocb_meminfo_t; + +#define CFE_FWI_64BIT 0x00000001 +#define CFE_FWI_32BIT 0x00000002 +#define CFE_FWI_RELOC 0x00000004 +#define CFE_FWI_UNCACHED 0x00000008 +#define CFE_FWI_MULTICPU 0x00000010 +#define CFE_FWI_FUNCSIM 0x00000020 +#define CFE_FWI_RTLSIM 0x00000040 + +typedef struct iocb_fwinfo_s { + cfe_int64_t fwi_version; /* major, minor, eco version */ + cfe_int64_t fwi_totalmem; /* total installed mem */ + cfe_int64_t fwi_flags; /* various flags */ + cfe_int64_t fwi_boardid; /* board ID */ + cfe_int64_t fwi_bootarea_va; /* VA of boot area */ + cfe_int64_t fwi_bootarea_pa; /* PA of boot area */ + cfe_int64_t fwi_bootarea_size; /* size of boot area */ + cfe_int64_t fwi_reserved1; + cfe_int64_t fwi_reserved2; + cfe_int64_t fwi_reserved3; +} iocb_fwinfo_t; + + +typedef struct cfe_iocb_s { + cfe_uint_t iocb_fcode; /* IOCB function code */ + cfe_int_t iocb_status; /* return status */ + cfe_int_t iocb_handle; /* file/device handle */ + cfe_uint_t iocb_flags; /* flags for this IOCB */ + cfe_uint_t iocb_psize; /* size of parameter list */ + union { + iocb_buffer_t iocb_buffer; /* buffer parameters */ + iocb_inpstat_t iocb_inpstat; /* input status parameters */ + iocb_envbuf_t iocb_envbuf; /* environment function parameters */ + iocb_cpuctl_t iocb_cpuctl; /* CPU control parameters */ + iocb_time_t iocb_time; /* timer parameters */ + iocb_meminfo_t iocb_meminfo; /* memory arena info parameters */ + iocb_fwinfo_t iocb_fwinfo; /* firmware information */ + iocb_exitstat_t iocb_exitstat; /* Exit Status */ + } plist; +} cfe_iocb_t; + + +#endif diff --git a/cfe/cfe/include/cfe_ioctl.h b/cfe/cfe/include/cfe_ioctl.h new file mode 100644 index 0000000..1a389f8 --- /dev/null +++ b/cfe/cfe/include/cfe_ioctl.h @@ -0,0 +1,167 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCTL definitions File: cfe_ioctl.h + * + * IOCTL function numbers and I/O data structures. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * NVFAM and FLASH stuff + ********************************************************************* */ + +#define IOCTL_NVRAM_GETINFO 1 /* return nvram_info_t */ +#define IOCTL_NVRAM_ERASE 2 /* erase sector containing nvram_info_t area */ +#define IOCTL_FLASH_ERASE_SECTOR 3 /* erase an arbitrary sector */ +#define IOCTL_FLASH_ERASE_ALL 4 /* Erase the entire flash */ +#define IOCTL_FLASH_WRITE_ALL 5 /* write entire flash */ +#define IOCTL_FLASH_GETINFO 6 /* get flash device info */ +#define IOCTL_FLASH_GETSECTORS 7 /* get sector information */ +#define IOCTL_FLASH_ERASE_RANGE 8 /* erase range of bytes */ +#define IOCTL_NVRAM_UNLOCK 9 /* allow r/w beyond logical end of device */ +#define IOCTL_FLASH_PROTECT_RANGE 10 /* Protect a group of sectors */ +#define IOCTL_FLASH_UNPROTECT_RANGE 11 /* unprotect a group of sectors */ +#define IOCTL_FLASH_DATA_WIDTH_MODE 12 /* switch flash and gen bus to support 8 or 16-bit mode I/Os */ +#define IOCTL_FLASH_BURST_MODE 13 /* configure gen bus for burst mode */ + +typedef struct flash_range_s { + unsigned int range_base; + unsigned int range_length; +} flash_range_t; + +typedef struct flash_info_s { + unsigned long long flash_base; /* flash physical base address */ + unsigned int flash_size; /* available device size in bytes */ + unsigned int flash_type; /* type, from FLASH_TYPE below */ + unsigned int flash_flags; /* Various flags (FLASH_FLAG_xxx) */ +} flash_info_t; + +typedef struct flash_sector_s { + int flash_sector_idx; + int flash_sector_status; + unsigned int flash_sector_offset; + unsigned int flash_sector_size; +} flash_sector_t; + +#define FLASH_SECTOR_OK 0 +#define FLASH_SECTOR_INVALID -1 + +#define FLASH_TYPE_UNKNOWN 0 /* not sure what kind of flash */ +#define FLASH_TYPE_SRAM 1 /* not flash: it's SRAM */ +#define FLASH_TYPE_ROM 2 /* not flash: it's ROM */ +#define FLASH_TYPE_FLASH 3 /* it's flash memory of some sort */ + +#define FLASH_FLAG_NOERASE 1 /* Byte-range writes supported, + Erasing is not necessary */ + +typedef struct nvram_info_s { + int nvram_offset; /* offset of environment area */ + int nvram_size; /* size of environment area */ + int nvram_eraseflg; /* true if we need to erase first */ +} nvram_info_t; + +/* ********************************************************************* + * Ethernet stuff + ********************************************************************* */ + +#define IOCTL_ETHER_GETHWADDR 1 /* Get hardware address (6bytes) */ +#define IOCTL_ETHER_SETHWADDR 2 /* Set hardware address (6bytes) */ +#define IOCTL_ETHER_GETSPEED 3 /* Get Speed and Media (int) */ +#define IOCTL_ETHER_SETSPEED 4 /* Set Speed and Media (int) */ +#define IOCTL_ETHER_GETLINK 5 /* get link status (int) */ +#define IOCTL_ETHER_GETLOOPBACK 7 /* get loopback state */ +#define IOCTL_ETHER_SETLOOPBACK 8 /* set loopback state */ +#define IOCTL_ETHER_SETPACKETFIFO 9 /* set packet fifo mode (int) */ +#define IOCTL_ETHER_SETSTROBESIG 10 /* set strobe signal (int) */ + +#define ETHER_LOOPBACK_OFF 0 /* no loopback */ +#define ETHER_LOOPBACK_INT 1 /* Internal loopback */ +#define ETHER_LOOPBACK_EXT 2 /* External loopback (through PHY) */ + +#define ETHER_SPEED_AUTO 0 /* Auto detect */ +#define ETHER_SPEED_UNKNOWN 0 /* Speed not known (on link status) */ +#define ETHER_SPEED_10HDX 1 /* 10MB hdx and fdx */ +#define ETHER_SPEED_10FDX 2 +#define ETHER_SPEED_100HDX 3 /* 100MB hdx and fdx */ +#define ETHER_SPEED_100FDX 4 +#define ETHER_SPEED_1000HDX 5 /* 1000MB hdx and fdx */ +#define ETHER_SPEED_1000FDX 6 + +#define ETHER_FIFO_8 0 /* 8-bit packet fifo mode */ +#define ETHER_FIFO_16 1 /* 16-bit packet fifo mode */ +#define ETHER_ETHER 2 /* Standard ethernet mode */ + +#define ETHER_STROBE_GMII 0 /* GMII style strobe signal */ +#define ETHER_STROBE_ENCODED 1 /* Encoded */ +#define ETHER_STROBE_SOP 2 /* SOP flagged. Only in 8-bit mode*/ +#define ETHER_STROBE_EOP 3 /* EOP flagged. Only in 8-bit mode*/ + +/* ********************************************************************* + * Serial Ports + ********************************************************************* */ + +#define IOCTL_SERIAL_SETSPEED 1 /* get baud rate (int) */ +#define IOCTL_SERIAL_GETSPEED 2 /* set baud rate (int) */ +#define IOCTL_SERIAL_SETFLOW 3 /* Set Flow Control */ +#define IOCTL_SERIAL_GETFLOW 4 /* Get Flow Control */ + +#define SERIAL_FLOW_NONE 0 /* no flow control */ +#define SERIAL_FLOW_SOFTWARE 1 /* software flow control (not impl) */ +#define SERIAL_FLOW_HARDWARE 2 /* hardware flow control */ + +/* ********************************************************************* + * Block device stuff + ********************************************************************* */ + +#define IOCTL_BLOCK_GETBLOCKSIZE 1 /* get block size (int) */ +#define IOCTL_BLOCK_GETTOTALBLOCKS 2 /* get total bocks (long long) */ +#define IOCTL_BLOCK_GETDEVTYPE 3 /* get device type (struct) */ + +typedef struct blockdev_info_s { + unsigned long long blkdev_totalblocks; + unsigned int blkdev_blocksize; + unsigned int blkdev_devtype; +} blockdev_info_t; + +#define BLOCK_DEVTYPE_DISK 0 +#define BLOCK_DEVTYPE_CDROM 1 + diff --git a/cfe/cfe/include/cfe_irq.h b/cfe/cfe/include/cfe_irq.h new file mode 100644 index 0000000..7605b5e --- /dev/null +++ b/cfe/cfe/include/cfe_irq.h @@ -0,0 +1,103 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IRQ related definitions File: cfe_irq.h + * + * This module describes CFE's interface for dispatching + * to driver-supplied service routines. Dispatch can be based + * either on asynchronous interrupt events or on synchrnous + * polling of the interrupt status registers from the idle loop. + * + * The interface attempts to accomodate the concept of interrupt + * mapping as is common on high-integration parts with standard + * cores. The details are motivated by the bcm1250/MIPS + * architecture, where the mapping abstraction is somewhat violated + * by CP0 interrupts that do not go through the mapper. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define NR_IRQS 64 + +#define CFE_IRQ_FLAGS_SHARED 0x1 + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +/* ********************************************************************* + * Functions + ********************************************************************* */ + +void cfe_irq_init(void); + + +/* Functions that use interrupt mapping, i.e., the irq argument is the + interrupt number at the input to the mapper. */ + +void cfe_mask_irq(int cpu, unsigned int irq); +void cfe_unmask_irq(int cpu, unsigned int irq); + +void cfe_enable_irq(unsigned int irq); +void cfe_disable_irq(unsigned int irq); + +int cfe_request_irq(unsigned int irq, + void (*handler)(void *), void *arg, + unsigned long irqflags, int device); +void cfe_free_irq(unsigned int irq, int device); + +/* pseudo-interrupts, by polling request lines and invoking handlers */ + +void cfe_irq_poll(void *); + + +/* Functions that bypass interrupt mapping, i.e., the ip argument + is the interrupt number at the output of the mapper and/or the + input to the CPU. */ + +typedef void (* ip_handler_t)(int ip); + +void cfe_irq_setvector(int ip, ip_handler_t handler); + +/* enable/disable interrupts at the CPU level. */ + +void cfe_irq_enable(int mask); +int cfe_irq_disable(void); diff --git a/cfe/cfe/include/cfe_loader.h b/cfe/cfe/include/cfe_loader.h new file mode 100644 index 0000000..9ed0c13 --- /dev/null +++ b/cfe/cfe/include/cfe_loader.h @@ -0,0 +1,86 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Loader API File: cfe_loader.h + * + * This is the main API for the program loader. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _CFE_LOADER_H_ +#define _CFE_LOADER_H_ + +#define LOADFLG_NOISY 0x0001 /* print out noisy info */ +#define LOADFLG_EXECUTE 0x0002 /* execute loaded program */ +#define LOADFLG_SPECADDR 0x0004 /* Use a specific size & addr */ +#define LOADFLG_NOBB 0x0008 /* don't look for a boot block */ +#define LOADFLG_NOCLOSE 0x0010 /* don't close network */ +#define LOADFLG_COMPRESSED 0x0020 /* file is compressed */ +#define LOADFLG_BATCH 0x0040 /* batch file */ + +typedef struct cfe_loadargs_s { + char *la_filename; /* name of file on I/O device */ + char *la_filesys; /* file system name */ + char *la_device; /* device name (ide0, etc.) */ + char *la_options; /* args to pass to loaded prog */ + char *la_loader; /* binary file loader to use */ + unsigned int la_flags; /* various flags */ + long la_address; /* used by SPECADDR only */ + unsigned long la_maxsize; /* used by SPECADDR only */ + long la_entrypt; /* returned entry point */ +} cfe_loadargs_t; + + +typedef struct cfe_loader_s { + char *name; /* name of loader */ + int (*loader)(cfe_loadargs_t *); /* access function */ + int flags; /* flags */ +} cfe_loader_t; + +#define LDRLOAD(ldr,arg) (*((ldr)->loader))(arg) + +int cfe_load_program(char *name,cfe_loadargs_t *la); +const cfe_loader_t *cfe_findloader(char *name); +void splitpath(char *path,char **devname,char **filename); +void cfe_go(cfe_loadargs_t *la); +int cfe_boot(char *ldrname,cfe_loadargs_t *la); +int cfe_savedata(char *fsname,char *devname,char *filename,uint8_t *start,uint8_t *end); + +#endif /* _CFE_LOADER_H_ */ diff --git a/cfe/cfe/include/cfe_mem.h b/cfe/cfe/include/cfe_mem.h new file mode 100644 index 0000000..83c3be2 --- /dev/null +++ b/cfe/cfe/include/cfe_mem.h @@ -0,0 +1,79 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Memory manager definitions File: cfe_mem.h + * + * Function prototypes and contants for the memory manager + * (used to manage the physical memory arena) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define MEMTYPE_EMPTY 0 +#define MEMTYPE_DRAM_AVAILABLE 1 /* must match value in cfe_iocb.h */ +#define MEMTYPE_DRAM_NOTINSTALLED 2 +#define MEMTYPE_DRAM_USEDBYFIRMWARE 3 +#define MEMTYPE_BOOTROM 4 +#define MEMTYPE_IOREGISTERS 5 +#define MEMTYPE_RESERVED 6 +#define MEMTYPE_L2CACHE 7 +#define MEMTYPE_LDT_PCI 8 +#define MEMTYPE_DRAM_BOOTPROGRAM 9 + +/* ********************************************************************* + * External data + ********************************************************************* */ + +extern unsigned int mem_bootarea_start; +extern unsigned int mem_bootarea_size; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +void cfe_arena_init(void); +int cfe_arena_loadcheck(uintptr_t start,unsigned int size); +int cfe_arena_enum(int idx,int *type,uint64_t *start,uint64_t *size,int allrecs); +void cfe_pagetable_init(void); + diff --git a/cfe/cfe/include/cfe_timer.h b/cfe/cfe/include/cfe_timer.h new file mode 100644 index 0000000..8c6a26f --- /dev/null +++ b/cfe/cfe/include/cfe_timer.h @@ -0,0 +1,74 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Timer defs and prototypes File: cfe_timer.h + * + * Definitions, prototypes, and macros related to the timer. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _CFE_TIMER_T +#define _CFE_TIMER_T + +void cfe_bg_init(void); +void cfe_bg_add(void (*func)(void *),void *arg); +void cfe_bg_remove(void (*func)(void *)); + +void background(void); + +#define POLL() background() + +typedef int64_t cfe_timer_t; + +void cfe_timer_init(void); +extern volatile int64_t cfe_ticks; +extern int cfe_cpu_speed; + +void cfe_sleep(int ticks); +void cfe_usleep(int usec); + +#define CFE_HZ 10 /* ticks per second */ + +#define TIMER_SET(x,v) x = cfe_ticks + (v) +#define TIMER_EXPIRED(x) ((x) && (cfe_ticks > (x))) +#define TIMER_CLEAR(x) x = 0 +#define TIMER_RUNNING(x) ((x) != 0) + +#endif diff --git a/cfe/cfe/include/cfe_xiocb.h b/cfe/cfe/include/cfe_xiocb.h new file mode 100644 index 0000000..75a336a --- /dev/null +++ b/cfe/cfe/include/cfe_xiocb.h @@ -0,0 +1,202 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB definitions File: cfe_iocb.h + * + * This module describes CFE's IOCB structure, the main + * data structure used to communicate API requests with CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _CFE_XIOCB_H +#define _CFE_XIOCB_H + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_CMD_FW_GETINFO 0 +#define CFE_CMD_FW_RESTART 1 +#define CFE_CMD_FW_BOOT 2 +#define CFE_CMD_FW_CPUCTL 3 +#define CFE_CMD_FW_GETTIME 4 +#define CFE_CMD_FW_MEMENUM 5 +#define CFE_CMD_FW_FLUSHCACHE 6 + +#define CFE_CMD_DEV_GETHANDLE 9 +#define CFE_CMD_DEV_ENUM 10 +#define CFE_CMD_DEV_OPEN 11 +#define CFE_CMD_DEV_INPSTAT 12 +#define CFE_CMD_DEV_READ 13 +#define CFE_CMD_DEV_WRITE 14 +#define CFE_CMD_DEV_IOCTL 15 +#define CFE_CMD_DEV_CLOSE 16 +#define CFE_CMD_DEV_GETINFO 17 + +#define CFE_CMD_ENV_ENUM 20 +#define CFE_CMD_ENV_GET 22 +#define CFE_CMD_ENV_SET 23 +#define CFE_CMD_ENV_DEL 24 + +#define CFE_CMD_MAX 32 + +#define CFE_CMD_VENDOR_USE 0x8000 /* codes above this are for customer use */ + +#define CFE_MI_RESERVED 0 /* memory is reserved, do not use */ +#define CFE_MI_AVAILABLE 1 /* memory is available */ + +#define CFE_FLG_WARMSTART 0x00000001 +#define CFE_FLG_FULL_ARENA 0x00000001 +#define CFE_FLG_ENV_PERMANENT 0x00000001 + +#define CFE_CPU_CMD_START 1 +#define CFE_CPU_CMD_STOP 0 + +#define CFE_STDHANDLE_CONSOLE 0 + +#define CFE_DEV_NETWORK 1 +#define CFE_DEV_DISK 2 +#define CFE_DEV_FLASH 3 +#define CFE_DEV_SERIAL 4 +#define CFE_DEV_CPU 5 +#define CFE_DEV_NVRAM 6 +#define CFE_DEV_CLOCK 7 +#define CFE_DEV_OTHER 8 +#define CFE_DEV_MASK 0x0F + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef unsigned long long cfe_xuint_t; +typedef long long cfe_xint_t; +typedef long long cfe_xptr_t; + +typedef struct xiocb_buffer_s { + cfe_xuint_t buf_offset; /* offset on device (bytes) */ + cfe_xptr_t buf_ptr; /* pointer to a buffer */ + cfe_xuint_t buf_length; /* length of this buffer */ + cfe_xuint_t buf_retlen; /* returned length (for read ops) */ + cfe_xuint_t buf_ioctlcmd; /* IOCTL command (used only for IOCTLs) */ +} xiocb_buffer_t; + +#define buf_devflags buf_ioctlcmd /* returned device info flags */ + +typedef struct xiocb_inpstat_s { + cfe_xuint_t inp_status; /* 1 means input available */ +} xiocb_inpstat_t; + +typedef struct xiocb_envbuf_s { + cfe_xint_t enum_idx; /* 0-based enumeration index */ + cfe_xptr_t name_ptr; /* name string buffer */ + cfe_xint_t name_length; /* size of name buffer */ + cfe_xptr_t val_ptr; /* value string buffer */ + cfe_xint_t val_length; /* size of value string buffer */ +} xiocb_envbuf_t; + +typedef struct xiocb_cpuctl_s { + cfe_xuint_t cpu_number; /* cpu number to control */ + cfe_xuint_t cpu_command; /* command to issue to CPU */ + cfe_xuint_t start_addr; /* CPU start address */ + cfe_xuint_t gp_val; /* starting GP value */ + cfe_xuint_t sp_val; /* starting SP value */ + cfe_xuint_t a1_val; /* starting A1 value */ +} xiocb_cpuctl_t; + +typedef struct xiocb_time_s { + cfe_xint_t ticks; /* current time in ticks */ +} xiocb_time_t; + +typedef struct xiocb_exitstat_s { + cfe_xint_t status; +} xiocb_exitstat_t; + +typedef struct xiocb_meminfo_s { + cfe_xint_t mi_idx; /* 0-based enumeration index */ + cfe_xint_t mi_type; /* type of memory block */ + cfe_xuint_t mi_addr; /* physical start address */ + cfe_xuint_t mi_size; /* block size */ +} xiocb_meminfo_t; + +#define CFE_FWI_64BIT 0x00000001 +#define CFE_FWI_32BIT 0x00000002 +#define CFE_FWI_RELOC 0x00000004 +#define CFE_FWI_UNCACHED 0x00000008 +#define CFE_FWI_MULTICPU 0x00000010 +#define CFE_FWI_FUNCSIM 0x00000020 +#define CFE_FWI_RTLSIM 0x00000040 + +typedef struct xiocb_fwinfo_s { + cfe_xint_t fwi_version; /* major, minor, eco version */ + cfe_xint_t fwi_totalmem; /* total installed mem */ + cfe_xint_t fwi_flags; /* various flags */ + cfe_xint_t fwi_boardid; /* board ID */ + cfe_xint_t fwi_bootarea_va; /* VA of boot area */ + cfe_xint_t fwi_bootarea_pa; /* PA of boot area */ + cfe_xint_t fwi_bootarea_size; /* size of boot area */ + cfe_xint_t fwi_reserved1; + cfe_xint_t fwi_reserved2; + cfe_xint_t fwi_reserved3; +} xiocb_fwinfo_t; + +typedef struct cfe_xiocb_s { + cfe_xuint_t xiocb_fcode; /* IOCB function code */ + cfe_xint_t xiocb_status; /* return status */ + cfe_xint_t xiocb_handle; /* file/device handle */ + cfe_xuint_t xiocb_flags; /* flags for this IOCB */ + cfe_xuint_t xiocb_psize; /* size of parameter list */ + union { + xiocb_buffer_t xiocb_buffer; /* buffer parameters */ + xiocb_inpstat_t xiocb_inpstat; /* input status parameters */ + xiocb_envbuf_t xiocb_envbuf; /* environment function parameters */ + xiocb_cpuctl_t xiocb_cpuctl; /* CPU control parameters */ + xiocb_time_t xiocb_time; /* timer parameters */ + xiocb_meminfo_t xiocb_meminfo; /* memory arena info parameters */ + xiocb_fwinfo_t xiocb_fwinfo; /* firmware information */ + xiocb_exitstat_t xiocb_exitstat; /* Exit Status */ + } plist; +} cfe_xiocb_t; + +#endif diff --git a/cfe/cfe/include/dev_flash.h b/cfe/cfe/include/dev_flash.h new file mode 100644 index 0000000..8cbce48 --- /dev/null +++ b/cfe/cfe/include/dev_flash.h @@ -0,0 +1,168 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash memory definitions File: dev_flash.h + * + * Stuff we use when manipulating flash memory devices. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* + * AMD Flash commands and magic offsets + */ + +#define AMD_FLASH_MAGIC_ADDR_1 0x555 /* AAA for 16-bit devices in 8-bit mode */ +#define AMD_FLASH_MAGIC_ADDR_2 0x2AA /* 554 for 16-bit devices in 8-bit mode */ + +#define AMD_FLASH_RESET 0xF0 +#define AMD_FLASH_MAGIC_1 0xAA +#define AMD_FLASH_MAGIC_2 0x55 +#define AMD_FLASH_AUTOSEL 0x90 +#define AMD_FLASH_PROGRAM 0xA0 +#define AMD_FLASH_UNLOCK_BYPASS 0x20 +#define AMD_FLASH_ERASE_3 0x80 +#define AMD_FLASH_ERASE_4 0xAA +#define AMD_FLASH_ERASE_5 0x55 +#define AMD_FLASH_ERASE_ALL_6 0x10 +#define AMD_FLASH_ERASE_SEC_6 0x30 + +/* + * INTEL Flash commands and magic offsets + */ + +#define INTEL_FLASH_READ_MODE 0xFF +#define INTEL_FLASH_ERASE_BLOCK 0x20 +#define INTEL_FLASH_ERASE_CONFIRM 0xD0 +#define INTEL_FLASH_PROGRAM 0x40 + +/* INTEL Flash commands for 16-bit mode */ +#define INTEL_FLASH_16BIT_READ_MODE 0xFF00 +#define INTEL_FLASH_16BIT_ERASE_BLOCK 0x2000 +#define INTEL_FLASH_16BIT_ERASE_CONFIRM 0xD000 +#define INTEL_FLASH_16BIT_PROGRAM 0x4000 +#define INTEL_FLASH_8BIT 0 +#define INTEL_FLASH_16BIT 1 + + +/* + * Common Flash Interface (CFI) commands and offsets + */ + +#define FLASH_CFI_QUERY_ADDR 0x55 +#define FLASH_CFI_QUERY_MODE 0x98 +#define FLASH_CFI_QUERY_EXIT 0xFF + +#define FLASH_CFI_MANUFACTURER 0x00 +#define FLASH_CFI_DEVICE 0x01 +#define FLASH_CFI_SIGNATURE 0x10 +#define FLASH_CFI_QUERY_STRING 0x10 +#define FLASH_CFI_COMMAND_SET 0x13 +#define FLASH_CFI_DEVICE_SIZE 0x27 +#define FLASH_CFI_DEVICE_INTERFACE 0x28 +#define FLASH_CFI_REGION_COUNT 0x2C +#define FLASH_CFI_REGION_TABLE 0x2D + +#define FLASH_CFI_CMDSET_INTEL_ECS 0x0001 /* Intel extended */ +#define FLASH_CFI_CMDSET_AMD_STD 0x0002 /* AMD Standard */ +#define FLASH_CFI_CMDSET_INTEL_STD 0x0003 /* Intel Standard */ +#define FLASH_CFI_CMDSET_AMD_ECS 0x0004 /* AMD Extended */ + +#define FLASH_CFI_DEVIF_X8 0x0000 /* 8-bit asynchronous */ +#define FLASH_CFI_DEVIF_X16 0x0001 /* 16-bit asynchronous */ +#define FLASH_CFI_DEVIF_X8X16 0x0002 /* 8 or 16-bit with BYTE# pin */ +#define FLASH_CFI_DEVIF_X32 0x0003 /* 32-bit asynchronous */ + +/* + * JEDEC offsets + */ + +#define FLASH_JEDEC_OFFSET_MFR 0 +#define FLASH_JEDEC_OFFSET_DEV 1 + +/* Vendor-specific flash identifiers */ + +#define FLASH_MFR_HYUNDAI 0xAD + +/* ********************************************************************* + * Macros for defining custom sector tables + ********************************************************************* */ + +#define FLASH_SECTOR_RANGE(nblks,size) (((nblks)-1) << 16) + ((size)/256) +#define FLASH_SECTOR_NBLKS(x) (((x) >> 16)+1) +#define FLASH_SECTOR_SIZE(x) (((x) & 0xFFFF)*256) +#define FLASH_MAXSECTORS 8 + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +/* + * This structure is passed in the "probe_ptr" field of the + * flash's probe routines and can be used for advanced + * configuration. If you pass this structure, probe_a and + * probe_b will be ignored by the driver + * + * flash_prog_phys is the base address you use for flash commands - + * you can put 0 here if it's the same as flash_phys. some boards, + * like the Algor P5064, have a different PA region used for doing + * byte accesses to the flash. In this case the special + * "flash_prog_phys" field is used for that. + */ + + +#define FLASH_FLG_NVRAM 0x00000001 /* Reserve space for NVRAM */ +#define FLASH_FLG_AUTOSIZE 0x00000002 /* resize to actual device size */ +#define FLASH_FLG_16BIT 0x00000004 /* it's a 16-bit ROM in 16-bit mode */ +#define FLASH_FLG_MANUAL 0x00000008 /* Not CFI, manual sectoring */ +#define FLASH_FLG_WIDE 0x00000010 /* must shift control addresses left one bit */ + +#ifndef __ASSEMBLER__ +typedef struct flash_probe_t { + long flash_phys; + long flash_prog_phys; /* base address for programming, if different */ + int flash_size; /* total flash size */ + int flash_flags; + /* The following are used when manually sectoring */ + int flash_cmdset; + int flash_nsectors; /* number of ranges */ + int flash_sectors[FLASH_MAXSECTORS]; +} flash_probe_t; +#endif diff --git a/cfe/cfe/include/dev_ide.h b/cfe/cfe/include/dev_ide.h new file mode 100644 index 0000000..96d3e18 --- /dev/null +++ b/cfe/cfe/include/dev_ide.h @@ -0,0 +1,90 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IDE disk driver File: dev_ide.h + * + * Probe constants for the IDE disk device. Various flags + * can be passed to the probe routine to configure various + * things. This is where they are defined. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* + * Use the macros below to set the type of the master and slave devices + * on the IDE bus. If you want automatic probing, then you need + * to specify that IDE_DEV_TYPE_AUTO as the device type. + */ + + +/* + * XXX: If you have more than one PCI IDE controller + * installed, this will be applied to all installed + * controllers. Clearly not right, we'll need to add + * a field here for a controller index. + */ + + +#define IDE_PROBE_TYPE_MASK 0x0F +#define IDE_PROBE_MASTER_SHIFT 0 +#define IDE_PROBE_SLAVE_SHIFT 4 + +#define IDE_PROBE_MASTER_TYPE(x) ((x) << IDE_PROBE_MASTER_SHIFT) +#define IDE_PROBE_SLAVE_TYPE(x) ((x) << IDE_PROBE_SLAVE_SHIFT) + +#define IDE_PROBE_GET_TYPE(pb,unit) (((pb) >> (unit*4)) & IDE_PROBE_TYPE_MASK) + +/* + * Device types. + */ + +#define IDE_DEVTYPE_NOPROBE 0 /* none */ +#define IDE_DEVTYPE_AUTO 0x0F /* automatically probe */ + +#define IDE_DEVTYPE_DISK 1 /* hard drives */ +#define IDE_DEVTYPE_CDROM 2 /* CD-ROMs */ +#define IDE_DEVTYPE_ATAPIDISK 3 /* ZIP disks, etc. */ + + + diff --git a/cfe/cfe/include/dev_ide_common.h b/cfe/cfe/include/dev_ide_common.h new file mode 100644 index 0000000..736fd99 --- /dev/null +++ b/cfe/cfe/include/dev_ide_common.h @@ -0,0 +1,204 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Generic IDE disk driver File: dev_ide_common.c + * + * This file contains common constants and structures for IDE + * disks and CFE drivers for them. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define IDE_REG_DATA 0x0 +#define IDE_REG_ERROR 0x1 +#define IDE_REG_PRECOMP 0x1 +#define IDE_REG_SECCNT 0x2 +#define IDE_REG_IR 0x2 /* ATAPI */ +#define IDE_REG_SECNUM 0x3 +#define IDE_REG_BCLSB 0x4 /* ATAPI */ +#define IDE_REG_BCMSB 0x5 /* ATAPI */ +#define IDE_REG_CYLLSB 0x4 +#define IDE_REG_CYLMSB 0x5 +#define IDE_REG_DRVHD 0x6 +#define IDE_REG_STATUS 0x7 +#define IDE_REG_COMMAND 0x7 +#define IDE_REG_ALTSTAT 0x6 /* Note: ALTSTAT is really 0x3F6, what do we do? */ +#define IDE_REG_DIGOUT 0x6 + +#define IDE_IR_CD 0x01 /* 1 = command, 0 = data */ +#define IDE_IR_IO 0x02 /* 1 = from device, 0 = to device */ +#define IDE_IR_REL 0x04 + +#define IDE_ERR_BBK 0x80 /* sector marked bad by host */ +#define IDE_ERR_UNC 0x40 /* uncorrectable error */ +#define IDE_ERR_MC 0x20 /* medium changed */ +#define IDE_ERR_NID 0x10 /* no ID mark found */ +#define IDE_ERR_MCR 0x08 /* medium change required */ +#define IDE_ERR_ABT 0x04 /* command aborted */ +#define IDE_ERR_NT0 0x02 /* track 0 not found */ +#define IDE_ERR_NDM 0x01 /* address mark not found */ + +#define IDE_DRV_SLAVE 0x10 +#define IDE_DRV_LBA 0x40 +#define IDE_DRV_MBO 0xA0 +#define IDE_DRV_HDMASK 0x0F + +#define IDE_STS_BSY 0x80 /* drive is busy */ +#define IDE_STS_RDY 0x40 /* drive is ready */ +#define IDE_STS_WFT 0x20 /* write fault */ +#define IDE_STS_SKC 0x10 /* seek complete */ +#define IDE_STS_DRQ 0x08 /* data can be transferred */ +#define IDE_STS_CORR 0x04 /* correctable data error */ +#define IDE_STS_IDX 0x02 /* index mark just passed */ +#define IDE_STS_ERR 0x01 /* Error register contains info */ + +#define IDE_CMD_RECAL 0x10 +#define IDE_CMD_READ 0x20 +#define IDE_CMD_READRETRY 0x21 +#define IDE_CMD_WRITE 0x30 +#define IDE_CMD_READVERIFY 0x40 +#define IDE_CMD_DIAGNOSTIC 0x90 +#define IDE_CMD_INITPARAMS 0x91 +#define IDE_CMD_SETMULTIPLE 0xC6 +#define IDE_CMD_POWER_MODE 0xE5 +#define IDE_CMD_DRIVE_INFO 0xEC + +#define IDE_CMD_ATAPI_SOFTRESET 0x08 +#define IDE_CMD_ATAPI_PACKET 0xA0 +#define IDE_CMD_ATAPI_IDENTIFY 0xA1 +#define IDE_CMD_ATAPI_SERVICE 0xA2 + +#define IDE_DOR_SRST 0x04 +#define IDE_DOR_IEN 0x02 + +#define DISK_SECTORSIZE 512 +#define CDROM_SECTORSIZE 2048 +#define MAX_SECTORSIZE 2048 + +#define ATAPI_SENSE_MASK 0xF0 +#define ATAPI_SENSE_NONE 0x00 +#define ATAPI_SENSE_RECOVERED 0x10 +#define ATAPI_SENSE_NOTREADY 0x20 +#define ATAPI_SENSE_MEDIUMERROR 0x30 +#define ATAPI_SENSE_HWERROR 0x40 +#define ATAPI_SENSE_ILLREQUEST 0x50 +#define ATAPI_SENSE_ATTENTION 0x60 +#define ATAPI_SENSE_PROTECT 0x70 +#define ATAPI_SENSE_BLANKCHECK 0x80 +#define ATAPI_SENSE_VSPECIFIC 0x90 +#define ATAPI_SENSE_COPYABORT 0xA0 +#define ATAPI_SENSE_CMDABORT 0xB0 +#define ATAPI_SENSE_EQUAL 0xC0 +#define ATAPI_SENSE_VOLOVERFLOW 0xD0 +#define ATAPI_SENSE_MISCOMPARE 0xE0 +#define ATAPI_SENSE_RESERVED 0xF0 + +#define ATAPI_SIG_LSB 0x14 +#define ATAPI_SIG_MSB 0xEB + +#define CDB_CMD_READ 0x28 +#define CDB_CMD_WRITE 0x2A +#define CDB_CMD_REQSENSE 0x03 + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct idecommon_dispatch_s idecommon_dispatch_t; + +struct idecommon_dispatch_s { + void *ref; + uint32_t baseaddr; + uint8_t (*inb)(idecommon_dispatch_t *disp,uint32_t reg); + uint16_t (*inw)(idecommon_dispatch_t *disp,uint32_t reg); + void (*ins)(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len); + + void (*outb)(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val); + void (*outw)(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val); + void (*outs)(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len); +}; + +#define IDEDISP_WRITEREG8(ide,reg,val) (*((ide)->outb))(ide,reg,val) +#define IDEDISP_WRITEREG16(ide,reg,val) (*((ide)->outw))(ide,reg,val) +#define IDEDISP_WRITEBUF(ide,reg,buf,len) (*((ide)->outs))(ide,reg,buf,len) +#define IDEDISP_READREG8(ide,reg) (*((ide)->inb))(ide,reg) +#define IDEDISP_READREG16(ide,reg) (*((ide)->inw))(ide,reg) +#define IDEDISP_READBUF(ide,reg,buf,len) (*((ide)->ins))(ide,reg,buf,len) + +typedef struct idecommon_s idecommon_t; + +struct idecommon_s { + idecommon_dispatch_t *idecommon_dispatch; + unsigned long idecommon_addr; /* physical address */ + int idecommon_unit; /* 0 or 1 master/slave */ + int idecommon_sectorsize; /* size of each sector */ + long long idecommon_ttlsect; /* total sectors */ + int idecommon_atapi; /* 1 if ATAPI device */ + int idecommon_devtype; /* device type */ + uint64_t idecommon_deferprobe; /* Defer probe to open */ + uint32_t idecommon_flags; /* flags for underlying driver */ + int (*idecommon_readfunc)(idecommon_t *ide,uint64_t lba,int numsec,uint8_t *buffer); + int (*idecommon_writefunc)(idecommon_t *ide,uint64_t lba,int numsec,uint8_t *buffer); + + uint32_t timer; +}; + + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +extern void idecommon_init(idecommon_t *ide,int devtype); +extern int idecommon_open(cfe_devctx_t *ctx); +extern int idecommon_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +extern int idecommon_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +extern int idecommon_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +extern int idecommon_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +extern int idecommon_identify(idecommon_t *ide,unsigned char *buffer); +extern int idecommon_close(cfe_devctx_t *ctx); +extern int idecommon_devprobe(idecommon_t *ide,int noisy); +void idecommon_attach(cfe_devdisp_t *disp); + diff --git a/cfe/cfe/include/dev_newflash.h b/cfe/cfe/include/dev_newflash.h new file mode 100644 index 0000000..5efced0 --- /dev/null +++ b/cfe/cfe/include/dev_newflash.h @@ -0,0 +1,344 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash memory definitions File: dev_newflash.h + * + * Stuff we use when manipulating flash memory devices. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef __ASSEMBLER__ +#include "cfe_device.h" +#include "cfe_iocb.h" +#endif + +/* ********************************************************************* + * Configuration + ********************************************************************* */ + +/* Bits for compile-time removal of features */ +#define FLASH_DRIVER_INTEL 1 /* support Intel cmd sets */ +#define FLASH_DRIVER_AMD 2 /* support AMD cmd sets */ +#define FLASH_DRIVER_CFI 4 /* support auto probing */ + +/* Default value unless overridden in bsp_config.h */ +#ifndef FLASH_DRIVERS +#define FLASH_DRIVERS (FLASH_DRIVER_INTEL | FLASH_DRIVER_AMD | FLASH_DRIVER_CFI) +#endif + +/* ********************************************************************* + * Flash magic numbers + ********************************************************************* */ + +/* + * AMD Flash commands and magic offsets + */ + +#define AMD_FLASH_MAGIC_ADDR_1 0x555 /* AAA for 16-bit devices in 8-bit mode */ +#define AMD_FLASH_MAGIC_ADDR_2 0x2AA /* 554 for 16-bit devices in 8-bit mode */ + +#define AMD_FLASH_RESET 0xF0 +#define AMD_FLASH_MAGIC_1 0xAA +#define AMD_FLASH_MAGIC_2 0x55 +#define AMD_FLASH_AUTOSEL 0x90 +#define AMD_FLASH_DEVCODE8 0x2 +#define AMD_FLASH_DEVCODE16 0x1 +#define AMD_FLASH_DEVCODE16B 0x2 +#define AMD_FLASH_MANID 0x0 +#define AMD_FLASH_PROGRAM 0xA0 +#define AMD_FLASH_UNLOCK_BYPASS 0x20 +#define AMD_FLASH_ERASE_3 0x80 +#define AMD_FLASH_ERASE_4 0xAA +#define AMD_FLASH_ERASE_5 0x55 +#define AMD_FLASH_ERASE_ALL_6 0x10 +#define AMD_FLASH_ERASE_SEC_6 0x30 + +/* + * INTEL Flash commands and magic offsets + */ + +#define INTEL_FLASH_READ_MODE 0xFF +#define INTEL_FLASH_ERASE_BLOCK 0x20 +#define INTEL_FLASH_ERASE_CONFIRM 0xD0 +#define INTEL_FLASH_PROGRAM 0x40 + +/* INTEL Flash commands for 16-bit mode */ +#define INTEL_FLASH_16BIT_READ_MODE 0xFF00 +#define INTEL_FLASH_16BIT_ERASE_BLOCK 0x2000 +#define INTEL_FLASH_16BIT_ERASE_CONFIRM 0xD000 +#define INTEL_FLASH_16BIT_PROGRAM 0x4000 +#define INTEL_FLASH_8BIT 0 +#define INTEL_FLASH_16BIT 1 + + +/* + * Common Flash Interface (CFI) commands and offsets + */ + +#define FLASH_CFI_QUERY_ADDR 0x55 +#define FLASH_CFI_QUERY_MODE 0x98 +#define FLASH_CFI_QUERY_EXIT 0xFF + +#define FLASH_CFI_MANUFACTURER 0x00 +#define FLASH_CFI_DEVICE 0x01 +#define FLASH_CFI_SIGNATURE 0x10 +#define FLASH_CFI_QUERY_STRING 0x10 +#define FLASH_CFI_COMMAND_SET 0x13 +#define FLASH_CFI_DEVICE_SIZE 0x27 +#define FLASH_CFI_DEVICE_INTERFACE 0x28 +#define FLASH_CFI_REGION_COUNT 0x2C +#define FLASH_CFI_REGION_TABLE 0x2D + +#define FLASH_CFI_CMDSET_INTEL_ECS 0x0001 /* Intel extended */ +#define FLASH_CFI_CMDSET_AMD_STD 0x0002 /* AMD Standard */ +#define FLASH_CFI_CMDSET_INTEL_STD 0x0003 /* Intel Standard */ +#define FLASH_CFI_CMDSET_AMD_ECS 0x0004 /* AMD Extended */ + +#define FLASH_CFI_DEVIF_X8 0x0000 /* 8-bit asynchronous */ +#define FLASH_CFI_DEVIF_X16 0x0001 /* 16-bit asynchronous */ +#define FLASH_CFI_DEVIF_X8X16 0x0002 /* 8 or 16-bit with BYTE# pin */ +#define FLASH_CFI_DEVIF_X32 0x0003 /* 32-bit asynchronous */ + +/* + * JEDEC offsets + */ + +#define FLASH_JEDEC_OFFSET_MFR 0 +#define FLASH_JEDEC_OFFSET_DEV 1 + +/* Vendor-specific flash identifiers */ + +#define FLASH_MFR_HYUNDAI 0xAD +#define FLASH_MFR_AMD 0x01 + +/* ********************************************************************* + * Macros for defining custom sector tables + ********************************************************************* */ + +#define FLASH_SECTOR_RANGE(nblks,size) (((nblks)-1) << 16) + ((size)/256) +#define FLASH_SECTOR_NBLKS(x) (((x) >> 16)+1) +#define FLASH_SECTOR_SIZE(x) (((x) & 0xFFFF)*256) +#define FLASH_MAXSECTORS 8 + +/* ********************************************************************* + * Flashop engine constants and structures + * The flashop engine interprets a little table of commands + * to manipulate flash parts - we do this so we can operate + * on the flash that we're currently running from. + ********************************************************************* */ + +/* + * Structure of the "instruction" table is six words, + * size dependant on the machine word size (32 or 64 bits). + * + * opcode + * flash base + * destination + * source + * length + * result + */ + +#define FEINST_OP _TBLIDX(0) +#define FEINST_BASE _TBLIDX(1) +#define FEINST_DEST _TBLIDX(2) +#define FEINST_SRC _TBLIDX(3) +#define FEINST_CNT _TBLIDX(4) +#define FEINST_RESULT _TBLIDX(5) +#define FEINST_SIZE _TBLIDX(6) /* size of an instruction */ + +#ifndef __ASSEMBLER__ +typedef struct flashinstr_s { /* must match offsets above */ + long fi_op; + long fi_base; + long fi_dest; + long fi_src; + long fi_cnt; + long fi_result; +} flashinstr_t; +#endif + +/* + * Flash opcodes + */ + +#define FEOP_RETURN 0 /* return to CFE */ +#define FEOP_REBOOT 1 /* Reboot system */ +#define FEOP_READ8 2 /* read, 8 bits at a time */ +#define FEOP_READ16 3 /* read, 16 bits at a time */ +#define FEOP_CFIQUERY8 4 /* CFI Query 8-bit */ +#define FEOP_CFIQUERY16 5 /* CFI Query 16-bit */ +#define FEOP_CFIQUERY16B 6 /* CFI Query 16-bit */ +#define FEOP_MEMCPY 7 /* generic memcpy */ +#define FEOP_AMD_ERASE8 8 /* AMD-style 8-bit erase-sector */ +#define FEOP_AMD_ERASE16 9 /* AMD-style 16-bit erase-sector */ +#define FEOP_AMD_ERASE16B 10 /* AMD-style 16-bit erase-sector */ +#define FEOP_AMD_PGM8 11 /* AMD-style 8-bit program */ +#define FEOP_AMD_PGM16 12 /* AMD-style 16-bit program */ +#define FEOP_AMD_PGM16B 13 /* AMD-style 16-bit program */ +#define FEOP_AMD_DEVCODE8 14 /* AMD-style 8-bit Boot Block Info */ +#define FEOP_AMD_DEVCODE16 15 /* AMD-style 8-bit Boot Block Info */ +#define FEOP_AMD_DEVCODE16B 16 /* AMD-style 8-bit Boot Block Info */ +#define FEOP_AMD_MANID8 17 /* AMD-style 8-bit Boot Block Info */ +#define FEOP_AMD_MANID16 18 /* AMD-style 8-bit Boot Block Info */ +#define FEOP_AMD_MANID16B 19 /* AMD-style 8-bit Boot Block Info */ +#define FEOP_INTEL_ERASE8 20 /* Intel-style 8-bit erase-sector */ +#define FEOP_INTEL_ERASE16 21 /* Intel-style 16-bit erase-sector */ +#define FEOP_INTEL_PGM8 22 /* Intel-style 8-bit program */ +#define FEOP_INTEL_PGM16 23 /* Intel-style 16-bit program */ + +/* + * Flashop result values. + */ + +#define FERES_OK 0 +#define FERES_ERROR -1 + + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +/* + * Flags. If you instantiate the driver with probe_a = physical + * address and probe_b = size, you should also OR in the + * bus and device width below. + */ + +#define FLASH_FLG_AUTOSIZE 0x00000002 /* resize to actual device size */ +#define FLASH_FLG_BUS8 0 +#define FLASH_FLG_BUS16 0x00000004 /* ROM is connected to 16-bit bus */ +#define FLASH_FLG_DEV8 0 +#define FLASH_FLG_DEV16 0x00000010 /* ROM has 16-bit data width */ +#define FLASH_FLG_MANUAL 0x00000008 /* Not CFI, manual sectoring */ +#define FLASH_FLG_MASK 0x000000FF /* mask of probe bits for flags */ +#define FLASH_SIZE_MASK 0xFFFFFF00 /* mask of probe bits for size */ +/* you don't have to shift the size, we assume it's in multiples of 256bytes */ + +#ifndef __ASSEMBLER__ + +/* + * Partition structure - use this to define a flash "partition." + * The partitions are assigned in order from the beginning of the flash. + * The special size '0' means 'fill to end of flash', and you can + * have more partitions after that which are aligned with the top + * of the flash. + * Therefore if you have a 1MB flash and set up + * partitions for 256KB, 0, 128KB, the 128KB part will be aligned + * to the top of the flash and the middle block will be 768KB. + * Partitions can be on byte boundaries. + */ + +typedef struct newflash_part_t { + int fp_size; + char *fp_name; +} newflash_part_t; +#define FLASH_MAX_PARTITIONS 8 + +/* + * Probe structure - this is used when we want to describe to the flash + * driver the layout of our flash, particularly when you want to + * manually describe the sectors. + */ + +typedef struct newflash_probe_t { + long flash_phys; /* physical address of flash */ + int flash_size; /* total flash size */ + int flash_flags; /* flags (FLASH_FLG_xxx) */ + int flash_type; /* FLASH_TYPE_xxx */ + /* The following are used when manually sectoring */ + int flash_cmdset; /* FLASH_CMDSET_xxx */ + int flash_nsectors; /* number of ranges */ + int flash_sectors[FLASH_MAXSECTORS]; + /* This says how many contiguous flash chips are in this region */ + int flash_nchips; /* "flash_size" is just for one chip */ + /* The following are used for partitioned flashes */ + int flash_nparts; /* zero means not partitioned */ + newflash_part_t flash_parts[FLASH_MAX_PARTITIONS]; + /* The following are used for whacky, weird flashes */ + int (*flash_ioctl_hook)(cfe_devctx_t *ctx,iocb_buffer_t *buffer); + /* You can replace the flash engine with your own */ + int (*flash_engine_hook)(flashinstr_t *prog); +} newflash_probe_t; + + +/* ********************************************************************* + * PRIVATE STRUCTURES + * + * These structures are actually the "property" of the + * flash driver. The only reason a board package might + * want to dig around in here is if it implements a hook + * or overrides functions to support special, weird flash parts. + ********************************************************************* */ + +typedef struct flashdev_s flashdev_t; + +typedef struct flashpart_s { + flashdev_t *fp_dev; + int fp_offset; + int fp_size; +} flashpart_t; + +#define FLASH_MAX_CFIDATA 256 /* total size of CFI Data */ +#define FLASH_MAX_INST 8 /* instructions we use during probing */ + +struct flashdev_s { + newflash_probe_t fd_probe; /* probe information */ + + uint8_t fd_erasefunc; /* Erase routine to use */ + uint8_t fd_pgmfunc; /* program routine to use */ + uint8_t fd_readfunc; /* Read routine to use */ + flashpart_t fd_parts[FLASH_MAX_PARTITIONS]; + + uint8_t *fd_sectorbuffer; /* sector copy buffer */ + int fd_ttlsect; /* total sectors on one device */ + int fd_ttlsize; /* total size of all devices (flash size * nchips) */ + + int fd_iptr; /* flashop engine instructions */ + flashinstr_t *fd_inst; +}; + + + +#endif + + + diff --git a/cfe/cfe/include/elf.h b/cfe/cfe/include/elf.h new file mode 100644 index 0000000..944aab4 --- /dev/null +++ b/cfe/cfe/include/elf.h @@ -0,0 +1,194 @@ +/* + * ELF data structures and values + */ + +typedef unsigned short Elf32_Half; +typedef unsigned int Elf32_Word; +typedef signed int Elf32_Sword; +typedef unsigned int Elf32_Off; +typedef unsigned int Elf32_Addr; +typedef unsigned char Elf_Char; + +/* + * File Header + */ + +#define EI_NIDENT 16 + +typedef struct { + Elf_Char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +/* e_indent */ +#define EI_MAG0 0 /* File identification byte 0 index */ +#define EI_MAG1 1 /* File identification byte 1 index */ +#define EI_MAG2 2 /* File identification byte 2 index */ +#define EI_MAG3 3 /* File identification byte 3 index */ +#define EI_CLASS 4 /* File class */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define EI_DATA 5 /* Data encoding */ +#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 */ +#define EI_PAD 7 /* Start of padding bytes */ + +#define ELFMAG0 0x7F /* Magic number byte 0 */ +#define ELFMAG1 'E' /* Magic number byte 1 */ +#define ELFMAG2 'L' /* Magic number byte 2 */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* 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 */ +#define ET_LOPROC 0xFF00 /* Processor-specific */ +#define ET_HIPROC 0xFFFF /* Processor-specific */ + +/* e_machine */ +#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_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 */ + +/* e_version */ +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ + + +/* + * Program Header + */ +typedef struct { + Elf32_Word p_type; /* Identifies program segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment, file & memory */ +} Elf32_Phdr; + + +/* p_type */ +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved, unspecified semantics */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_LOPROC 0x70000000 /* Processor-specific */ +#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */ + +/* p_flags */ +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */ + + +/* + * Section Header + */ +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +/* sh_type */ +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program specific (private) data */ +#define SHT_SYMTAB 2 /* Link editing symbol table */ +#define SHT_STRTAB 3 /* A string table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* A symbol hash table */ +#define SHT_DYNAMIC 6 /* Information for dynamic linking */ +#define SHT_NOTE 7 /* Information that marks file */ +#define SHT_NOBITS 8 /* Section occupies no space in file */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ +#define SHT_DYNSYM 11 /* Dynamic linking symbol table */ +#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */ +#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */ +#define SHT_LOUSER 0x80000000 /* Application-specific semantics */ +#define SHT_HIUSER 0x8FFFFFFF /* Application-specific semantics */ + +/* sh_flags */ +#define SHF_WRITE (1 << 0) /* Writable data during execution */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions */ +#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */ + + +/* + * Symbol Table + */ +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + Elf_Char st_info; + Elf_Char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + + +#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4) +#define ELF_ST_TYPE(val) ((val) & 0xF) +#define ELF_ST_INFO(bind,type) (((bind) << 4) | ((type) & 0xF)) + +/* symbol binding */ +#define STB_LOCAL 0 /* Symbol not visible outside obj */ +#define STB_GLOBAL 1 /* Symbol visible outside obj */ +#define STB_WEAK 2 /* Like globals, lower precedence */ +#define STB_LOPROC 13 /* Application-specific semantics */ +#define STB_HIPROC 15 /* Application-specific semantics */ + +/* symbol type */ +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol gives a file name */ +#define STT_LOPROC 13 /* Application-specific semantics */ +#define STT_HIPROC 15 /* Application-specific semantics */ + +/* special values st_shndx */ +#define SHN_UNDEF 0 /* Undefined section reference */ +#define SHN_LORESERV 0xFF00 /* Begin range of reserved indices */ +#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */ +#define SHN_HIPROC 0xFF1F /* End range of appl-specific */ +#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */ +#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */ diff --git a/cfe/cfe/include/env_subr.h b/cfe/cfe/include/env_subr.h new file mode 100644 index 0000000..f5dfb9f --- /dev/null +++ b/cfe/cfe/include/env_subr.h @@ -0,0 +1,117 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Environment helper routines File: env_subr.h + * + * Definitions and prototypes for environment variable subroutines + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + + +/* + * TLV types. These codes are used in the "type-length-value" + * encoding of the items stored in the NVRAM device (flash or EEPROM) + * + * The layout of the flash/nvram is as follows: + * + * + * + * The type code of "ENV_TLV_TYPE_END" marks the end of the list. + * The "length" field marks the length of the data section, not + * including the type and length fields. + * + * Environment variables are stored as follows: + * + * = + * + * If bit 0 (low bit) is set, the length is an 8-bit value. + * If bit 0 (low bit) is clear, the length is a 16-bit value + * + * Bit 7 set indicates "user" TLVs. In this case, bit 0 still + * indicates the size of the length field. + * + * Flags are from the constants below: + * + */ + +#define ENV_LENGTH_16BITS 0x00 /* for low bit */ +#define ENV_LENGTH_8BITS 0x01 + +#define ENV_TYPE_USER 0x80 + +#define ENV_CODE_SYS(n,l) (((n)<<1)|(l)) +#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER) + +/* + * The actual TLV types we support + */ + +#define ENV_TLV_TYPE_END 0x00 +#define ENV_TLV_TYPE_ENV ENV_CODE_SYS(0,ENV_LENGTH_8BITS) + +/* + * Environment variable flags + */ + +#define ENV_FLG_NORMAL 0x00 /* normal read/write */ +#define ENV_FLG_BUILTIN 0x01 /* builtin - not stored in flash */ +#define ENV_FLG_READONLY 0x02 /* read-only - cannot be changed */ + +#define ENV_FLG_MASK 0xFF /* mask of attributes we keep */ +#define ENV_FLG_ADMIN 0x100 /* lets us internally override permissions */ + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int env_delenv(const char *name); +char *env_getenv(const char *name); +int env_setenv(const char *name,char *value,int flags); +int env_load(void); +int env_save(void); +int env_enum(int idx,char *name,int *namelen,char *val,int *vallen); +int env_envtype(const char *name); + diff --git a/cfe/cfe/include/foxconnCfg.h b/cfe/cfe/include/foxconnCfg.h new file mode 100755 index 0000000..3c43675 --- /dev/null +++ b/cfe/cfe/include/foxconnCfg.h @@ -0,0 +1,9 @@ +#ifndef _FOXCONNCFG_H +#define _FOXCONNCFG_H + +#define FOXCONN_BOARD_ID "U12L161T00_NETGEAR" +#define GPIO_POWER_RED_LED 18 +#define GPIO_POWER_RED_LED_ON 1 +#define GPIO_POWER_RED_LED_OFF 0 + +#endif \ No newline at end of file diff --git a/cfe/cfe/include/lib_arena.h b/cfe/cfe/include/lib_arena.h new file mode 100644 index 0000000..2ae49d6 --- /dev/null +++ b/cfe/cfe/include/lib_arena.h @@ -0,0 +1,76 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Arena definitions File: lib_arena.h + * + * Definitions for the arena manager, which is used to keep + * track of ranges of physical memory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct arena_node_s { + queue_t an_next; + uint64_t an_address; + uint64_t an_length; + int an_type; + char *an_descr; +} arena_node_t; + + +typedef struct arena_s { + queue_t arena_list; + uint64_t arena_base; + uint64_t arena_size; +} arena_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int arena_markrange(arena_t *arena,uint64_t address,uint64_t length, + int type,char *descr); +void arena_init(arena_t *arena,uint64_t physmembase,uint64_t physmemsize); + diff --git a/cfe/cfe/include/lib_malloc.h b/cfe/cfe/include/lib_malloc.h new file mode 100644 index 0000000..da1e27b --- /dev/null +++ b/cfe/cfe/include/lib_malloc.h @@ -0,0 +1,78 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Local memory manager File: mempool.h + * + * This routine is used to manage memory allocated within the + * firmware. You give it a chunk of memory to manage, and then + * these routines manage suballocations from there. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _LIB_MALLOC_H +#define _LIB_MALLOC_H + +typedef struct memstats_s { + int mem_totalbytes; + int mem_allocbytes; + int mem_freebytes; + int mem_allocnodes; + int mem_freenodes; + int mem_largest; +} memstats_t; + +typedef struct mempool_s mempool_t; +void kmeminit(mempool_t *pool,unsigned char *buffer,int length); +void kfree(mempool_t *pool,void *ptr); +void *kmalloc(mempool_t *pool,unsigned int size,unsigned int align); +int kmemchk(mempool_t *pool,int verbose); +extern mempool_t kmempool; +void *kmempoolbase(mempool_t *pool); +int kmempoolsize(mempool_t *pool); +int kmemstats(mempool_t *pool,memstats_t *stats); + +#define KMEMINIT(buffer,length) kmeminit(&kmempool,(buffer),(length)) +#define KMEMPOOLBASE() kmempoolbase(&kmempool) +#define KMEMPOOLSIZE() kmempoolsize(&kmempool) +#define KMALLOC(size,align) kmalloc(&kmempool,(size),(align)) +#define KFREE(ptr) kfree(&kmempool,(ptr)) +#define KMEMSTATS(s) kmemstats(&kmempool,(s)) + +#endif diff --git a/cfe/cfe/include/lib_printf.h b/cfe/cfe/include/lib_printf.h new file mode 100755 index 0000000..e4d2860 --- /dev/null +++ b/cfe/cfe/include/lib_printf.h @@ -0,0 +1,69 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * simple printf File: lib_printf.h + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This module contains a very, very, very simple printf + * suitable for use in the boot ROM. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include + +int xvsprintf(char *outbuf,const char *templat,va_list marker); +int xsprintf(char *buf,const char *templat,...); +#if CFG_RAMAPP +int xprintf(const char *templat,...); +#else +#define xprintf(...) +#endif + +extern int (*xprinthook)(const char *); +int xvprintf(const char *template,va_list marker); + +/* + * compatibility macros + */ + + +#define printf xprintf +#define sprintf xsprintf +#define vsprintf xvsprintf +#define vprintf xvprintf diff --git a/cfe/cfe/include/lib_queue.h b/cfe/cfe/include/lib_queue.h new file mode 100644 index 0000000..530c70f --- /dev/null +++ b/cfe/cfe/include/lib_queue.h @@ -0,0 +1,85 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Queue management prototypes File: lib_queue.h + * + * Constants, structures, and function prototypes for the queue + * manager. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _LIB_QUEUE_H +#define _LIB_QUEUE_H + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define q_init(q) (q)->q_prev = (q), (q)->q_next = (q) +#define q_isempty(q) ((q)->q_next == (q)) +#define q_getfirst(q) ((q)->q_next) +#define q_getlast(q) ((q)->q_prev) + +/* ********************************************************************* + * Types + ********************************************************************* */ + + +typedef struct queue_s { + struct queue_s *q_next; + struct queue_s *q_prev; +} queue_t; + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +void q_enqueue(queue_t *,queue_t *); +void q_dequeue(queue_t *); +queue_t *q_deqnext(queue_t *); +int q_map(queue_t *qb,int (*func)(queue_t *,unsigned int,unsigned int), + unsigned int a,unsigned int b); +int q_count(queue_t *); +int q_find(queue_t *,queue_t *); + + +#endif diff --git a/cfe/cfe/include/lib_string.h b/cfe/cfe/include/lib_string.h new file mode 100644 index 0000000..4d0f3d8 --- /dev/null +++ b/cfe/cfe/include/lib_string.h @@ -0,0 +1,117 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * string prototypes File: lib_string.h + * + * Function prototypes for the string routines + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +char *lib_strcpy(char *dest,const char *src); +char *lib_strncpy(char *dest,const char *src,size_t cnt); +size_t lib_xstrncpy(char *dest,const char *src,size_t cnt); +size_t lib_strlen(const char *str); + +int lib_strcmp(const char *dest,const char *src); + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +int lib_strncmp(const char *dest, const char *src, size_t cnt ); +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +int lib_strcmpi(const char *dest,const char *src); +char *lib_strchr(const char *dest,int c); +char *lib_strrchr(const char *dest,int c); +int lib_memcmp(const void *dest,const void *src,size_t cnt); +void *lib_memcpy(void *dest,const void *src,size_t cnt); +void *lib_memset(void *dest,int c,size_t cnt); +char *lib_strdup(char *str); +void lib_trimleading(char *str); +void lib_chop_filename(char *str,char **host,char **file); +void lib_strupr(char *s); +char lib_toupper(char c); +char *lib_strcat(char *dest,const char *src); +char *lib_gettoken(char **str); +char *lib_strnchr(const char *dest,int c,size_t cnt); +int lib_parseipaddr(const char *ipaddr,uint8_t *dest); +int lib_atoi(const char *dest); +int lib_lookup(const cons_t *list,char *str); +int lib_setoptions(const cons_t *list,char *str,unsigned int *flags); +int lib_xtoi(const char *dest); +uint64_t lib_xtoq(const char *dest); + + + +#ifndef _LIB_NO_MACROS_ +#define strcpy(d,s) lib_strcpy(d,s) +#define strncpy(d,s,c) lib_strncpy(d,s,c) +#define xstrncpy(d,s,c) lib_xstrncpy(d,s,c) +#define strlen(s) lib_strlen(s) +#define strchr(s,c) lib_strchr(s,c) +#define strrchr(s,c) lib_strrchr(s,c) +#define strdup(s) lib_strdup(s) +#define strcmp(d,s) lib_strcmp(d,s) + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#define strncmp(d,s,c) lib_strncmp(d,s,c) +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +#define strcmpi(d,s) lib_strcmpi(d,s) +#define memcmp(d,s,c) lib_memcmp(d,s,c) +#define memset(d,s,c) lib_memset(d,s,c) +#define memcpy(d,s,c) lib_memcpy(d,s,c) +#define bcopy(s,d,c) lib_memcpy(d,s,c) +#define bzero(d,c) lib_memset(d,0,c) +#define strupr(s) lib_strupr(s) +#define toupper(c) lib_toupper(c) +#define strcat(d,s) lib_strcat(d,s) +#define gettoken(s) lib_gettoken(s) +#define strnchr(d,ch,cnt) lib_strnchr(d,ch,cnt) +#define atoi(d) lib_atoi(d) +#define xtoi(d) lib_xtoi(d) +#define xtoq(d) lib_xtoq(d) +#define parseipaddr(i,d) lib_parseipaddr(i,d) +#define lookup(x,y) lib_lookup(x,y) +#define setoptions(x,y,z) lib_setoptions(x,y,z) +#endif + +void +qsort(void *bot, size_t nmemb, size_t size, int (*compar)(const void *,const void *)); + diff --git a/cfe/cfe/include/lib_types.h b/cfe/cfe/include/lib_types.h new file mode 100644 index 0000000..7453a0d --- /dev/null +++ b/cfe/cfe/include/lib_types.h @@ -0,0 +1,120 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Basic types File: lib_types.h + * + * This module defines the basic types used in CFE. Simple + * types, such as uint64_t, are defined here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifdef __mips +#if ((defined(__MIPSEB)+defined(__MIPSEL)) != 1) +#error "Either __MIPSEB or __MIPSEL must be defined!" +#endif +#endif + + +#ifndef _LIB_TYPES_H +#define _LIB_TYPES_H + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* ********************************************************************* + * Basic types + ********************************************************************* */ + +typedef int size_t; + +typedef char int8_t; +typedef unsigned char uint8_t; + +typedef short int16_t; +typedef unsigned short uint16_t; + +#ifdef __long64 +typedef int int32_t; +typedef unsigned int uint32_t; +#else +typedef long int32_t; +typedef unsigned long uint32_t; +#endif + +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#define unsigned signed /* Kludge to get unsigned size-shaped type. */ +typedef __SIZE_TYPE__ intptr_t; +#undef unsigned +typedef __SIZE_TYPE__ uintptr_t; + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#ifndef offsetof +#define offsetof(type,memb) ((size_t)&((type *)0)->memb) +#endif + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct cons_s { + char *str; + int num; +} cons_t; + +#endif diff --git a/cfe/cfe/include/socregs.h b/cfe/cfe/include/socregs.h new file mode 100644 index 0000000..835f8aa --- /dev/null +++ b/cfe/cfe/include/socregs.h @@ -0,0 +1,63 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * SOC Register table defs File: socregs.h + * + * Data structures related to the "show soc" command and the + * "makereg" program. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +typedef struct socreg_s socreg_t; + +struct socreg_s { + uint32_t reg_addr; + uint32_t reg_agent; + const char *reg_inst; + const char *reg_subinst; + uint32_t reg_mask; + void (*reg_printfunc)(const socreg_t *reg,uint64_t value); + const char *reg_descr; +}; + + + + diff --git a/cfe/cfe/include/tftpd.h b/cfe/cfe/include/tftpd.h new file mode 100755 index 0000000..d7a15a9 --- /dev/null +++ b/cfe/cfe/include/tftpd.h @@ -0,0 +1,26 @@ +/*************************************************************************** +*** +*** Copyright 2005 Hon Hai Precision Ind. Co. Ltd. +*** All Rights Reserved. +*** No portions of this material shall be reproduced in any form without the +*** written permission of Hon Hai Precision Ind. Co. Ltd. +*** +*** All information contained in this document is Hon Hai Precision Ind. +*** Co. Ltd. company private, proprietary, and trade secret property and +*** are protected by international intellectual property laws and treaties. +*** +****************************************************************************/ + +#ifndef __TFTPD_H +#define __TFTPD_H + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#define TFTPD_STATE_OFF 0 +#define TFTPD_STATE_WAIT_IMAGE 1 +#define TFTPD_STATE_WRITE_IMAGE 2 + +extern int get_tftpd_state(void); +extern int set_tftpd_state(int state); +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +#endif diff --git a/cfe/cfe/include/ui_command.h b/cfe/cfe/include/ui_command.h new file mode 100644 index 0000000..e85a3ae --- /dev/null +++ b/cfe/cfe/include/ui_command.h @@ -0,0 +1,140 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Command interpreter defs File: ui_command.h + * + * This file contains structures related to the + * command interpreter. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _LIB_QUEUE_H +#include "lib_queue.h" +#endif + +typedef struct ui_cmdsw_s { + int swidx; + char *swname; + char *swvalue; +} ui_cmdsw_t; + +#define MAX_TOKENS 64 +#define MAX_SWITCHES 16 +#define MAX_TOKEN_SIZE 1000 +typedef struct ui_cmdline_s { + int argc; + char *argv[MAX_TOKENS]; + int swc; + ui_cmdsw_t swv[MAX_SWITCHES]; + int (*func)(struct ui_cmdline_s *,int argc,char *argv[]); + int argidx; + char *ref; + char *usage; + char *switches; +} ui_cmdline_t; + +typedef struct ui_command_s { + queue_t list; + int term; + char *ptr; + queue_t head; +} ui_command_t; + +typedef struct ui_token_s { + queue_t qb; + char token; +} ui_token_t; + +#define CMD_TERM_EOL 0 +#define CMD_TERM_SEMI 1 +#define CMD_TERM_AND 2 +#define CMD_TERM_OR 3 + +int cmd_sw_value(ui_cmdline_t *cmd,char *swname,char **swvalue); +int cmd_sw_posn(ui_cmdline_t *cmd,char *swname); +char *cmd_sw_name(ui_cmdline_t *cmd,int swidx); +int cmd_sw_isset(ui_cmdline_t *cmd,char *swname); +char *cmd_getarg(ui_cmdline_t *cmd,int argnum); +void cmd_free(ui_cmdline_t *cmd); +int cmd_sw_validate(ui_cmdline_t *cmd,char *validstr); +void cmd_parse(ui_cmdline_t *cmd,char *line); +int cmd_addcmd(char *command, + int (*func)(ui_cmdline_t *,int argc,char *argv[]), + void *ref, + char *help, + char *usage, + char *switches); +int cmd_lookup(queue_t *head,ui_cmdline_t *cmd); +void cmd_init(void); +int cmd_getcommand(ui_cmdline_t *cmd); +void cmd_showusage(ui_cmdline_t *cmd); + + + +#define CMD_ERR_INVALID -1 +#define CMD_ERR_AMBIGUOUS -2 +#define CMD_ERR_BLANK -3 + + +/* ********************************************************************* + * Prototypes (public routines) + ********************************************************************* */ + +const char *ui_errstring(int errcode); +int ui_showerror(int errcode,char *tmplt,...); +int ui_showusage(ui_cmdline_t *cmd); +int ui_docommands(char *str); +#define ui_docommand(str) ui_docommands(str) +void ui_restart(int); +int ui_init_cmddisp(void); + + +/* ********************************************************************* + * Prototypes (internal routines) + ********************************************************************* */ + +ui_command_t *cmd_readcommand(queue_t *head); +void cmd_build_list(queue_t *qb,char *buf); +void cmd_walk_and_expand(queue_t *qb); +ui_command_t *cmd_readcommand(queue_t *head); +void cmd_free_tokens(queue_t *list); +void cmd_build_cmdline(queue_t *head, ui_cmdline_t *cmd); + + diff --git a/cfe/cfe/lib/lib_arena.c b/cfe/cfe/lib/lib_arena.c new file mode 100644 index 0000000..41867dc --- /dev/null +++ b/cfe/cfe/lib/lib_arena.c @@ -0,0 +1,389 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Arena Manager File lib_arena.c + * + * This module manages the _arena_, a sorted linked list of + * memory regions and attributes. We use this to keep track + * of physical memory regions and what is assigned to them. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_queue.h" +#include "lib_arena.h" +#include "lib_malloc.h" + +/* ********************************************************************* + * arena_print(arena,msg) + * + * Debug routine to print out an arena entry + * + * Input parameters: + * arena - arena descriptor + * msg - heading message + * + * Return value: + * nothing + ********************************************************************* */ + +#ifdef _TESTPROG_ +static void arena_print(arena_t *arena,char *msg) +{ + arena_node_t *node; + queue_t *qb; + + printf("%s\n",msg); + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + node = (arena_node_t *) qb; + + printf("Start %5I64d End %5I64d Type %d\n", + node->an_address, + node->an_address+node->an_length, + node->an_type); + + } + +} +#endif + +/* ********************************************************************* + * arena_init(arena,physmembase,physmemsize) + * + * Initialize an arena descriptor. The arena is typically + * created to describe the entire physical memory address space. + * + * Input parameters: + * arena - arena descriptor + * physmembase - base of region to manage (usually 0) + * physmemsize - size of region to manage (typically maxint) + * + * Return value: + * nothing + ********************************************************************* */ + +void arena_init(arena_t *arena,uint64_t physmembase,uint64_t physmemsize) +{ + arena_node_t *an = NULL; + + an = (arena_node_t *) KMALLOC(sizeof(arena_node_t),sizeof(uint64_t)); + + /* XXX check return value */ + + arena->arena_base = physmembase; + arena->arena_size = physmemsize; + + an->an_address = physmembase; + an->an_length = physmemsize; + an->an_type = 0; + an->an_descr = NULL; + + q_init(&(arena->arena_list)); + q_enqueue(&(arena->arena_list),(queue_t *) an); +} + + +/* ********************************************************************* + * arena_find(arena,pt) + * + * Locate the arena node containing a particular point in the + * address space. This routine walks the list and finds the node + * whose address range contains the specified point. + * + * Input parameters: + * arena - arena descriptor + * pt - point to look for + * + * Return value: + * arena node pointer, or NULL if no node found + ********************************************************************* */ + +static arena_node_t *arena_find(arena_t *arena,uint64_t pt) +{ + queue_t *qb; + arena_node_t *an; + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + an = (arena_node_t *) qb; + + if ((pt >= an->an_address) && + (pt < (an->an_address + an->an_length))) return an; + + } + + return NULL; +} + +/* ********************************************************************* + * arena_split(arena,splitpoint) + * + * Split the node containing the specified point. When we carve + * the arena up, we split the arena at the points on the edges + * of the new region, change their types, and then coalesce the + * arena. This handles the "split" part of that process. + * + * Input parameters: + * arena - arena descriptor + * splitpoint - address to split arena at + * + * Return value: + * 0 if ok + * -1 if could not split + ********************************************************************* */ + +static int arena_split(arena_t *arena,uint64_t splitpoint) +{ + arena_node_t *node; + arena_node_t *newnode; + + /* + * Don't need to split if it's the *last* address in the arena + */ + + if (splitpoint == (arena->arena_base+arena->arena_size)) return 0; + + /* + * Find the block that contains the split point. + */ + + node = arena_find(arena,splitpoint); + if (node == NULL) return -1; /* should not happen */ + + /* + * If the address matches exactly, don't need to split + */ + if (node->an_address == splitpoint) return 0; + + /* + * Allocate a new node and adjust the length of the node we're + * splitting. + */ + + newnode = (arena_node_t *) KMALLOC(sizeof(arena_node_t),sizeof(uint64_t)); + + newnode->an_length = node->an_length - (splitpoint - node->an_address); + node->an_length = splitpoint - node->an_address; + newnode->an_address = splitpoint; + newnode->an_type = node->an_type; + + /* + * Put the new node in the arena + */ + + q_enqueue(node->an_next.q_next,(queue_t *) newnode); + + return 0; +} + +/* ********************************************************************* + * arena_coalesce(arena) + * + * Coalesce the arena, merging regions that have the same type + * together. After coalescing, no two adjacent nodes will + * have the same type. + * + * Input parameters: + * arena - arena descriptor + * + * Return value: + * nothing + ********************************************************************* */ + +static void arena_coalesce(arena_t *arena) +{ + arena_node_t *node; + arena_node_t *nextnode; + int removed; + queue_t *qb; + + do { + removed = 0; + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + + node = (arena_node_t *) qb; + nextnode = (arena_node_t *) node->an_next.q_next; + + if ((queue_t *) nextnode == &(arena->arena_list)) break; + + if (node->an_type == nextnode->an_type) { + node->an_length += nextnode->an_length; + q_dequeue((queue_t *) nextnode); + KFREE(nextnode); + removed++; + } + } + } while (removed > 0); +} + + +/* ********************************************************************* + * arena_markrange(arena,address,length,type,descr) + * + * Mark a region in the arena, changing the types of nodes and + * splitting nodes as necessary. This routine is called for + * each region we want to add. The order of marking regions is + * important, since new marks overwrite old ones. Therefore, you + * could mark a whole range as DRAM, and then mark sub-regions + * within that as used by firmware. + * + * Input parameters: + * arena - arena descriptor + * address,length - region to mark + * type - type code for region + * descr - text description of region (optional) + * + * Return value: + * 0 if ok + * -1 if error + ********************************************************************* */ + +int arena_markrange(arena_t *arena,uint64_t address,uint64_t length,int type,char *descr) +{ + queue_t *qb; + arena_node_t *node; + + /* + * Range check the region we want to mark + */ + + if ((address < arena->arena_base) || + ((address+length) > (arena->arena_base + arena->arena_size))) { + return -1; + } + + /* + * Force the arena to be split at the two points at the + * beginning and end of the range we want. If we have + * problems, coalesce the arena again and get out. + */ + + if (arena_split(arena,address) < 0) { + /* don't need to coalesce, we didn't split */ + return -1; + } + if (arena_split(arena,(address+length)) < 0) { + /* recombine nodes split above */ + arena_coalesce(arena); + return -1; + } + + /* + * Assuming we've split the arena at the beginning and ending + * split points, we'll never mark any places outside the range + * specified in the "Address,length" args. + */ + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + node = (arena_node_t *) qb; + + if ((node->an_address >= address) && + ((node->an_address + node->an_length) <= (address+length))) { + node->an_type = type; + node->an_descr = descr; + } + } + + /* + * Now, coalesce adjacent pieces with the same type back together again + */ + + arena_coalesce(arena); + + return 0; +} + + + +/* ********************************************************************* + * main(argc,argv) + * + * Test program. + * + * Input parameters: + * argc,argv - guess + * + * Return value: + * nothing + ********************************************************************* */ + +#ifdef _TESTPROG_ +void main(int argc,char *argv[]) +{ + arena_t arena; + + arena_init(&arena,0,1024); +#if 0 + arena_print(&arena,"empty arena------------"); + + arena_split(&arena,5); + arena_print(&arena,"split at 5-------------"); + + arena_split(&arena,300); + arena_print(&arena,"split at 300-----------"); + + arena_split(&arena,100); + arena_print(&arena,"split at 100-----------"); + + arena_coalesce(&arena); + arena_print(&arena,"coalesced again--------"); + + arena_markrange(&arena,100,50,1); + arena_print(&arena,"addrange 100-150-------"); + arena_markrange(&arena,10,50,1); + arena_print(&arena,"addrange 10-60---------"); + arena_markrange(&arena,1000,24,3); + arena_print(&arena,"addrange 1000-1023-----"); +#endif + + arena_markrange(&arena,100,10,1); + arena_markrange(&arena,120,10,2); + arena_markrange(&arena,140,10,3); + arena_print(&arena,"Before big markrange---------"); + + arena_markrange(&arena,50,200,4); + arena_print(&arena,"after big markrange---------"); + +} +#endif diff --git a/cfe/cfe/lib/lib_malloc.c b/cfe/cfe/lib/lib_malloc.c new file mode 100644 index 0000000..f7e33b2 --- /dev/null +++ b/cfe/cfe/lib/lib_malloc.c @@ -0,0 +1,620 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Local memory manager File: cfe_malloc.c + * + * This routine is used to manage memory allocated within the + * firmware. You give it a chunk of memory to manage, and then + * these routines manage suballocations from there. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifdef TESTPROG +#include +#include +#include +#endif + +#include "lib_types.h" +#include "lib_printf.h" +#include "lib_malloc.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define MEMNODE_SEAL 0xFAAFA123 /* just some random constant */ +#define MINBLKSIZE 64 + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef enum { memnode_free = 0, memnode_alloc } memnode_status_t; + +typedef struct memnode_s { + unsigned int seal; + struct memnode_s *next; /* pointer to next node */ + unsigned int length; /* length of the entire data section */ + memnode_status_t status; /* alloc/free status */ + unsigned char *data; /* points to actual user data */ + void *memnodeptr; /* memnode back pointer (see comments) */ +} memnode_t; + +struct mempool_s { + memnode_t *root; /* pointer to root node */ + unsigned char *base; /* base of memory region */ + unsigned int length; /* size of memory region */ +}; + +#define memnode_data(t,m) (t) (((memnode_t *) (m))+1) + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +mempool_t kmempool; /* default pool */ + +/* ********************************************************************* + * kmeminit(pool,buffer,length) + * + * Initialize the memory manager, given a pointer to an area + * of memory and a size. This routine simply initializes the + * root node to be a single block of empty space. + * + * Input parameters: + * pool - pool pointer + * buffer - beginning of buffer area, must be pointer-aligned + * length - length of buffer area + * + * Return value: + * nothing + ********************************************************************* */ + + +void kmeminit(mempool_t *pool,unsigned char *buffer,int length) +{ + pool->root = (memnode_t *) buffer; + pool->root->seal = MEMNODE_SEAL; + pool->root->length = length - sizeof(memnode_t); + pool->root->data = memnode_data(unsigned char *,pool->root); + pool->root->status = memnode_free; + pool->root->next = NULL; + + pool->base = buffer; + pool->length = length; +} + + +/* ********************************************************************* + * kmempoolbase(pool) + * + * Returns the base address of the specified memory pool + * + * Input parameters: + * pool - pool pointer + * + * Return value: + * pointer to beginning of pool's memory + ********************************************************************* */ +void *kmempoolbase(mempool_t *pool) +{ + return pool->base; +} + +/* ********************************************************************* + * kmempoolsize(pool) + * + * Returns the total size of the specified memory pool + * + * Input parameters: + * pool - pool pointer + * + * Return value: + * size of pool in bytes + ********************************************************************* */ + +int kmempoolsize(mempool_t *pool) +{ + return pool->length; +} + +/* ********************************************************************* + * kmemcompact(pool) + * + * Compact the memory blocks, coalescing consectutive free blocks + * on the list. + * + * Input parameters: + * pool - pool descriptor + * + * Return value: + * nothing + ********************************************************************* */ + +static void kmemcompact(mempool_t *pool) +{ + memnode_t *m; + int compacted; + + do { + compacted = 0; + + for (m = pool->root; m; m = m->next) { + + /* Check seal to be sure that we're doing ok */ + + if (m->seal != MEMNODE_SEAL) { +#ifdef TESTPROG + printf("Memory list corrupted!\n"); +#endif + return; + } + + /* + * If we're not on the last block and both this + * block and the next one are free, combine them + */ + + if (m->next && + (m->status == memnode_free) && + (m->next->status == memnode_free)) { + m->length += sizeof(memnode_t) + m->next->length; + m->next->seal = 0; + m->next = m->next->next; + compacted++; + } + + /* Keep going till we make a pass without doing anything. */ + } + } while (compacted > 0); +} + + +/* ********************************************************************* + * kfree(ptr) + * + * Return some memory to the pool. + * + * Input parameters: + * ptr - pointer to something allocated via kmalloc() + * + * Return value: + * nothing + ********************************************************************* */ + +void kfree(mempool_t *pool,void *ptr) +{ + memnode_t **backptr; + memnode_t *m; + + if (((unsigned char *) ptr < pool->base) || + ((unsigned char *) ptr >= (pool->base+pool->length))) { +#ifdef TESTPROG + printf("Pointer %08X does not belong to pool %08X\n",ptr,pool); +#endif + return; + } + + backptr = (memnode_t **) (((unsigned char *) ptr) - sizeof(memnode_t *)); + m = *backptr; + + if (m->seal != MEMNODE_SEAL) { +#ifdef TESTPROG + printf("Invalid node freed: %08X\n",m); +#endif + return; + } + + m->status = memnode_free; + + kmemcompact(pool); +} + +/* ********************************************************************* + * lib_outofmemory() + * + * Called when we run out of memory. + * XXX replace with something real someday + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void lib_outofmemory(void); +void lib_outofmemory(void) +{ + xprintf("PANIC: out of memory!\n"); +} + +/* ********************************************************************* + * kmalloc(pool,size,align) + * + * Allocate some memory from the pool. + * + * Input parameters: + * pool - pool structure + * size - size of item to allocate + * align - alignment (must be zero or a power of 2) + * + * Return value: + * pointer to data, or NULL if no memory left + ********************************************************************* */ + +void *kmalloc(mempool_t *pool,unsigned int size,unsigned int align) +{ + memnode_t *m; + memnode_t *newm; + memnode_t **backptr; + uintptr_t daddr = 0; + uintptr_t realsize = 0; + uintptr_t extra; + uintptr_t blkend; + uintptr_t ptralign; + + /* + * Everything should be aligned by at least the + * size of an int64 + */ + + ptralign = (uintptr_t) align; + if (ptralign < sizeof(void *)) ptralign = sizeof(uint64_t); + + /* + * Everything should be at least a multiple of the + * size of a pointer. + */ + + if (size == 0) size = sizeof(void *); + if (size & (sizeof(void *)-1)) { + size += sizeof(void *); + size &= ~(sizeof(void *)-1); + } + + /* + * Find a memnode at least big enough to hold the storage we + * want. + */ + + for (m = pool->root; m; m = m->next) { + + if (m->status == memnode_alloc) continue; + + /* + * If we wanted a particular alignment, we will + * need to adjust the size. + */ + + daddr = memnode_data(uintptr_t,m); + extra = 0; + if (daddr & (ptralign-1)) { + extra = size + (ptralign - (daddr & (ptralign-1))); + } + realsize = size + extra; + + if (m->length < realsize) continue; + break; + } + + /* + * If m is null, there's no memory left. + */ + + if (m == NULL) { + lib_outofmemory(); + return NULL; + } + + /* + * Otherwise, use this block. Calculate the address of the data + * to preserve the alignment. + */ + + if (daddr & (ptralign-1)) { + daddr += ptralign; + daddr &= ~(ptralign-1); + } + + /* Mark this node as allocated. */ + + m->data = (unsigned char *) daddr; + m->status = memnode_alloc; + + /* + * Okay, this is ugly. Store a pointer to the original + * memnode just before what we've allocated. It's guaranteed + * to be aligned at least well enough for this pointer. + * If for some reason the memnode was already exactly + * aligned, backing up will put us inside the memnode + * structure itself... that's why the memnodeptr field + * is there, as a placeholder for this eventuality. + */ + + backptr = (memnode_t **) (m->data - sizeof(memnode_t *)); + *backptr = m; + + /* + * See if we need to split it. + * Don't bother to split if the resulting size will be + * less than MINBLKSIZE bytes + */ + + if (m->length - realsize < MINBLKSIZE) { + return m->data; + } + + /* + * Split this block. Align the address on a pointer-size + * boundary. + */ + + daddr += size; + if (daddr & (uintptr_t)(sizeof(void *)-1)) { + daddr += (uintptr_t)sizeof(void *); + daddr &= ~(uintptr_t)(sizeof(void *)-1); + } + + blkend = memnode_data(uintptr_t,m) + (uintptr_t)(m->length); + + newm = (memnode_t *) daddr; + + newm->next = m->next; + m->length = (unsigned int) (daddr - memnode_data(uintptr_t,m)); + m->next = newm; + m->status = memnode_alloc; + newm->seal = MEMNODE_SEAL; + newm->data = memnode_data(unsigned char *,newm); + newm->length = (unsigned int) (blkend - memnode_data(uintptr_t,newm)); + newm->status = memnode_free; + + return m->data; +} + + +int kmemstats(mempool_t *pool,memstats_t *stats) +{ + memnode_t *m; + memnode_t **backptr; + uintptr_t daddr; + + stats->mem_totalbytes = pool->length; + stats->mem_allocbytes = 0; + stats->mem_freebytes = 0; + stats->mem_allocnodes = 0; + stats->mem_freenodes = 0; + stats->mem_largest = 0; + + for (m = pool->root; m; m = m->next) { + if (m->status) { + stats->mem_allocnodes++; + stats->mem_allocbytes += m->length; + } + else { + stats->mem_freenodes++; + stats->mem_freebytes += m->length; + if (m->length > stats->mem_largest) { + stats->mem_largest = m->length; + } + } + + daddr = memnode_data(uintptr_t,m); + if (m->seal != MEMNODE_SEAL) { + return -1; + } + if (m->next && ((daddr + m->length) != (uintptr_t) m->next)) { + return -1; + } + if (m->next && (m->next < m)) { + return -1; + } + if (m->data < (unsigned char *) m) { + return -1; + } + if (m->status == memnode_alloc) { + backptr = (memnode_t **) (m->data - sizeof(void *)); + if (*backptr != m) { + return -1; + } + } + } + + return 0; +} + + +/* ********************************************************************* + * kmemchk() + * + * Check the consistency of the memory pool. + * + * Input parameters: + * pool - pool pointer + * + * Return value: + * 0 - pool is consistent + * -1 - pool is corrupt + ********************************************************************* */ + +#ifdef TESTPROG +int kmemchk(mempool_t *pool,int verbose) +{ + memnode_t *m; + memnode_t **backptr; + unsigned int daddr; + + for (m = pool->root; m; m = m->next) { + if (verbose) { + printf("%08X: Next=%08X Len=%5u %s Data=%08X ", + m,m->next,m->length, + m->status ? "alloc" : "free ", + m->data); + } + daddr = memnode_data(uintptr_t,m); + if (m->seal != MEMNODE_SEAL) { + if (verbose) printf("BadSeal "); + else return -1; + } + if (m->next && (daddr + m->length != (unsigned int) m->next)) { + if (verbose) printf("BadLength "); + else return -1; + } + if (m->next && (m->next < m)) { + if (verbose) printf("BadOrder "); + else return -1; + } + if (m->data < (unsigned char *) m) { + if (verbose) printf("BadData "); + else return -1; + } + if (m->status == memnode_alloc) { + backptr = (memnode_t **) (m->data - sizeof(void *)); + if (*backptr != m) { + if (verbose) printf("BadBackPtr "); + else return -1; + } + } + if (verbose) printf("\n"); + } + + return 0; +} + + +#define MEMSIZE 1024*1024 + +unsigned char *ptrs[4096]; +unsigned int sizes[4096]; + +/* ********************************************************************* + * main(argc,argv) + * + * Test program for the memory allocator + * + * Input parameters: + * argc,argv + * + * Return value: + * nothing + ********************************************************************* */ + + +void main(int argc,char *argv[]) +{ + unsigned char *mem; + int items = 0; + int idx; + int size; + int totalsize = 0; + int nfree,freecnt; + mempool_t *pool = &kmempool; + + mem = malloc(MEMSIZE); + kmeminit(pool,mem,MEMSIZE); + + items = 0; + + for (;;) { + + for (;;) { + if (items == 4096) break; + size = rand() % 1024; + ptrs[items] = kmalloc(pool,size,1<<(rand() & 7)); + if (!ptrs[items]) break; + sizes[items] = size; + items++; + totalsize += size; + } + + printf("%d items allocated, %d total bytes\n",items,totalsize); + + if (kmemchk(pool,0) < 0) { + kmemchk(pool,1); + exit(1); + } + + /* Scramble the pointers */ + idx = items - 1; + + while (idx) { + if (rand() & 2) { + mem = ptrs[0]; + ptrs[0] = ptrs[idx]; + ptrs[idx] = mem; + + nfree = sizes[0]; + sizes[0] = sizes[idx]; + sizes[idx] = nfree; + } + idx--; + } + + /* now free a random number of elements */ + + nfree = rand() % items; + freecnt = 0; + + for (idx = nfree; idx < items; idx++) { + kfree(pool,ptrs[idx]); + totalsize -= sizes[idx]; + freecnt++; + ptrs[idx] = NULL; + sizes[idx] = 0; + if (kmemchk(pool,0) < 0) { + kmemchk(pool,1); + exit(1); + } + } + + items -= freecnt; + + printf("."); + + } + + kmemchk(pool,1); + + exit(0); +} + +#endif /* TESTPROG */ diff --git a/cfe/cfe/lib/lib_misc.c b/cfe/cfe/lib/lib_misc.c new file mode 100644 index 0000000..e5a2a02 --- /dev/null +++ b/cfe/cfe/lib/lib_misc.c @@ -0,0 +1,229 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Misc. library routines File: lib_misc.c + * + * Miscellaneous library routines. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#define _LIB_NO_MACROS_ +#include "lib_string.h" + + +/* ********************************************************************* + * lib_parseipaddr(ipaddr,dest) + * + * Parse an IP address. + * + * Input parameters: + * ipaddr - string of IP address + * dest - pointer to 4 bytes to receive binary IP address + * + * Return value: + * 0 if ok + * -1 if ip address is invalid + ********************************************************************* */ + +int lib_parseipaddr(const char *ipaddr,uint8_t *dest) +{ + int a,b,c,d; + char *x; + + /* make sure it's all digits and dots. */ + x = (char *) ipaddr; + while (*x) { + if ((*x == '.') || ((*x >= '0') && (*x <= '9'))) { + x++; + continue; + } + return -1; + } + + x = (char *) ipaddr; + a = lib_atoi(ipaddr); + x = lib_strchr(x,'.'); + if (!x) return -1; + b = lib_atoi(x+1); + x = lib_strchr(x+1,'.'); + if (!x) return -1; + c = lib_atoi(x+1); + x = lib_strchr(x+1,'.'); + if (!x) return -1; + d = lib_atoi(x+1); + + if ((a < 0) || (a > 255)) return -1; + if ((b < 0) || (b > 255)) return -1; + if ((c < 0) || (c > 255)) return -1; + if ((d < 0) || (d > 255)) return -1; + + dest[0] = (uint8_t) a; + dest[1] = (uint8_t) b; + dest[2] = (uint8_t) c; + dest[3] = (uint8_t) d; + + return 0; +} + + +/* ********************************************************************* + * lib_lookup(list,str) + * + * Look up an element on a {string,value} list. + * + * Input parameters: + * list - list to search + * str - string to find on the list + * + * Return value: + * 0 if string was not found + * else number associated with this string + ********************************************************************* */ + +int lib_lookup(const cons_t *list,char *str) +{ + while (list->str) { + if (lib_strcmp(list->str,str) == 0) return list->num; + list++; + } + + return 0; + +} + +/* ********************************************************************* + * lib_findinlist(list,str) + * + * Like lib_lookup but returns cons structure instead of value + * + * Input parameters: + * list - list of associations + * str - what to find + * + * Return value: + * cons_t or null if not found + ********************************************************************* */ + +static const cons_t *lib_findinlist(const cons_t *list,char *str) +{ + while (list->str) { + if (lib_strcmp(list->str,str) == 0) return list; + list++; + } + return NULL; +} + + +/* ********************************************************************* + * lib_setoptions(list,str,flags) + * + * Set or reset one or more bits in a flags variable based + * on the list of valid bits and a string containing what + * to change. flags starts off as a default value. + * + * The input string is a comma-separated list of options, + * optionally prefixed by "no_" or "no" to invert the + * sense of the option. negative values in the table + * remove options, positive add options (you can't use + * bit 31 as an option for this reason). + * + * Input parameters: + * list - list of valid options + * str - options to parse + * flags - pointer to variable to be modified + * + * Return value: + * number of options we did not understand, 0=ok + ********************************************************************* */ + +int lib_setoptions(const cons_t *list,char *str,unsigned int *flags) +{ + char *dupstr; + char *x; + char *ptr; + const cons_t *val; + int newbits; + int errors = 0; + + if (!list || !str || !flags) return 0; + + dupstr = lib_strdup(str); + if (!dupstr) return 0; + + ptr = dupstr; + + while (*ptr) { + if ((x = lib_strchr(ptr,','))) { + *x = '\0'; + } + + val = lib_findinlist(list,ptr); + newbits = 0; + if (!val) { + if (lib_memcmp(ptr,"no_",3) == 0) { + val = lib_findinlist(list,ptr+3); + } + else if (lib_memcmp(ptr,"no",2) == 0) { + val = lib_findinlist(list,ptr+2); + } + if (val) newbits = ~((unsigned int) (val->num)); + else errors++; + } + else { + newbits = (val->num); + } + + /* if new bits are negative, it's an AND mask + otherwise it's an OR mask */ + + if (newbits < 0) *flags &= (unsigned int) newbits; + else *flags |= (unsigned int) newbits; + + if (x) ptr = x+1; + else break; + } + + KFREE(dupstr); + + return errors; +} diff --git a/cfe/cfe/lib/lib_printf.c b/cfe/cfe/lib/lib_printf.c new file mode 100644 index 0000000..7dc3442 --- /dev/null +++ b/cfe/cfe/lib/lib_printf.c @@ -0,0 +1,442 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * simple printf File: lib_printf.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This module contains a very, very, very simple printf + * suitable for use in the boot ROM. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include +#include "lib_types.h" +#include "lib_printf.h" + +/* ********************************************************************* + * Externs * + ********************************************************************* */ + +/* ********************************************************************* + * Globals * + ********************************************************************* */ + +static const char digits[17] = "0123456789ABCDEF"; +static const char ldigits[17] = "0123456789abcdef"; + +int (*xprinthook)(const char *str) = NULL; + +/* ********************************************************************* + * __atox(buf,num,radix,width) + * + * Convert a number to a string + * + * Input Parameters: + * buf - where to put characters + * num - number to convert + * radix - radix to convert number to (usually 10 or 16) + * width - width in characters + * + * Return Value: + * number of digits placed in output buffer + ********************************************************************* */ +static int __atox(char *buf,unsigned int num,unsigned int radix,int width, + const char *digits) +{ + char buffer[16]; + char *op; + int retval; + + op = &buffer[0]; + retval = 0; + + do { + *op++ = digits[num % radix]; + retval++; + num /= radix; + } while (num != 0); + + if (width && (width > retval)) { + width = width - retval; + while (width) { + *op++ = '0'; + retval++; + width--; + } + } + + while (op != buffer) { + op--; + *buf++ = *op; + } + + return retval; +} + + +/* ********************************************************************* + * __llatox(buf,num,radix,width) + * + * Convert a long number to a string + * + * Input Parameters: + * buf - where to put characters + * num - number to convert + * radix - radix to convert number to (usually 10 or 16) + * width - width in characters + * + * Return Value: + * number of digits placed in output buffer + ********************************************************************* */ +static int __llatox(char *buf,unsigned long long num,unsigned int radix, + int width,const char *digits) +{ + char buffer[16]; + char *op; + int retval; + + op = &buffer[0]; + retval = 0; + +#ifdef _MIPSREGS32_ + /* + * Hack: to avoid pulling in the helper library that isn't necessarily + * compatible with PIC code, force radix to 16, use shifts and masks + */ + do { + *op++ = digits[num & 0x0F]; + retval++; + num >>= 4; + } while (num != 0); +#else + do { + *op++ = digits[num % radix]; + retval++; + num /= radix; + } while (num != 0); +#endif + + if (width && (width > retval)) { + width = width - retval; + while (width) { + *op++ = '0'; + retval++; + width--; + } + } + + while (op != buffer) { + op--; + *buf++ = *op; + } + + return retval; +} + +/* ********************************************************************* + * xvsprintf(outbuf,template,arglist) + * + * Format a string into the output buffer + * + * Input Parameters: + * outbuf - output buffer + * template - template string + * arglist - parameters + * + * Return Value: + * number of characters copied + ********************************************************************* */ +#define isdigit(x) (((x) >= '0') && ((x) <= '9')) +int xvsprintf(char *outbuf,const char *templat,va_list marker) +{ + char *optr; + const char *iptr; + unsigned char *tmpptr; + unsigned int x; + unsigned long long lx; + int i; + long long ll; + int leadingzero; + int leadingnegsign; + int islong; + int width; + int width2 = 0; + int hashash = 0; + + optr = outbuf; + iptr = templat; + + while (*iptr) { + if (*iptr != '%') {*optr++ = *iptr++; continue;} + + iptr++; + + if (*iptr == '#') { hashash = 1; iptr++; } + if (*iptr == '-') { + leadingnegsign = 1; + iptr++; + } + else leadingnegsign = 0; + + if (*iptr == '0') leadingzero = 1; + else leadingzero = 0; + + width = 0; + while (*iptr && isdigit(*iptr)) { + width += (*iptr - '0'); + iptr++; + if (isdigit(*iptr)) width *= 10; + } + if (*iptr == '.') { + iptr++; + width2 = 0; + while (*iptr && isdigit(*iptr)) { + width2 += (*iptr - '0'); + iptr++; + if (isdigit(*iptr)) width2 *= 10; + } + } + + islong = 0; + if (*iptr == 'l') { islong++; iptr++; } + if (*iptr == 'l') { islong++; iptr++; } + + switch (*iptr) { + case 'I': + tmpptr = (unsigned char *) va_arg(marker,unsigned char *); + optr += __atox(optr,*tmpptr++,10,0,digits); + *optr++ = '.'; + optr += __atox(optr,*tmpptr++,10,0,digits); + *optr++ = '.'; + optr += __atox(optr,*tmpptr++,10,0,digits); + *optr++ = '.'; + optr += __atox(optr,*tmpptr++,10,0,digits); + break; + case 's': + tmpptr = (unsigned char *) va_arg(marker,unsigned char *); + if (!tmpptr) tmpptr = (unsigned char *) "(null)"; + if ((width == 0) & (width2 == 0)) { + while (*tmpptr) *optr++ = *tmpptr++; + break; + } + while (width && *tmpptr) { + *optr++ = *tmpptr++; + width--; + } + while (width) { + *optr++ = ' '; + width--; + } + break; + case 'a': + tmpptr = (unsigned char *) va_arg(marker,unsigned char *); + for (x = 0; x < 5; x++) { + optr += __atox(optr,*tmpptr++,16,2,digits); + *optr++ = '-'; + } + optr += __atox(optr,*tmpptr++,16,2,digits); + break; + case 'd': + switch (islong) { + case 0: + case 1: + i = va_arg(marker,int); + if (i < 0) { *optr++='-'; i = -i;} + optr += __atox(optr,i,10,width,digits); + break; + case 2: + ll = va_arg(marker,long long int); + if (ll < 0) { *optr++='-'; ll = -ll;} + optr += __llatox(optr,ll,10,width,digits); + break; + } + break; + case 'u': + switch (islong) { + case 0: + case 1: + x = va_arg(marker,unsigned int); + optr += __atox(optr,x,10,width,digits); + break; + case 2: + lx = va_arg(marker,unsigned long long); + optr += __llatox(optr,lx,10,width,digits); + break; + } + break; + case 'X': + case 'x': + switch (islong) { + case 0: + case 1: + x = va_arg(marker,unsigned int); + optr += __atox(optr,x,16,width, + (*iptr == 'X') ? digits : ldigits); + break; + case 2: + lx = va_arg(marker,unsigned long long); + optr += __llatox(optr,lx,16,width, + (*iptr == 'X') ? digits : ldigits); + break; + } + break; + case 'p': + case 'P': +#ifdef __long64 + lx = va_arg(marker,unsigned long long); + optr += __llatox(optr,lx,16,16, + (*iptr == 'P') ? digits : ldigits); +#else + x = va_arg(marker,unsigned int); + optr += __atox(optr,x,16,8, + (*iptr == 'P') ? digits : ldigits); +#endif + break; + case 'w': + x = va_arg(marker,unsigned int); + x &= 0x0000FFFF; + optr += __atox(optr,x,16,4,digits); + break; + case 'b': + x = va_arg(marker,unsigned int); + x &= 0x0000FF; + optr += __atox(optr,x,16,2,digits); + break; + case 'Z': + x = va_arg(marker,unsigned int); + tmpptr = va_arg(marker,unsigned char *); + while (x) { + optr += __atox(optr,*tmpptr++,16,2,digits); + x--; + } + break; + case 'c': + x = va_arg(marker, int); + *optr++ = x & 0xff; + break; + + default: + *optr++ = *iptr; + break; + } + iptr++; + } + + *optr = '\0'; + + return (optr - outbuf); +} + + +/* ********************************************************************* + * xsprintf(buf,template,params..) + * + * format messages from template into a buffer. + * + * Input Parameters: + * buf - output buffer + * template - template string + * params... parameters + * + * Return Value: + * number of bytes copied to buffer + ********************************************************************* */ +int xsprintf(char *buf,const char *templat,...) +{ + va_list marker; + int count; + + va_start(marker,templat); + count = xvsprintf(buf,templat,marker); + va_end(marker); + + return count; +} + +/* ********************************************************************* + * xprintf(template,...) + * + * A miniature printf. + * + * %a - Ethernet address (16 bytes) + * %s - unpacked string, null terminated + * %x - hex word (machine size) + * %w - hex word (16 bits) + * %b - hex byte (8 bits) + * %Z - buffer (put length first, then buffer address) + * + * Return value: + * number of bytes written + ********************************************************************* */ + +int xprintf(const char *templat,...) +{ + va_list marker; + int count; + char buffer[512]; + + va_start(marker,templat); + count = xvsprintf(buffer,templat,marker); + va_end(marker); + + if (xprinthook) (*xprinthook)(buffer); + + return count; +} + + +int xvprintf(const char *templat,va_list marker) +{ + int count; + char buffer[512]; + + count = xvsprintf(buffer,templat,marker); + + if (xprinthook) (*xprinthook)(buffer); + + return count; +} + + + + + + + + diff --git a/cfe/cfe/lib/lib_qsort.c b/cfe/cfe/lib/lib_qsort.c new file mode 100644 index 0000000..f3c60b8 --- /dev/null +++ b/cfe/cfe/lib/lib_qsort.c @@ -0,0 +1,88 @@ +#include "lib_types.h" +#include "lib_string.h" + +#define CHAR_BIT 8 +#define MAXSTACK (sizeof(int) * CHAR_BIT) + +static void qsexchange(void *a, void *b, size_t size) +{ + size_t i; + + /****************** + * exchange a,b * + ******************/ + + for (i = sizeof(int); i <= size; i += sizeof(int)) { + int t = *((int *)a); + *(((int *)a)++) = *((int *)b); + *(((int *)b)++) = t; + } + for (i = i - sizeof(int) + 1; i <= size; i++) { + char t = *((char *)a); + *(((char *)a)++) = *((char *)b); + *(((char *)b)++) = t; + } +} + +void qsort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +{ + void *lbStack[MAXSTACK], *ubStack[MAXSTACK]; + int sp; + unsigned int offset; + + /******************** + * ANSI-C qsort() * + ********************/ + + lbStack[0] = (char *)base; + ubStack[0] = (char *)base + (nmemb-1)*size; + for (sp = 0; sp >= 0; sp--) { + char *lb, *ub, *m; + char *P, *i, *j; + + lb = lbStack[sp]; + ub = ubStack[sp]; + + while (lb < ub) { + + /* select pivot and exchange with 1st element */ + offset = (ub - lb) >> 1; + P = lb + offset - offset % size; + qsexchange (lb, P, size); + + /* partition into two segments */ + i = lb + size; + j = ub; + while (1) { + while (i < j && compar(lb, i) > 0) i += size; + while (j >= i && compar(j, lb) > 0) j -= size; + if (i >= j) break; + qsexchange (i, j, size); + j -= size; + i += size; + } + + /* pivot belongs in A[j] */ + qsexchange (lb, j, size); + m = j; + + /* keep processing smallest segment, and stack largest */ + if (m - lb <= ub - m) { + if (m + size < ub) { + lbStack[sp] = m + size; + ubStack[sp++] = ub; + } + ub = m - size; + } + else { + if (m - size > lb) { + lbStack[sp] = lb; + ubStack[sp++] = m - size; + } + lb = m + size; + } + } + } +} + diff --git a/cfe/cfe/lib/lib_queue.c b/cfe/cfe/lib/lib_queue.c new file mode 100644 index 0000000..0712adf --- /dev/null +++ b/cfe/cfe/lib/lib_queue.c @@ -0,0 +1,219 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Queue Management routines File: lib_queue.c + * + * Routines to manage doubly-linked queues. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_queue.h" + + +/* ********************************************************************* + * Q_ENQUEUE(qb,item) + * + * Add item to a queue + * + * Input Parameters: + * qb - queue block + * item - item to add + * + * Return Value: + * Nothing. + ********************************************************************* */ + +void q_enqueue(queue_t *qb,queue_t *item) +{ + qb->q_prev->q_next = item; + item->q_next = qb; + item->q_prev = qb->q_prev; + qb->q_prev = item; +} + + +/* ********************************************************************* + * Q_DEQUEUE(element) + * + * Remove an element from the queue + * + * Input Parameters: + * element - element to remove + * + * Return Value: + * Nothing. + ********************************************************************* */ + +void q_dequeue(queue_t *item) +{ + item->q_prev->q_next = item->q_next; + item->q_next->q_prev = item->q_prev; +} + + +/* ********************************************************************* + * Q_DEQNEXT(qb) + * + * Dequeue next element from the specified queue + * + * Input Parameters: + * qb - queue block + * + * Return Value: + * next element, or NULL + ********************************************************************* */ + +queue_t *q_deqnext(queue_t *qb) +{ + if (qb->q_next == qb) { + return NULL; + } + + qb = qb->q_next; + + qb->q_prev->q_next = qb->q_next; + qb->q_next->q_prev = qb->q_prev; + + return qb; +} + + +/* ********************************************************************* + * Q_MAP(qb) + * + * "Map" a queue, calling the specified function for each + * element in the queue + * + * If the function returns nonzero, q_map will terminate. + * + * Input Parameters: + * qb - queue block + * fn - function pointer + * a,b - parameters for the function + * + * Return Value: + * return value from function, or zero if entire queue + * was mapped. + ********************************************************************* */ + +int q_map(queue_t *qb, int (*func)(queue_t *,unsigned int,unsigned int), + unsigned int a,unsigned int b) +{ + queue_t *qe; + queue_t *nextq; + int res; + + qe = qb; + + qe = qb->q_next; + + while (qe != qb) { + nextq = qe->q_next; + if ((res = (*func)(qe,a,b))) return res; + qe = nextq; + } + + return 0; +} + + + + + +/* ********************************************************************* + * Q_COUNT(qb) * + * * + * Counts the elements on a queue (not interlocked) * + * * + * Input Parameters: * + * qb - queue block * + * * + * Return Value: * + * number of elements * + ********************************************************************* */ +int q_count(queue_t *qb) +{ + queue_t *qe; + int res = 0; + + qe = qb; + + while (qe->q_next != qb) { + qe = qe->q_next; + res++; + } + + return res; +} + + + + +/* ********************************************************************* + * Q_FIND(qb,item) + * + * Determines if a particular element is on a queue. + * + * Input Parameters: + * qb - queue block + * item - queue element + * + * Return Value: + * 0 - not on queue + * >0 - position on queue + ********************************************************************* */ +int q_find(queue_t *qb,queue_t *item) +{ + queue_t *q; + int res = 1; + + q = qb->q_next; + + while (q != item) { + if (q == qb) return 0; + q = q->q_next; + res++; + } + + return res; +} + diff --git a/cfe/cfe/lib/lib_string.c b/cfe/cfe/lib/lib_string.c new file mode 100644 index 0000000..08e9ee7 --- /dev/null +++ b/cfe/cfe/lib/lib_string.c @@ -0,0 +1,386 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * String routines File: lib_string.c + * + * Some standard routines for messing with strings. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + + +#include "lib_types.h" +#define _LIB_NO_MACROS_ +#include "lib_string.h" + +char *lib_strcpy(char *dest,const char *src) +{ + char *ptr = dest; + + while (*src) *ptr++ = *src++; + *ptr = '\0'; + + return dest; +} + +char *lib_strncpy(char *dest,const char *src,size_t cnt) +{ + char *ptr = dest; + + while (*src && (cnt > 0)) { + *ptr++ = *src++; + cnt--; + } + if (cnt > 0) *ptr = '\0'; + + return dest; +} + + +size_t lib_xstrncpy(char *dest,const char *src,size_t cnt) +{ + char *ptr = dest; + size_t copied = 0; + + while (*src && (cnt > 1)) { + *ptr++ = *src++; + cnt--; + copied++; + } + *ptr = '\0'; + + return copied; +} + +size_t lib_strlen(const char *str) +{ + size_t cnt = 0; + + while (*str) { + str++; + cnt++; + } + + return cnt; +} + + +int lib_strcmp(const char *dest,const char *src) +{ + while (*src && *dest) { + if (*dest < *src) return -1; + if (*dest > *src) return 1; + dest++; + src++; + } + + if (*dest && !*src) return 1; + if (!*dest && *src) return -1; + return 0; +} + +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ +int lib_strncmp(const char *dest, const char *src, size_t cnt ) +{ + while (*src && *dest && cnt) { + if (*dest < *src ) return -1; + if (*dest > *src) return 1; + dest++; + src++; + cnt--; + } + + if (!cnt) return 0; + if (*dest && !*src) return 1; + if (!*dest && *src) return -1; + return 0; +} +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ + + +int lib_strcmpi(const char *dest,const char *src) +{ + char dc,sc; + + while (*src && *dest) { + dc = lib_toupper(*dest); + sc = lib_toupper(*src); + if (dc < sc) return -1; + if (dc > sc) return 1; + dest++; + src++; + } + + if (*dest && !*src) return 1; + if (!*dest && *src) return -1; + return 0; +} + + +char *lib_strchr(const char *dest,int c) +{ + while (*dest) { + if (*dest == c) return (char *) dest; + dest++; + } + return NULL; +} + +char *lib_strnchr(const char *dest,int c,size_t cnt) +{ + while (*dest && (cnt > 0)) { + if (*dest == c) return (char *) dest; + dest++; + cnt--; + } + return NULL; +} + +char *lib_strrchr(const char *dest,int c) +{ + char *ret = NULL; + + while (*dest) { + if (*dest == c) ret = (char *) dest; + dest++; + } + + return ret; +} + + +int lib_memcmp(const void *dest,const void *src,size_t cnt) +{ + const unsigned char *d; + const unsigned char *s; + + d = (const unsigned char *) dest; + s = (const unsigned char *) src; + + while (cnt) { + if (*d < *s) return -1; + if (*d > *s) return 1; + d++; s++; cnt--; + } + + return 0; +} + +void *lib_memcpy(void *dest,const void *src,size_t cnt) +{ + unsigned char *d; + const unsigned char *s; + + d = (unsigned char *) dest; + s = (const unsigned char *) src; + + while (cnt) { + *d++ = *s++; + cnt--; + } + + return dest; +} + +void *lib_memset(void *dest,int c,size_t cnt) +{ + unsigned char *d; + + d = dest; + + while (cnt) { + *d++ = (unsigned char) c; + cnt--; + } + + return d; +} + +char lib_toupper(char c) +{ + if ((c >= 'a') && (c <= 'z')) c -= 32; + return c; +} + +void lib_strupr(char *str) +{ + while (*str) { + *str = lib_toupper(*str); + str++; + } +} + +char *lib_strcat(char *dest,const char *src) +{ + char *ptr = dest; + + while (*ptr) ptr++; + while (*src) *ptr++ = *src++; + *ptr = '\0'; + + return dest; +} + +#define isspace(x) (((x) == ' ') || ((x) == '\t')) + +char *lib_gettoken(char **ptr) +{ + char *p = *ptr; + char *ret; + + /* skip white space */ + + while (*p && isspace(*p)) p++; + ret = p; + + /* check for end of string */ + + if (!*p) { + *ptr = p; + return NULL; + } + + /* skip non-whitespace */ + + while (*p) { + if (isspace(*p)) break; + + /* do quoted strings */ + + if (*p == '"') { + p++; + ret = p; + while (*p && (*p != '"')) p++; + if (*p == '"') *p = '\0'; + } + + p++; + + } + + if (*p) { + *p++ = '\0'; + } + *ptr = p; + + return ret; +} + + +int lib_atoi(const char *dest) +{ + int x = 0; + int digit; + + if ((*dest == '0') && (*(dest+1) == 'x')) { + return lib_xtoi(dest+2); + } + + while (*dest) { + if ((*dest >= '0') && (*dest <= '9')) { + digit = *dest - '0'; + } + else { + break; + } + x *= 10; + x += digit; + dest++; + } + + return x; +} + +uint64_t lib_xtoq(const char *dest) +{ + uint64_t x = 0; + unsigned int digit; + + if ((*dest == '0') && (*(dest+1) == 'x')) dest += 2; + + while (*dest) { + if ((*dest >= '0') && (*dest <= '9')) { + digit = *dest - '0'; + } + else if ((*dest >= 'A') && (*dest <= 'F')) { + digit = 10 + *dest - 'A'; + } + else if ((*dest >= 'a') && (*dest <= 'f')) { + digit = 10 + *dest - 'a'; + } + else { + break; + } + x *= 16; + x += digit; + dest++; + } + + return x; +} + +int lib_xtoi(const char *dest) +{ + int x = 0; + int digit; + + if ((*dest == '0') && (*(dest+1) == 'x')) dest += 2; + + while (*dest) { + if ((*dest >= '0') && (*dest <= '9')) { + digit = *dest - '0'; + } + else if ((*dest >= 'A') && (*dest <= 'F')) { + digit = 10 + *dest - 'A'; + } + else if ((*dest >= 'a') && (*dest <= 'f')) { + digit = 10 + *dest - 'a'; + } + else { + break; + } + x *= 16; + x += digit; + dest++; + } + + return x; +} diff --git a/cfe/cfe/lib/lib_string2.c b/cfe/cfe/lib/lib_string2.c new file mode 100644 index 0000000..e42070a --- /dev/null +++ b/cfe/cfe/lib/lib_string2.c @@ -0,0 +1,96 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * More string routines File: lib_string2.c + * + * More routines to muck with strings; these routines typically + * need malloc to operate. This way lib_string.c can be incorporated + * into other programs that don't need malloc + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_malloc.h" +#define _LIB_NO_MACROS_ +#include "lib_string.h" + + +char *lib_strdup(char *str) +{ + char *buf; + + buf = KMALLOC(lib_strlen(str)+1,0); + if (buf) { + lib_strcpy(buf,str); + } + + return buf; +} + +void lib_trimleading(char *path) +{ + if (*path == '/') { + lib_strcpy(path, path+1); + } + + return; +} + +void lib_chop_filename(char *str,char **host,char **file) +{ + char *p; + + *host = str; + + p = lib_strchr(str,':'); + if (!p) p = lib_strchr(str,'/'); + + if (p) { + *p++ = '\0'; + *file = p; + } + else { + *file = NULL; + } +} + + diff --git a/cfe/cfe/lzma/LzmaDecode.c b/cfe/cfe/lzma/LzmaDecode.c new file mode 100755 index 0000000..cb83453 --- /dev/null +++ b/cfe/cfe/lzma/LzmaDecode.c @@ -0,0 +1,584 @@ +/* + LzmaDecode.c + LZMA Decoder (optimized for Speed version) + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this Code, expressly permits you to + statically or dynamically link your Code (or bind by name) to the + interfaces of this file without subjecting your linked Code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "LzmaDecode.h" + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*Buffer++) + +#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ + { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} + +#ifdef _LZMA_IN_CB + +#define RC_TEST { if (Buffer == BufferLim) \ + { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ + BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} + +#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 + +#else + +#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } + +#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 + +#endif + +#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } + +#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) +#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; +#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; + +#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ + { UpdateBit0(p); mi <<= 1; A0; } else \ + { UpdateBit1(p); mi = (mi + mi) + 1; A1; } + +#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) + +#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ + { int i = numLevels; res = 1; \ + do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ + res -= (1 << numLevels); } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) +{ + unsigned char prop0; + if (size < LZMA_PROPERTIES_SIZE) + return LZMA_RESULT_DATA_ERROR; + prop0 = propsData[0]; + if (prop0 >= (9 * 5 * 5)) + return LZMA_RESULT_DATA_ERROR; + { + for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); + for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); + propsRes->lc = prop0; + /* + unsigned char remainder = (unsigned char)(prop0 / 9); + propsRes->lc = prop0 % 9; + propsRes->pb = remainder / 5; + propsRes->lp = remainder % 5; + */ + } + + #ifdef _LZMA_OUT_READ + { + int i; + propsRes->DictionarySize = 0; + for (i = 0; i < 4; i++) + propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); + if (propsRes->DictionarySize == 0) + propsRes->DictionarySize = 1; + } + #endif + return LZMA_RESULT_OK; +} + +#define kLzmaStreamWasFinishedId (-1) + +int LzmaDecode(CLzmaDecoderState *vs, + #ifdef _LZMA_IN_CB + ILzmaInCallback *InCallback, + #else + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + #endif + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) +{ + CProb *p = vs->Probs; + SizeT nowPos = 0; + Byte previousByte = 0; + UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; + UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; + int lc = vs->Properties.lc; + + #ifdef _LZMA_OUT_READ + + UInt32 Range = vs->Range; + UInt32 Code = vs->Code; + #ifdef _LZMA_IN_CB + const Byte *Buffer = vs->Buffer; + const Byte *BufferLim = vs->BufferLim; + #else + const Byte *Buffer = inStream; + const Byte *BufferLim = inStream + inSize; + #endif + int state = vs->State; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + UInt32 distanceLimit = vs->DistanceLimit; + + Byte *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->Properties.DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + Byte tempDictionary[4]; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + if (len == kLzmaStreamWasFinishedId) + return LZMA_RESULT_OK; + + if (dictionarySize == 0) + { + dictionary = tempDictionary; + dictionarySize = 1; + tempDictionary[0] = vs->TempDictionary[0]; + } + + if (len == kLzmaNeedInitId) + { + { + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + UInt32 i; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + rep0 = rep1 = rep2 = rep3 = 1; + state = 0; + globalPos = 0; + distanceLimit = 0; + dictionaryPos = 0; + dictionary[dictionarySize - 1] = 0; + #ifdef _LZMA_IN_CB + RC_INIT; + #else + RC_INIT(inStream, inSize); + #endif + } + len = 0; + } + while(len != 0 && nowPos < outSize) + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; + + #else /* if !_LZMA_OUT_READ */ + + int state = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + int len = 0; + const Byte *Buffer; + const Byte *BufferLim; + UInt32 Range; + UInt32 Code; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + + { + UInt32 i; + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + } + + #ifdef _LZMA_IN_CB + RC_INIT; + #else + RC_INIT(inStream, inSize); + #endif + + #endif /* _LZMA_OUT_READ */ + + while(nowPos < outSize) + { + CProb *prob; + UInt32 bound; + int posState = (int)( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & posStateMask); + + prob = p + IsMatch + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + int symbol = 1; + UpdateBit0(prob) + prob = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + int matchByte; + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + #else + matchByte = outStream[nowPos - rep0]; + #endif + do + { + int bit; + CProb *probLit; + matchByte <<= 1; + bit = (matchByte & 0x100); + probLit = prob + 0x100 + bit + symbol; + RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) + } + while (symbol < 0x100); + } + while (symbol < 0x100) + { + CProb *probLit = prob + symbol; + RC_GET_BIT(probLit, symbol) + } + previousByte = (Byte)symbol; + + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #endif + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + } + else + { + UpdateBit1(prob); + prob = p + IsRep + state; + IfBit0(prob) + { + UpdateBit0(prob); + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < kNumLitStates ? 0 : 3; + prob = p + LenCoder; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG0 + state; + IfBit0(prob) + { + UpdateBit0(prob); + prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + #ifdef _LZMA_OUT_READ + UInt32 pos; + #endif + UpdateBit0(prob); + + #ifdef _LZMA_OUT_READ + if (distanceLimit == 0) + #else + if (nowPos == 0) + #endif + return LZMA_RESULT_DATA_ERROR; + + state = state < kNumLitStates ? 9 : 11; + #ifdef _LZMA_OUT_READ + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + #endif + + continue; + } + else + { + UpdateBit1(prob); + } + } + else + { + UInt32 distance; + UpdateBit1(prob); + prob = p + IsRepG1 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep1; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG2 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep2; + } + else + { + UpdateBit1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = p + RepLenCoder; + } + { + int numBits, offset; + CProb *probLen = prob + LenChoice; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + numBits = kLenNumLowBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenChoice2; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + numBits = kLenNumMidBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + numBits = kLenNumHighBits; + } + } + RangeDecoderBitTreeDecode(probLen, numBits, len); + len += offset; + } + + if (state < 4) + { + int posSlot; + state += kNumLitStates; + prob = p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = (2 | ((UInt32)posSlot & 1)); + if (posSlot < kEndPosModelIndex) + { + rep0 <<= numDirectBits; + prob = p + SpecPos + rep0 - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + RC_NORMALIZE + Range >>= 1; + rep0 <<= 1; + if (Code >= Range) + { + Code -= Range; + rep0 |= 1; + } + } + while (--numDirectBits != 0); + prob = p + Align; + rep0 <<= kNumAlignBits; + numDirectBits = kNumAlignBits; + } + { + int i = 1; + int mi = 1; + do + { + CProb *prob3 = prob + mi; + RC_GET_BIT2(prob3, mi, ; , rep0 |= i); + i <<= 1; + } + while(--numDirectBits != 0); + } + } + else + rep0 = posSlot; + if (++rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = kLzmaStreamWasFinishedId; + break; + } + } + + len += kMatchMinLen; + #ifdef _LZMA_OUT_READ + if (rep0 > distanceLimit) + #else + if (rep0 > nowPos) + #endif + return LZMA_RESULT_DATA_ERROR; + + #ifdef _LZMA_OUT_READ + if (dictionarySize - distanceLimit > (UInt32)len) + distanceLimit += len; + else + distanceLimit = dictionarySize; + #endif + + do + { + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + RC_NORMALIZE; + + #ifdef _LZMA_OUT_READ + vs->Range = Range; + vs->Code = Code; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = globalPos + (UInt32)nowPos; + vs->DistanceLimit = distanceLimit; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->RemainLen = len; + vs->TempDictionary[0] = tempDictionary[0]; + #endif + + #ifdef _LZMA_IN_CB + vs->Buffer = Buffer; + vs->BufferLim = BufferLim; + #else + *inSizeProcessed = (SizeT)(Buffer - inStream); + #endif + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/cfe/cfe/lzma/LzmaDecode.h b/cfe/cfe/lzma/LzmaDecode.h new file mode 100755 index 0000000..2870eeb --- /dev/null +++ b/cfe/cfe/lzma/LzmaDecode.h @@ -0,0 +1,113 @@ +/* + LzmaDecode.h + LZMA Decoder interface + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#ifndef __LZMADECODE_H +#define __LZMADECODE_H + +#include "LzmaTypes.h" + +/* #define _LZMA_IN_CB */ +/* Use callback for input data */ + +/* #define _LZMA_OUT_READ */ +/* Use read function for output data */ + +/* #define _LZMA_PROB32 */ +/* It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case */ + +/* #define _LZMA_LOC_OPT */ +/* Enable local speed optimizations inside code */ + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb UInt16 +#endif + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + +#ifdef _LZMA_IN_CB +typedef struct _ILzmaInCallback +{ + int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); +} ILzmaInCallback; +#endif + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +typedef struct _CLzmaProperties +{ + int lc; + int lp; + int pb; + #ifdef _LZMA_OUT_READ + UInt32 DictionarySize; + #endif +}CLzmaProperties; + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); + +#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) + +#define kLzmaNeedInitId (-2) + +typedef struct _CLzmaDecoderState +{ + CLzmaProperties Properties; + CProb *Probs; + + #ifdef _LZMA_IN_CB + const unsigned char *Buffer; + const unsigned char *BufferLim; + #endif + + #ifdef _LZMA_OUT_READ + unsigned char *Dictionary; + UInt32 Range; + UInt32 Code; + UInt32 DictionaryPos; + UInt32 GlobalPos; + UInt32 DistanceLimit; + UInt32 Reps[4]; + int State; + int RemainLen; + unsigned char TempDictionary[4]; + #endif +} CLzmaDecoderState; + +#ifdef _LZMA_OUT_READ +#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } +#endif + +int LzmaDecode(CLzmaDecoderState *vs, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback, + #else + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + #endif + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); + +#endif diff --git a/cfe/cfe/lzma/LzmaDecodeSize.c b/cfe/cfe/lzma/LzmaDecodeSize.c new file mode 100755 index 0000000..a3a5eb9 --- /dev/null +++ b/cfe/cfe/lzma/LzmaDecodeSize.c @@ -0,0 +1,712 @@ +/* + LzmaDecodeSize.c + LZMA Decoder (optimized for Size version) + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "LzmaDecode.h" + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +typedef struct _CRangeDecoder +{ + const Byte *Buffer; + const Byte *BufferLim; + UInt32 Range; + UInt32 Code; + #ifdef _LZMA_IN_CB + ILzmaInCallback *InCallback; + int Result; + #endif + int ExtraBytes; +} CRangeDecoder; + +Byte RangeDecoderReadByte(CRangeDecoder *rd) +{ + if (rd->Buffer == rd->BufferLim) + { + #ifdef _LZMA_IN_CB + SizeT size; + rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size); + rd->BufferLim = rd->Buffer + size; + if (size == 0) + #endif + { + rd->ExtraBytes = 1; + return 0xFF; + } + } + return (*rd->Buffer++); +} + +/* #define ReadByte (*rd->Buffer++) */ +#define ReadByte (RangeDecoderReadByte(rd)) + +void RangeDecoderInit(CRangeDecoder *rd + #ifndef _LZMA_IN_CB + , const Byte *stream, SizeT bufferSize + #endif + ) +{ + int i; + #ifdef _LZMA_IN_CB + rd->Buffer = rd->BufferLim = 0; + #else + rd->Buffer = stream; + rd->BufferLim = stream + bufferSize; + #endif + rd->ExtraBytes = 0; + rd->Code = 0; + rd->Range = (0xFFFFFFFF); + for(i = 0; i < 5; i++) + rd->Code = (rd->Code << 8) | ReadByte; +} + +#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code; +#define RC_FLUSH_VAR rd->Range = range; rd->Code = code; +#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; } + +UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits) +{ + RC_INIT_VAR + UInt32 result = 0; + int i; + for (i = numTotalBits; i != 0; i--) + { + /* UInt32 t; */ + range >>= 1; + + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + /* + t = (code - range) >> 31; + t &= 1; + code -= range & (t - 1); + result = (result + result) | (1 - t); + */ + RC_NORMALIZE + } + RC_FLUSH_VAR + return result; +} + +int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd) +{ + UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob; + if (rd->Code < bound) + { + rd->Range = bound; + *prob += (kBitModelTotal - *prob) >> kNumMoveBits; + if (rd->Range < kTopValue) + { + rd->Code = (rd->Code << 8) | ReadByte; + rd->Range <<= 8; + } + return 0; + } + else + { + rd->Range -= bound; + rd->Code -= bound; + *prob -= (*prob) >> kNumMoveBits; + if (rd->Range < kTopValue) + { + rd->Code = (rd->Code << 8) | ReadByte; + rd->Range <<= 8; + } + return 1; + } +} + +#define RC_GET_BIT2(prob, mi, A0, A1) \ + UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \ + if (code < bound) \ + { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \ + else \ + { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \ + RC_NORMALIZE + +#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;) + +int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) +{ + int mi = 1; + int i; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + for(i = numLevels; i != 0; i--) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + mi; + RC_GET_BIT(prob, mi) + #else + mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd); + #endif + } + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return mi - (1 << numLevels); +} + +int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) +{ + int mi = 1; + int i; + int symbol = 0; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + for(i = 0; i < numLevels; i++) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + mi; + RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i)) + #else + int bit = RangeDecoderBitDecode(probs + mi, rd); + mi = mi + mi + bit; + symbol |= (bit << i); + #endif + } + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd) +{ + int symbol = 1; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + do + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + symbol; + RC_GET_BIT(prob, symbol) + #else + symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); + #endif + } + while (symbol < 0x100); + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte) +{ + int symbol = 1; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + do + { + int bit; + int matchBit = (matchByte >> 7) & 1; + matchByte <<= 1; + #ifdef _LZMA_LOC_OPT + { + CProb *prob = probs + 0x100 + (matchBit << 8) + symbol; + RC_GET_BIT2(prob, symbol, bit = 0, bit = 1) + } + #else + bit = RangeDecoderBitDecode(probs + 0x100 + (matchBit << 8) + symbol, rd); + symbol = (symbol << 1) | bit; + #endif + if (matchBit != bit) + { + while (symbol < 0x100) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + symbol; + RC_GET_BIT(prob, symbol) + #else + symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); + #endif + } + break; + } + } + while (symbol < 0x100); + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + +int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState) +{ + if(RangeDecoderBitDecode(p + LenChoice, rd) == 0) + return RangeDecoderBitTreeDecode(p + LenLow + + (posState << kLenNumLowBits), kLenNumLowBits, rd); + if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0) + return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid + + (posState << kLenNumMidBits), kLenNumMidBits, rd); + return kLenNumLowSymbols + kLenNumMidSymbols + + RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd); +} + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) +{ + unsigned char prop0; + if (size < LZMA_PROPERTIES_SIZE) + return LZMA_RESULT_DATA_ERROR; + prop0 = propsData[0]; + if (prop0 >= (9 * 5 * 5)) + return LZMA_RESULT_DATA_ERROR; + { + for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); + for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); + propsRes->lc = prop0; + /* + unsigned char remainder = (unsigned char)(prop0 / 9); + propsRes->lc = prop0 % 9; + propsRes->pb = remainder / 5; + propsRes->lp = remainder % 5; + */ + } + + #ifdef _LZMA_OUT_READ + { + int i; + propsRes->DictionarySize = 0; + for (i = 0; i < 4; i++) + propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); + if (propsRes->DictionarySize == 0) + propsRes->DictionarySize = 1; + } + #endif + return LZMA_RESULT_OK; +} + +#define kLzmaStreamWasFinishedId (-1) + +int LzmaDecode(CLzmaDecoderState *vs, + #ifdef _LZMA_IN_CB + ILzmaInCallback *InCallback, + #else + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + #endif + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) +{ + CProb *p = vs->Probs; + SizeT nowPos = 0; + Byte previousByte = 0; + UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; + UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; + int lc = vs->Properties.lc; + CRangeDecoder rd; + + #ifdef _LZMA_OUT_READ + + int state = vs->State; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + UInt32 distanceLimit = vs->DistanceLimit; + + Byte *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->Properties.DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + Byte tempDictionary[4]; + + rd.Range = vs->Range; + rd.Code = vs->Code; + #ifdef _LZMA_IN_CB + rd.InCallback = InCallback; + rd.Buffer = vs->Buffer; + rd.BufferLim = vs->BufferLim; + #else + rd.Buffer = inStream; + rd.BufferLim = inStream + inSize; + #endif + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + if (len == kLzmaStreamWasFinishedId) + return LZMA_RESULT_OK; + + if (dictionarySize == 0) + { + dictionary = tempDictionary; + dictionarySize = 1; + tempDictionary[0] = vs->TempDictionary[0]; + } + + if (len == kLzmaNeedInitId) + { + { + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + UInt32 i; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + rep0 = rep1 = rep2 = rep3 = 1; + state = 0; + globalPos = 0; + distanceLimit = 0; + dictionaryPos = 0; + dictionary[dictionarySize - 1] = 0; + RangeDecoderInit(&rd + #ifndef _LZMA_IN_CB + , inStream, inSize + #endif + ); + #ifdef _LZMA_IN_CB + if (rd.Result != LZMA_RESULT_OK) + return rd.Result; + #endif + if (rd.ExtraBytes != 0) + return LZMA_RESULT_DATA_ERROR; + } + len = 0; + } + while(len != 0 && nowPos < outSize) + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; + + #ifdef _LZMA_IN_CB + rd.Result = LZMA_RESULT_OK; + #endif + rd.ExtraBytes = 0; + + #else /* if !_LZMA_OUT_READ */ + + int state = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + int len = 0; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + + { + UInt32 i; + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + } + + #ifdef _LZMA_IN_CB + rd.InCallback = InCallback; + #endif + RangeDecoderInit(&rd + #ifndef _LZMA_IN_CB + , inStream, inSize + #endif + ); + + #ifdef _LZMA_IN_CB + if (rd.Result != LZMA_RESULT_OK) + return rd.Result; + #endif + if (rd.ExtraBytes != 0) + return LZMA_RESULT_DATA_ERROR; + + #endif /* _LZMA_OUT_READ */ + + + while(nowPos < outSize) + { + int posState = (int)( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & posStateMask); + #ifdef _LZMA_IN_CB + if (rd.Result != LZMA_RESULT_OK) + return rd.Result; + #endif + if (rd.ExtraBytes != 0) + return LZMA_RESULT_DATA_ERROR; + if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0) + { + CProb *probs = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + Byte matchByte; + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + #else + matchByte = outStream[nowPos - rep0]; + #endif + previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte); + } + else + previousByte = LzmaLiteralDecode(probs, &rd); + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #endif + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + } + else + { + if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1) + { + if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0) + { + if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0) + { + #ifdef _LZMA_OUT_READ + UInt32 pos; + #endif + + #ifdef _LZMA_OUT_READ + if (distanceLimit == 0) + #else + if (nowPos == 0) + #endif + return LZMA_RESULT_DATA_ERROR; + + state = state < 7 ? 9 : 11; + #ifdef _LZMA_OUT_READ + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + #endif + continue; + } + } + else + { + UInt32 distance; + if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0) + distance = rep1; + else + { + if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = LzmaLenDecode(p + RepLenCoder, &rd, posState); + state = state < 7 ? 8 : 11; + } + else + { + int posSlot; + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < 7 ? 7 : 10; + len = LzmaLenDecode(p + LenCoder, &rd, posState); + posSlot = RangeDecoderBitTreeDecode(p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits), kNumPosSlotBits, &rd); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits); + if (posSlot < kEndPosModelIndex) + { + rep0 += RangeDecoderReverseBitTreeDecode( + p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd); + } + else + { + rep0 += RangeDecoderDecodeDirectBits(&rd, + numDirectBits - kNumAlignBits) << kNumAlignBits; + rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd); + } + } + else + rep0 = posSlot; + if (++rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = kLzmaStreamWasFinishedId; + break; + } + } + + len += kMatchMinLen; + #ifdef _LZMA_OUT_READ + if (rep0 > distanceLimit) + #else + if (rep0 > nowPos) + #endif + return LZMA_RESULT_DATA_ERROR; + + #ifdef _LZMA_OUT_READ + if (dictionarySize - distanceLimit > (UInt32)len) + distanceLimit += len; + else + distanceLimit = dictionarySize; + #endif + + do + { + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + + + #ifdef _LZMA_OUT_READ + vs->Range = rd.Range; + vs->Code = rd.Code; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = globalPos + (UInt32)nowPos; + vs->DistanceLimit = distanceLimit; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->RemainLen = len; + vs->TempDictionary[0] = tempDictionary[0]; + #endif + + #ifdef _LZMA_IN_CB + vs->Buffer = rd.Buffer; + vs->BufferLim = rd.BufferLim; + #else + *inSizeProcessed = (SizeT)(rd.Buffer - inStream); + #endif + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/cfe/cfe/lzma/LzmaStateDecode.c b/cfe/cfe/lzma/LzmaStateDecode.c new file mode 100755 index 0000000..e50f88b --- /dev/null +++ b/cfe/cfe/lzma/LzmaStateDecode.c @@ -0,0 +1,521 @@ +/* + LzmaStateDecode.c + LZMA Decoder (State version) + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this Code, expressly permits you to + statically or dynamically link your Code (or bind by name) to the + interfaces of this file without subjecting your linked Code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "LzmaStateDecode.h" + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*Buffer++) + +#define RC_INIT Code = 0; Range = 0xFFFFFFFF; \ + { int i; for(i = 0; i < 5; i++) { Code = (Code << 8) | RC_READ_BYTE; }} + +#define RC_NORMALIZE if (Range < kTopValue) { Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } + +#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) +#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; +#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; + +#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ + { UpdateBit0(p); mi <<= 1; A0; } else \ + { UpdateBit1(p); mi = (mi + mi) + 1; A1; } + +#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) + +#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ + { int i = numLevels; res = 1; \ + do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ + res -= (1 << numLevels); } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +/* kRequiredInBufferSize = number of required input bytes for worst case: + longest match with longest distance. + kLzmaInBufferSize must be larger than kRequiredInBufferSize + 23 bits = 2 (match select) + 10 (len) + 6 (distance) + 4(align) + 1 (RC_NORMALIZE) +*/ + +#define kRequiredInBufferSize ((23 * (kNumBitModelTotalBits - kNumMoveBits + 1) + 26 + 9) / 8) + +#define kLzmaStreamWasFinishedId (-1) + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) +{ + unsigned char prop0; + if (size < LZMA_PROPERTIES_SIZE) + return LZMA_RESULT_DATA_ERROR; + prop0 = propsData[0]; + if (prop0 >= (9 * 5 * 5)) + return LZMA_RESULT_DATA_ERROR; + { + for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); + for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); + propsRes->lc = prop0; + /* + unsigned char remainder = (unsigned char)(prop0 / 9); + propsRes->lc = prop0 % 9; + propsRes->pb = remainder / 5; + propsRes->lp = remainder % 5; + */ + } + + { + int i; + propsRes->DictionarySize = 0; + for (i = 0; i < 4; i++) + propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); + if (propsRes->DictionarySize == 0) + propsRes->DictionarySize = 1; + return LZMA_RESULT_OK; + } +} + +int LzmaDecode( + CLzmaDecoderState *vs, + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed, + int finishDecoding) +{ + UInt32 Range = vs->Range; + UInt32 Code = vs->Code; + + unsigned char *Buffer = vs->Buffer; + int BufferSize = vs->BufferSize; /* don't change it to unsigned int */ + CProb *p = vs->Probs; + + int state = vs->State; + unsigned char previousByte; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + SizeT nowPos = 0; + UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; + UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; + int lc = vs->Properties.lc; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + UInt32 distanceLimit = vs->DistanceLimit; + + unsigned char *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->Properties.DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + unsigned char tempDictionary[4]; + + (*inSizeProcessed) = 0; + (*outSizeProcessed) = 0; + if (len == kLzmaStreamWasFinishedId) + return LZMA_RESULT_OK; + + if (dictionarySize == 0) + { + dictionary = tempDictionary; + dictionarySize = 1; + tempDictionary[0] = vs->TempDictionary[0]; + } + + if (len == kLzmaNeedInitId) + { + while (inSize > 0 && BufferSize < kLzmaInBufferSize) + { + Buffer[BufferSize++] = *inStream++; + (*inSizeProcessed)++; + inSize--; + } + if (BufferSize < 5) + { + vs->BufferSize = BufferSize; + return finishDecoding ? LZMA_RESULT_DATA_ERROR : LZMA_RESULT_OK; + } + { + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + UInt32 i; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + rep0 = rep1 = rep2 = rep3 = 1; + state = 0; + globalPos = 0; + distanceLimit = 0; + dictionaryPos = 0; + dictionary[dictionarySize - 1] = 0; + RC_INIT; + } + len = 0; + } + while(len != 0 && nowPos < outSize) + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; + + while(1) + { + int bufferPos = (int)(Buffer - vs->Buffer); + if (BufferSize - bufferPos < kRequiredInBufferSize) + { + int i; + BufferSize -= bufferPos; + if (BufferSize < 0) + return LZMA_RESULT_DATA_ERROR; + for (i = 0; i < BufferSize; i++) + vs->Buffer[i] = Buffer[i]; + Buffer = vs->Buffer; + while (inSize > 0 && BufferSize < kLzmaInBufferSize) + { + Buffer[BufferSize++] = *inStream++; + (*inSizeProcessed)++; + inSize--; + } + if (BufferSize < kRequiredInBufferSize && !finishDecoding) + break; + } + if (nowPos >= outSize) + break; + { + CProb *prob; + UInt32 bound; + int posState = (int)((nowPos + globalPos) & posStateMask); + + prob = p + IsMatch + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + int symbol = 1; + UpdateBit0(prob) + prob = p + Literal + (LZMA_LIT_SIZE * + ((((nowPos + globalPos)& literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + int matchByte; + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + do + { + int bit; + CProb *probLit; + matchByte <<= 1; + bit = (matchByte & 0x100); + probLit = prob + 0x100 + bit + symbol; + RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) + } + while (symbol < 0x100); + } + while (symbol < 0x100) + { + CProb *probLit = prob + symbol; + RC_GET_BIT(probLit, symbol) + } + previousByte = (unsigned char)symbol; + + outStream[nowPos++] = previousByte; + if (distanceLimit < dictionarySize) + distanceLimit++; + + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + } + else + { + UpdateBit1(prob); + prob = p + IsRep + state; + IfBit0(prob) + { + UpdateBit0(prob); + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < kNumLitStates ? 0 : 3; + prob = p + LenCoder; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG0 + state; + IfBit0(prob) + { + UpdateBit0(prob); + prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + UInt32 pos; + UpdateBit0(prob); + if (distanceLimit == 0) + return LZMA_RESULT_DATA_ERROR; + if (distanceLimit < dictionarySize) + distanceLimit++; + state = state < kNumLitStates ? 9 : 11; + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + outStream[nowPos++] = previousByte; + continue; + } + else + { + UpdateBit1(prob); + } + } + else + { + UInt32 distance; + UpdateBit1(prob); + prob = p + IsRepG1 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep1; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG2 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep2; + } + else + { + UpdateBit1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = p + RepLenCoder; + } + { + int numBits, offset; + CProb *probLen = prob + LenChoice; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + numBits = kLenNumLowBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenChoice2; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + numBits = kLenNumMidBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + numBits = kLenNumHighBits; + } + } + RangeDecoderBitTreeDecode(probLen, numBits, len); + len += offset; + } + + if (state < 4) + { + int posSlot; + state += kNumLitStates; + prob = p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = (2 | ((UInt32)posSlot & 1)); + if (posSlot < kEndPosModelIndex) + { + rep0 <<= numDirectBits; + prob = p + SpecPos + rep0 - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + RC_NORMALIZE + Range >>= 1; + rep0 <<= 1; + if (Code >= Range) + { + Code -= Range; + rep0 |= 1; + } + } + while (--numDirectBits != 0); + prob = p + Align; + rep0 <<= kNumAlignBits; + numDirectBits = kNumAlignBits; + } + { + int i = 1; + int mi = 1; + do + { + CProb *prob3 = prob + mi; + RC_GET_BIT2(prob3, mi, ; , rep0 |= i); + i <<= 1; + } + while(--numDirectBits != 0); + } + } + else + rep0 = posSlot; + if (++rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = kLzmaStreamWasFinishedId; + break; + } + } + + len += kMatchMinLen; + if (rep0 > distanceLimit) + return LZMA_RESULT_DATA_ERROR; + if (dictionarySize - distanceLimit > (UInt32)len) + distanceLimit += len; + else + distanceLimit = dictionarySize; + + do + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + } + RC_NORMALIZE; + + BufferSize -= (int)(Buffer - vs->Buffer); + if (BufferSize < 0) + return LZMA_RESULT_DATA_ERROR; + { + int i; + for (i = 0; i < BufferSize; i++) + vs->Buffer[i] = Buffer[i]; + } + vs->BufferSize = BufferSize; + vs->Range = Range; + vs->Code = Code; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = (UInt32)(globalPos + nowPos); + vs->DistanceLimit = distanceLimit; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->RemainLen = len; + vs->TempDictionary[0] = tempDictionary[0]; + + (*outSizeProcessed) = nowPos; + return LZMA_RESULT_OK; +} diff --git a/cfe/cfe/lzma/LzmaStateDecode.h b/cfe/cfe/lzma/LzmaStateDecode.h new file mode 100755 index 0000000..26490d6 --- /dev/null +++ b/cfe/cfe/lzma/LzmaStateDecode.h @@ -0,0 +1,96 @@ +/* + LzmaStateDecode.h + LZMA Decoder interface (State version) + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#ifndef __LZMASTATEDECODE_H +#define __LZMASTATEDECODE_H + +#include "LzmaTypes.h" + +/* #define _LZMA_PROB32 */ +/* It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb UInt16 +#endif + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +typedef struct _CLzmaProperties +{ + int lc; + int lp; + int pb; + UInt32 DictionarySize; +}CLzmaProperties; + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); + +#define LzmaGetNumProbs(lzmaProps) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((lzmaProps)->lc + (lzmaProps)->lp))) + +#define kLzmaInBufferSize 64 /* don't change it. it must be larger than kRequiredInBufferSize */ + +#define kLzmaNeedInitId (-2) + +typedef struct _CLzmaDecoderState +{ + CLzmaProperties Properties; + CProb *Probs; + unsigned char *Dictionary; + + unsigned char Buffer[kLzmaInBufferSize]; + int BufferSize; + + UInt32 Range; + UInt32 Code; + UInt32 DictionaryPos; + UInt32 GlobalPos; + UInt32 DistanceLimit; + UInt32 Reps[4]; + int State; + int RemainLen; /* -2: decoder needs internal initialization + -1: stream was finished, + 0: ok + > 0: need to write RemainLen bytes as match Reps[0], + */ + unsigned char TempDictionary[4]; /* it's required when DictionarySize = 0 */ +} CLzmaDecoderState; + +#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; (vs)->BufferSize = 0; } + +/* LzmaDecode: decoding from input stream to output stream. + If finishDecoding != 0, then there are no more bytes in input stream + after inStream[inSize - 1]. */ + +int LzmaDecode(CLzmaDecoderState *vs, + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed, + int finishDecoding); + +#endif diff --git a/cfe/cfe/lzma/LzmaStateTest.c b/cfe/cfe/lzma/LzmaStateTest.c new file mode 100755 index 0000000..5df4e43 --- /dev/null +++ b/cfe/cfe/lzma/LzmaStateTest.c @@ -0,0 +1,195 @@ +/* +LzmaStateTest.c +Test application for LZMA Decoder (State version) + +This file written and distributed to public domain by Igor Pavlov. +This file is part of LZMA SDK 4.26 (2005-08-02) +*/ + +#include +#include +#include + +#include "LzmaStateDecode.h" + +const char *kCantReadMessage = "Can not read input file"; +const char *kCantWriteMessage = "Can not write output file"; +const char *kCantAllocateMessage = "Can not allocate memory"; + +#define kInBufferSize (1 << 15) +#define kOutBufferSize (1 << 15) + +unsigned char g_InBuffer[kInBufferSize]; +unsigned char g_OutBuffer[kOutBufferSize]; + +size_t MyReadFile(FILE *file, void *data, size_t size) + { return fread(data, 1, size, file); } + +int MyReadFileAndCheck(FILE *file, void *data, size_t size) + { return (MyReadFile(file, data, size) == size); } + +int PrintError(char *buffer, const char *message) +{ + sprintf(buffer + strlen(buffer), "\nError: "); + sprintf(buffer + strlen(buffer), message); + return 1; +} + +int main3(FILE *inFile, FILE *outFile, char *rs) +{ + /* We use two 32-bit integers to construct 64-bit integer for file size. + You can remove outSizeHigh, if you don't need >= 4GB supporting, + or you can use UInt64 outSize, if your compiler supports 64-bit integers*/ + UInt32 outSize = 0; + UInt32 outSizeHigh = 0; + + int waitEOS = 1; + /* waitEOS = 1, if there is no uncompressed size in headers, + so decoder will wait EOS (End of Stream Marker) in compressed stream */ + + int i; + int res = 0; + CLzmaDecoderState state; /* it's about 140 bytes structure, if int is 32-bit */ + unsigned char properties[LZMA_PROPERTIES_SIZE]; + SizeT inAvail = 0; + unsigned char *inBuffer = 0; + + if (sizeof(UInt32) < 4) + return PrintError(rs, "LZMA decoder needs correct UInt32"); + + /* Read LZMA properties for compressed stream */ + + if (!MyReadFileAndCheck(inFile, properties, sizeof(properties))) + return PrintError(rs, kCantReadMessage); + + /* Read uncompressed size */ + + for (i = 0; i < 8; i++) + { + unsigned char b; + if (!MyReadFileAndCheck(inFile, &b, 1)) + return PrintError(rs, kCantReadMessage); + if (b != 0xFF) + waitEOS = 0; + if (i < 4) + outSize += (UInt32)(b) << (i * 8); + else + outSizeHigh += (UInt32)(b) << ((i - 4) * 8); + } + + /* Decode LZMA properties and allocate memory */ + + if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) + return PrintError(rs, "Incorrect stream properties"); + state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); + if (state.Probs == 0) + return PrintError(rs, kCantAllocateMessage); + + if (state.Properties.DictionarySize == 0) + state.Dictionary = 0; + else + { + state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); + if (state.Dictionary == 0) + { + free(state.Probs); + return PrintError(rs, kCantAllocateMessage); + } + } + + /* Decompress */ + + LzmaDecoderInit(&state); + + do + { + SizeT inProcessed, outProcessed; + int finishDecoding; + UInt32 outAvail = kOutBufferSize; + if (!waitEOS && outSizeHigh == 0 && outAvail > outSize) + outAvail = outSize; + if (inAvail == 0) + { + inAvail = (SizeT)MyReadFile(inFile, g_InBuffer, kInBufferSize); + inBuffer = g_InBuffer; + } + finishDecoding = (inAvail == 0); + res = LzmaDecode(&state, + inBuffer, inAvail, &inProcessed, + g_OutBuffer, outAvail, &outProcessed, + finishDecoding); + if (res != 0) + { + sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res); + res = 1; + break; + } + inAvail -= inProcessed; + inBuffer += inProcessed; + + if (outFile != 0) + if (fwrite(g_OutBuffer, 1, outProcessed, outFile) != outProcessed) + { + PrintError(rs, kCantWriteMessage); + res = 1; + break; + } + + if (outSize < outProcessed) + outSizeHigh--; + outSize -= (UInt32)outProcessed; + outSize &= 0xFFFFFFFF; + + if (outProcessed == 0 && finishDecoding) + { + if (!waitEOS && (outSize != 0 || outSizeHigh != 0)) + res = 1; + break; + } + } + while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0 || waitEOS); + + free(state.Dictionary); + free(state.Probs); + return res; +} + +int main2(int numArgs, const char *args[], char *rs) +{ + FILE *inFile = 0; + FILE *outFile = 0; + int res; + + sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov 2005-08-02\n"); + if (numArgs < 2 || numArgs > 3) + { + sprintf(rs + strlen(rs), "\nUsage: lzmadec file.lzma [outFile]\n"); + return 1; + } + + inFile = fopen(args[1], "rb"); + if (inFile == 0) + return PrintError(rs, "Can not open input file"); + + if (numArgs > 2) + { + outFile = fopen(args[2], "wb+"); + if (outFile == 0) + return PrintError(rs, "Can not open output file"); + } + + res = main3(inFile, outFile, rs); + + if (outFile != 0) + fclose(outFile); + fclose(inFile); + return res; +} + +int main(int numArgs, const char *args[]) +{ + char rs[800] = { 0 }; + int res = main2(numArgs, args, rs); + printf(rs); + return res; +} diff --git a/cfe/cfe/lzma/LzmaTest.c b/cfe/cfe/lzma/LzmaTest.c new file mode 100755 index 0000000..f95a753 --- /dev/null +++ b/cfe/cfe/lzma/LzmaTest.c @@ -0,0 +1,342 @@ +/* +LzmaTest.c +Test application for LZMA Decoder + +This file written and distributed to public domain by Igor Pavlov. +This file is part of LZMA SDK 4.26 (2005-08-05) +*/ + +#include +#include +#include + +#include "LzmaDecode.h" + +const char *kCantReadMessage = "Can not read input file"; +const char *kCantWriteMessage = "Can not write output file"; +const char *kCantAllocateMessage = "Can not allocate memory"; + +size_t MyReadFile(FILE *file, void *data, size_t size) +{ + if (size == 0) + return 0; + return fread(data, 1, size, file); +} + +int MyReadFileAndCheck(FILE *file, void *data, size_t size) + { return (MyReadFile(file, data, size) == size);} + +size_t MyWriteFile(FILE *file, const void *data, size_t size) +{ + if (size == 0) + return 0; + return fwrite(data, 1, size, file); +} + +int MyWriteFileAndCheck(FILE *file, const void *data, size_t size) + { return (MyWriteFile(file, data, size) == size); } + +#ifdef _LZMA_IN_CB +#define kInBufferSize (1 << 15) +typedef struct _CBuffer +{ + ILzmaInCallback InCallback; + FILE *File; + unsigned char Buffer[kInBufferSize]; +} CBuffer; + +int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size) +{ + CBuffer *b = (CBuffer *)object; + *buffer = b->Buffer; + *size = (SizeT)MyReadFile(b->File, b->Buffer, kInBufferSize); + return LZMA_RESULT_OK; +} +CBuffer g_InBuffer; + +#endif + +#ifdef _LZMA_OUT_READ +#define kOutBufferSize (1 << 15) +unsigned char g_OutBuffer[kOutBufferSize]; +#endif + +int PrintError(char *buffer, const char *message) +{ + sprintf(buffer + strlen(buffer), "\nError: "); + sprintf(buffer + strlen(buffer), message); + return 1; +} + +int main3(FILE *inFile, FILE *outFile, char *rs) +{ + /* We use two 32-bit integers to construct 64-bit integer for file size. + You can remove outSizeHigh, if you don't need >= 4GB supporting, + or you can use UInt64 outSize, if your compiler supports 64-bit integers*/ + UInt32 outSize = 0; + UInt32 outSizeHigh = 0; + #ifndef _LZMA_OUT_READ + SizeT outSizeFull; + unsigned char *outStream; + #endif + + int waitEOS = 1; + /* waitEOS = 1, if there is no uncompressed size in headers, + so decoder will wait EOS (End of Stream Marker) in compressed stream */ + + #ifndef _LZMA_IN_CB + SizeT compressedSize; + unsigned char *inStream; + #endif + + CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */ + unsigned char properties[LZMA_PROPERTIES_SIZE]; + + int res; + + #ifdef _LZMA_IN_CB + g_InBuffer.File = inFile; + #endif + + if (sizeof(UInt32) < 4) + return PrintError(rs, "LZMA decoder needs correct UInt32"); + + #ifndef _LZMA_IN_CB + { + long length; + fseek(inFile, 0, SEEK_END); + length = ftell(inFile); + fseek(inFile, 0, SEEK_SET); + if ((long)(SizeT)length != length) + return PrintError(rs, "Too big compressed stream"); + compressedSize = (SizeT)(length - (LZMA_PROPERTIES_SIZE + 8)); + } + #endif + + /* Read LZMA properties for compressed stream */ + + if (!MyReadFileAndCheck(inFile, properties, sizeof(properties))) + return PrintError(rs, kCantReadMessage); + + /* Read uncompressed size */ + + { + int i; + for (i = 0; i < 8; i++) + { + unsigned char b; + if (!MyReadFileAndCheck(inFile, &b, 1)) + return PrintError(rs, kCantReadMessage); + if (b != 0xFF) + waitEOS = 0; + if (i < 4) + outSize += (UInt32)(b) << (i * 8); + else + outSizeHigh += (UInt32)(b) << ((i - 4) * 8); + } + + #ifndef _LZMA_OUT_READ + if (waitEOS) + return PrintError(rs, "Stream with EOS marker is not supported"); + outSizeFull = (SizeT)outSize; + if (sizeof(SizeT) >= 8) + outSizeFull |= (((SizeT)outSizeHigh << 16) << 16); + else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) + return PrintError(rs, "Too big uncompressed stream"); + #endif + } + + /* Decode LZMA properties and allocate memory */ + + if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) + return PrintError(rs, "Incorrect stream properties"); + state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); + + #ifdef _LZMA_OUT_READ + if (state.Properties.DictionarySize == 0) + state.Dictionary = 0; + else + state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); + #else + if (outSizeFull == 0) + outStream = 0; + else + outStream = (unsigned char *)malloc(outSizeFull); + #endif + + #ifndef _LZMA_IN_CB + if (compressedSize == 0) + inStream = 0; + else + inStream = (unsigned char *)malloc(compressedSize); + #endif + + if (state.Probs == 0 + #ifdef _LZMA_OUT_READ + || (state.Dictionary == 0 && state.Properties.DictionarySize != 0) + #else + || (outStream == 0 && outSizeFull != 0) + #endif + #ifndef _LZMA_IN_CB + || (inStream == 0 && compressedSize != 0) + #endif + ) + { + free(state.Probs); + #ifdef _LZMA_OUT_READ + free(state.Dictionary); + #else + free(outStream); + #endif + #ifndef _LZMA_IN_CB + free(inStream); + #endif + return PrintError(rs, kCantAllocateMessage); + } + + /* Decompress */ + + #ifdef _LZMA_IN_CB + g_InBuffer.InCallback.Read = LzmaReadCompressed; + #else + if (!MyReadFileAndCheck(inFile, inStream, compressedSize)) + return PrintError(rs, kCantReadMessage); + #endif + + #ifdef _LZMA_OUT_READ + { + #ifndef _LZMA_IN_CB + SizeT inAvail = compressedSize; + const unsigned char *inBuffer = inStream; + #endif + LzmaDecoderInit(&state); + do + { + #ifndef _LZMA_IN_CB + SizeT inProcessed; + #endif + SizeT outProcessed; + SizeT outAvail = kOutBufferSize; + if (!waitEOS && outSizeHigh == 0 && outAvail > outSize) + outAvail = (SizeT)outSize; + res = LzmaDecode(&state, + #ifdef _LZMA_IN_CB + &g_InBuffer.InCallback, + #else + inBuffer, inAvail, &inProcessed, + #endif + g_OutBuffer, outAvail, &outProcessed); + if (res != 0) + { + sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res); + res = 1; + break; + } + #ifndef _LZMA_IN_CB + inAvail -= inProcessed; + inBuffer += inProcessed; + #endif + + if (outFile != 0) + if (!MyWriteFileAndCheck(outFile, g_OutBuffer, (size_t)outProcessed)) + { + PrintError(rs, kCantWriteMessage); + res = 1; + break; + } + + if (outSize < outProcessed) + outSizeHigh--; + outSize -= (UInt32)outProcessed; + outSize &= 0xFFFFFFFF; + + if (outProcessed == 0) + { + if (!waitEOS && (outSize != 0 || outSizeHigh != 0)) + res = 1; + break; + } + } + while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0 || waitEOS); + } + + #else + { + #ifndef _LZMA_IN_CB + SizeT inProcessed; + #endif + SizeT outProcessed; + res = LzmaDecode(&state, + #ifdef _LZMA_IN_CB + &g_InBuffer.InCallback, + #else + inStream, compressedSize, &inProcessed, + #endif + outStream, outSizeFull, &outProcessed); + if (res != 0) + { + sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res); + res = 1; + } + else if (outFile != 0) + { + if (!MyWriteFileAndCheck(outFile, outStream, (size_t)outProcessed)) + { + PrintError(rs, kCantWriteMessage); + res = 1; + } + } + } + #endif + + free(state.Probs); + #ifdef _LZMA_OUT_READ + free(state.Dictionary); + #else + free(outStream); + #endif + #ifndef _LZMA_IN_CB + free(inStream); + #endif + return res; +} + +int main2(int numArgs, const char *args[], char *rs) +{ + FILE *inFile = 0; + FILE *outFile = 0; + int res; + + sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov 2005-08-05\n"); + if (numArgs < 2 || numArgs > 3) + { + sprintf(rs + strlen(rs), "\nUsage: lzmadec file.lzma [outFile]\n"); + return 1; + } + + inFile = fopen(args[1], "rb"); + if (inFile == 0) + return PrintError(rs, "Can not open input file"); + + if (numArgs > 2) + { + outFile = fopen(args[2], "wb+"); + if (outFile == 0) + return PrintError(rs, "Can not open output file"); + } + + res = main3(inFile, outFile, rs); + + if (outFile != 0) + fclose(outFile); + fclose(inFile); + return res; +} + +int main(int numArgs, const char *args[]) +{ + char rs[800] = { 0 }; + int res = main2(numArgs, args, rs); + printf(rs); + return res; +} diff --git a/cfe/cfe/lzma/LzmaTypes.h b/cfe/cfe/lzma/LzmaTypes.h new file mode 100755 index 0000000..288c5e4 --- /dev/null +++ b/cfe/cfe/lzma/LzmaTypes.h @@ -0,0 +1,45 @@ +/* +LzmaTypes.h + +Types for LZMA Decoder + +This file written and distributed to public domain by Igor Pavlov. +This file is part of LZMA SDK 4.40 (2006-05-01) +*/ + +#ifndef __LZMATYPES_H +#define __LZMATYPES_H + +#ifndef _7ZIP_BYTE_DEFINED +#define _7ZIP_BYTE_DEFINED +typedef unsigned char Byte; +#endif + +#ifndef _7ZIP_UINT16_DEFINED +#define _7ZIP_UINT16_DEFINED +typedef unsigned short UInt16; +#endif + +#ifndef _7ZIP_UINT32_DEFINED +#define _7ZIP_UINT32_DEFINED +#ifdef _LZMA_UINT32_IS_ULONG +typedef unsigned long UInt32; +#else +typedef unsigned int UInt32; +#endif +#endif + +/* #define _LZMA_SYSTEM_SIZE_T */ +/* Use system's size_t. You can use it to enable 64-bit sizes supporting */ + +#ifndef _7ZIP_SIZET_DEFINED +#define _7ZIP_SIZET_DEFINED +#ifdef _LZMA_SYSTEM_SIZE_T +#include +typedef size_t SizeT; +#else +typedef UInt32 SizeT; +#endif +#endif + +#endif diff --git a/cfe/cfe/lzma/Makefile b/cfe/cfe/lzma/Makefile new file mode 100755 index 0000000..3611459 --- /dev/null +++ b/cfe/cfe/lzma/Makefile @@ -0,0 +1,5 @@ + +BSPOBJS += \ + dcapi.o \ + LzmaDecode.o + diff --git a/cfe/cfe/lzma/dcapi.c b/cfe/cfe/lzma/dcapi.c new file mode 100755 index 0000000..b8f59b0 --- /dev/null +++ b/cfe/cfe/lzma/dcapi.c @@ -0,0 +1,50 @@ +#include "LzmaDecode.h" +#include "bcm63xx_util.h" +#include "lib_malloc.h" + +#define LZMA_ORIGSIZE_SIZE 8 + +int decompressLZMA(unsigned char *in, unsigned insize, unsigned char *out, unsigned outsize); + +// Call ANSI C LZMA decoder to decompress a LZMA block +int decompressLZMA(unsigned char *in, unsigned insize, unsigned char *out, unsigned outsize) +{ + + SizeT inProcessed, outProcessed; + unsigned origsize; + int ret; + CLzmaDecoderState state; + + ret = LzmaDecodeProperties(&state.Properties, in, LZMA_PROPERTIES_SIZE); + if (ret != LZMA_RESULT_OK) { + return ret; + } + in += LZMA_PROPERTIES_SIZE; + + state.Probs = (CProb *)KMALLOC(LzmaGetNumProbs(&state.Properties) * sizeof(CProb), 0); + if (!state.Probs) { + return 1001; + } + + if (in[4]==0 && in[5]==0 && in[6]==0 && in[7]==0) { // uncompressed size < 4GB (should be) + origsize = in[0] | (in[1] << 8) | (in[2] << 16) | (in[3] << 24); + in += LZMA_ORIGSIZE_SIZE; + if (origsize <= outsize) { + ret = LzmaDecode(&state, in, insize, &inProcessed, out, origsize, &outProcessed); + } + else { + // output buffer too small + ret = 1000; + } + } + else { // uncompressed size > 4GB, old lzma format or corrupted image, assume old format here + printf("LZMA: Prossible old LZMA format, trying to decompress..\n"); + LzmaDecode(&state, in, insize, &inProcessed, out, outsize, &outProcessed); + ret = 0; // It would return an error code as the output buffer size doesn't match. We need to ignore the code. + } + + KFREE(state.Probs); + + return ret; +} + diff --git a/cfe/cfe/main/cfe.mk b/cfe/cfe/main/cfe.mk new file mode 100644 index 0000000..05b16b6 --- /dev/null +++ b/cfe/cfe/main/cfe.mk @@ -0,0 +1,301 @@ + +# +# CFE's version number +# + +include ${TOP}/main/cfe_version.mk + +# +# Default values for certain parameters +# + +CFG_MLONG64 ?= 0 +CFG_LITTLE ?= 0 +CFG_RELOC ?= 0 +CFG_UNCACHED ?= 0 +CFG_NEWRELOC ?= 0 +CFG_BOOTRAM ?= 0 +CFG_VGACONSOLE ?= 0 +CFG_PCI ?= 1 +CFG_LDT_REV_017 ?= 0 +CFG_ZLIB ?= 0 +CFG_BIENDIAN ?= 0 +CFG_DOWNLOAD ?= 0 +CFG_RAMAPP ?= 0 +CFG_USB ?= 0 + +# +# Paths to other parts of the firmware. Everything's relative to ${TOP} +# so that you can actually do a build anywhere you want. +# + +ARCH_TOP = ${TOP}/arch/${ARCH} +ARCH_SRC = ${ARCH_TOP}/common/src +ARCH_INC = ${ARCH_TOP}/common/include +CPU_SRC = ${ARCH_TOP}/cpu/${CPU}/src +CPU_INC = ${ARCH_TOP}/cpu/${CPU}/include + +# +# It's actually optional to have a 'board' +# directory. If you don't specify BOARD, +# don't include the files. +# + +ifneq ("$(strip ${BOARD})","") +BOARD_SRC = ${ARCH_TOP}/board/${BOARD}/src +BOARD_INC = ${ARCH_TOP}/board/${BOARD}/include +endif + +# +# Preprocessor defines for CFE's version number +# + +VDEF = -DCFE_VER_MAJ=${CFE_VER_MAJ} -DCFE_VER_MIN=${CFE_VER_MIN} -DCFE_VER_ECO=${CFE_VER_ECO} + +# +# Construct the list of paths that will eventually become the include +# paths and VPATH +# + +SRCDIRS = ${ARCH_SRC} ${CPU_SRC} ${BOARD_SRC} ${TOP}/main ${TOP}/vendor ${TOP}/include ${TOP}/net ${TOP}/dev ${TOP}/pci ${TOP}/ui ${TOP}/lib ${TOP}/common ${TOP}/verif + +CFE_INC = ${TOP}/include ${TOP}/pci ${TOP}/net + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +SRCDIRS += ${TOP}/x86emu ${TOP}/pccons +CFE_INC += ${TOP}/x86emu ${TOP}/pccons +endif + +ifeq ($(strip ${CFG_VAPI}),1) +SRCDIRS += ${TOP}/verif +CFE_INC += ${TOP}/verif +endif + +ifeq ($(strip ${CFG_ZLIB}),1) +SRCDIRS += ${TOP}/zlib +CFE_INC += ${TOP}/zlib +endif + + +INCDIRS = $(patsubst %,-I%,$(subst :, ,$(ARCH_INC) $(CPU_INC) $(BOARD_INC) $(CFE_INC))) + +VPATH = $(SRCDIRS) + +# +# Bi-endian support: If we're building the little-endian +# version, use a different linker script so we can locate the +# ROM at a higher address. You'd think we could do this with +# normal linker command line switches, but there appears to be no +# command-line way to override the 'AT' qualifier in the linker script. +# + +CFG_TEXTAT1MB=0 +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),1) + CFG_TEXTAT1MB=1 + endif +endif + + +# +# Configure tools and basic tools flags. This include sets up +# macros for calling the C compiler, basic flags, +# and linker scripts. +# + +include ${ARCH_SRC}/tools.mk + +# +# Add some common flags that are used on any architecture. +# + +CFLAGS += -I. $(INCDIRS) +CFLAGS += -D_CFE_ ${VDEF} -DCFG_BOARDNAME=\"${CFG_BOARDNAME}\" + +# +# Gross - allow more options to be supplied from command line +# + +ifdef CFG_OPTIONS +OPTFLAGS = $(patsubst %,-D%,$(subst :, ,$(CFG_OPTIONS))) +CFLAGS += ${OPTFLAGS} +endif + + +# +# This is the makefile's main target. Note that we actually +# do most of the work in 'ALL' not 'all', since we include +# other makefiles after this point. +# + +all : build_date.c makereg pcidevs_data2.h ALL + +# +# Macros that expand to the list of arch-independent files +# + +DEVOBJS = dev_flash.o dev_newflash.o dev_null.o dev_promice.o \ + dev_ide_common.o dev_ns16550.o dev_ds17887clock.o +LIBOBJS = lib_malloc.o lib_printf.o lib_queue.o lib_string.o lib_string2.o \ + lib_arena.o lib_misc.o lib_setjmp.o lib_qsort.o lib_hssubr.o lib_physio.o +NETOBJS = net_ether.o net_arp.o net_ip.o net_udp.o net_api.o net_dns.o \ + net_dhcp.o net_tftp.o net_icmp.o net_tcp.o net_tcpbuf.o dev_tcpconsole.o +CFEOBJS = env_subr.o cfe_attach.o cfe_iocb_dispatch.o cfe_devfuncs.o \ + nvram_subr.o cfe_console.o cfe_main.o cfe_mem.o cfe_timer.o \ + cfe_background.o cfe_error.o build_date.o \ + cfe_rawfs.o cfe_zlibfs.o cfe_xreq.o cfe_fatfs.o cfe_httpfs.o cfe_filesys.o cfe_boot.o \ + cfe_autoboot.o cfe_ldr_elf.o cfe_ldr_raw.o cfe_ldr_srec.o cfe_loader.o url.o \ + cfe_savedata.o +UIOBJS = ui_command.o ui_cmddisp.o ui_envcmds.o ui_devcmds.o \ + ui_netcmds.o ui_tcpcmds.o ui_memcmds.o ui_loadcmds.o ui_pcicmds.o \ + ui_examcmds.o ui_flash.o ui_misccmds.o \ + ui_test_disk.o ui_test_ether.o ui_test_flash.o ui_test_uart.o + +# +# Add more object files if we're supporting PCI +# + +ifeq ($(strip ${CFG_PCI}),1) +PCIOBJS = pciconf.o ldtinit.o pci_subr.o +PCIOBJS += pci_devs.o +DEVOBJS += dev_sp1011.o dev_ht7520.o +DEVOBJS += dev_ide_pci.o dev_ns16550_pci.o +DEVOBJS += dev_tulip.o dev_dp83815.o +CFLAGS += -DCFG_PCI=1 +ifeq ($(strip ${CFG_LDT_REV_017}),1) +CFLAGS += -DCFG_LDT_REV_017=1 +endif +ifeq ($(strip ${CFG_DOWNLOAD}),1) +DEVOBJS += dev_bcm1250.o download.data +CFLAGS += -DCFG_DOWNLOAD=1 +endif +endif + +# +# If doing bi-endian, add the compiler switch to change +# the way the vectors are generated. These switches are +# only added to the big-endian portion of the ROM, +# which is located at the real boot vector. +# + +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),0) + CFLAGS += -DCFG_BIENDIAN=1 + endif +endif + +# +# Include the makefiles for the architecture-common, cpu-specific, +# and board-specific directories. Each of these will supply +# some files to "ALLOBJS". The BOARD directory is optional +# as some ports are so simple they don't need boad-specific stuff. +# + +include ${ARCH_SRC}/Makefile +include ${CPU_SRC}/Makefile + +ifneq ("$(strip ${BOARD})","") +include ${BOARD_SRC}/Makefile +endif + +# +# Add the common object files here. +# + +ALLOBJS += $(LIBOBJS) $(DEVOBJS) $(CFEOBJS) $(VENOBJS) $(UIOBJS) $(NETOBJS) $(PCIOBJS) + +# +# VAPI continues to be a special case. +# + +ifeq ($(strip ${CFG_VAPI}),1) +include ${TOP}/verif/Makefile +endif + +# +# USB support +# + +ifeq ($(strip ${CFG_USB}),1) +SRCDIRS += ${TOP}/usb +CFE_INC += ${TOP}/usb +include ${TOP}/usb/Makefile +endif + +# +# If we're doing the VGA console thing, pull in the x86 emulator +# and the pcconsole subsystem +# + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +include ${TOP}/x86emu/Makefile +include ${TOP}/pccons/Makefile +endif + +# +# If we're including ZLIB, then add its makefile. +# + +ifeq ($(strip ${CFG_ZLIB}),1) +include ${TOP}/zlib/Makefile +CFLAGS += -DCFG_ZLIB=1 -DMY_ZCALLOC -DNO_MEMCPY +endif + +# +# Vendor extensions come next - they live in their own directory. +# + +include ${TOP}/vendor/Makefile + +.PHONY : all +.PHONY : ALL +.PHONY : build_date.c + +# +# Build the local tools that we use to construct other source files +# + +mkpcidb : ${TOP}/hosttools/mkpcidb.c + gcc -o mkpcidb ${TOP}/hosttools/mkpcidb.c + +memconfig : ${TOP}/hosttools/memconfig.c + gcc -o memconfig -D_MCSTANDALONE_ -D_MCSTANDALONE_NOISY_ -I${TOP}/arch/mips/cpu/sb1250/include ${TOP}/hosttools/memconfig.c ${TOP}/arch/${ARCH}/cpu/${CPU}/src/sb1250_draminit.c + +pcidevs_data2.h : mkpcidb ${TOP}/pci/pcidevs_data.h + ./mkpcidb > pcidevs_data2.h + +mkflashimage : ${TOP}/hosttools/mkflashimage.c + gcc -o mkflashimage -I${TOP}/include ${TOP}/hosttools/mkflashimage.c + +pci_subr.o : ${TOP}/pci/pci_subr.c pcidevs_data2.h + +build_date.c : + echo "const char *builddate = \"`date`\";" > build_date.c + echo "const char *builduser = \"`whoami`@`hostname`\";" >> build_date.c + +# +# Make a define for the board name +# + +CFLAGS += -D_$(patsubst "%",%,${CFG_BOARDNAME})_ + +LIBCFE = libcfe.a + +%.o : %.c + $(GCC) $(CFLAGS) -o $@ $< + +%.o : %.S + $(GCC) $(CFLAGS) -o $@ $< + +# +# This rule constructs "libcfe.a" which contains most of the object +# files. +# + +$(LIBCFE) : $(ALLOBJS) + rm -f $(LIBCFE) + $(AR) cr $(LIBCFE) $(ALLOBJS) + $(RANLIB) $(LIBCFE) + + + diff --git a/cfe/cfe/main/cfe_attach.c b/cfe/cfe/main/cfe_attach.c new file mode 100644 index 0000000..1235d6e --- /dev/null +++ b/cfe/cfe/main/cfe_attach.c @@ -0,0 +1,265 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device Attach routines File: cfe_attach.c + * + * This module manages the list of device drivers. When a driver + * is probed, it can call cfe_attach to create actual device + * instances. The routines in this module manage the + * device list and the assignment of device names. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_device.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_MAX_DEVINST 64 /* max # of instances of devices */ + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +/* + * Our device list. + */ + +queue_t cfe_devices = {&cfe_devices, &cfe_devices}; + +/* ********************************************************************* + * cfe_finddev(name) + * + * Locate a device in the device list by its name and return + * a pointer to the device structure. + * + * Input parameters: + * name - name of device, e.g., "uart0" + * + * Return value: + * cfe_device_t pointer or NULL + ********************************************************************* */ + +cfe_device_t *cfe_finddev(char *name) +{ + queue_t *qb; + cfe_device_t *dev; + + for (qb = cfe_devices.q_next; qb != &cfe_devices; qb = qb->q_next) { + dev = (cfe_device_t *) qb; + if (strcmp(dev->dev_fullname,name) == 0) { + return dev; + } + } + + return NULL; +} + + +/* ********************************************************************* + * cfe_device_reset() + * + * Call all the "reset" methods in the devices on the device + * list. Note that the methods get called even when the + * devices are closed! + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_device_reset(void) +{ + queue_t *qb; + cfe_device_t *dev; + + for (qb = cfe_devices.q_next; qb != &cfe_devices; qb = qb->q_next) { + dev = (cfe_device_t *) qb; + if (dev->dev_dispatch->dev_reset) { + (*(dev->dev_dispatch->dev_reset))(dev->dev_softc); + } + } +} + +/* ********************************************************************* + * cfe_attach_idx(drv,idx,softc,bootinfo,description) + * + * Add a device to the device list at a specific index. This + * is mainly used for devices like SCSI disks or CD-ROMs so + * we can use an index that matches the target ID or LUN. + * + * Input parameters: + * drv - driver structure (from the device driver module) + * idx - requested index (e.g., uartn where 'n' is the idx) + * softc - Unique information maintained for this device + * bootinfo - suffix for long form of the device name. For + * example, scsi0.3.1 might mean SCSI controller + * 0, device ID 3, LUN 1. The bootinfo would be + * "3.1" + * description - something nice to say for the devices command + * + * Return value: + * 0 if device has already been added at this index + * <0 for other problems + * 1 if we were successful. + ********************************************************************* */ + +int cfe_attach_idx(cfe_driver_t *drv,int idx,void *softc, + char *bootinfo,char *description) +{ + char name[64]; + cfe_device_t *dev; + + xsprintf(name,"%s%d",drv->drv_bootname,idx); + + if (bootinfo) { + strcat(name,"."); + strcat(name,bootinfo); + } + + if (cfe_finddev(name) != NULL) { + return 0; + } + + dev = (cfe_device_t *) KMALLOC(sizeof(cfe_device_t),0); + if (!dev) return -1; + + dev->dev_fullname = strdup(name); + dev->dev_softc = softc; + dev->dev_class = drv->drv_class; + dev->dev_dispatch = drv->drv_dispatch; + dev->dev_description = description ? strdup(description) : NULL; + dev->dev_opencount = 0; + + q_enqueue(&cfe_devices,(queue_t *) dev); + + return 1; + +} + + + +/* ********************************************************************* + * cfe_attach(drv,softc,bootinfo,description + * + * Add a device to the system. This is a callback from the + * probe routine, and is used to actually add devices to CFE's + * device list. + * + * Input parameters: + * drv - driver structure (from the device driver module) + * softc - Unique information maintained for this device + * bootinfo - suffix for long form of the device name. For + * example, scsi0.3.1 might mean SCSI controller + * 0, device ID 3, LUN 1. The bootinfo would be + * "3.1" + * description - something nice to say for the devices command + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_attach(cfe_driver_t *drv,void *softc, + char *bootinfo, + char *description) +{ + int idx; + int res; + + /* + * Try device indicies 0..CFE_MAX_DEVINST to assign a unique + * device name for this device. This is a really braindead way to + * do this, but how many devices are we expecting anyway? + */ + + for (idx = 0; idx < CFE_MAX_DEVINST; idx++) { + + res = cfe_attach_idx(drv,idx,softc,bootinfo,description); + + if (res < 0) break; /* out of memory or other badness */ + if (res > 0) break; /* success! */ + /* otherwise, try again, slot is taken */ + } + +} + +/* ********************************************************************* + * cfe_attach_init() + * + * Initialize this module. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +void cfe_attach_init(void) +{ + q_init(&(cfe_devices)); +} + + +/* ********************************************************************* + * cfe_device_name(ctx) + * + * Given a device context, return a device name + * + * Input parameters: + * ctx - context + * + * Return value: + * name + ********************************************************************* */ + +char *cfe_device_name(cfe_devctx_t *ctx) +{ + return ctx->dev_dev->dev_fullname; +} diff --git a/cfe/cfe/main/cfe_autoboot.c b/cfe/cfe/main/cfe_autoboot.c new file mode 100644 index 0000000..14f3d3c --- /dev/null +++ b/cfe/cfe/main/cfe_autoboot.c @@ -0,0 +1,456 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Automatic OS bootstrap File: cfe_autoboot.c + * + * This module handles OS bootstrap stuff. We use this version + * to do "automatic" booting; walking down a list of possible boot + * options, trying them until something good happens. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "env_subr.h" +#include "cfe.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_api.h" +#include "cfe_fileops.h" +#include "cfe_bootblock.h" +#include "bsp_config.h" +#include "cfe_boot.h" + +#include "cfe_loader.h" + +#include "cfe_autoboot.h" + +/* ********************************************************************* + * data + ********************************************************************* */ + +queue_t cfe_autoboot_list = {&cfe_autoboot_list,&cfe_autoboot_list}; + +extern cfe_loadargs_t cfe_loadargs; /* from cfe_boot.c */ +extern const char *bootvar_device; +extern const char *bootvar_file; +extern const char *bootvar_flags; + +extern char *varchars; + +/* ********************************************************************* + * macroexpand(instr,outstr) + * + * Expand environment variables in "instr" to "outstr" + * + * Input parameters: + * instr - to be expanded + * outstr - expanded. + * + * Return value: + * nothing + ********************************************************************* */ + +static void macroexpand(char *instr,char *outstr) +{ + char macroname[50]; + char *m; + + while (*instr) { + if (*instr == '$') { + instr++; + m = macroname; + while (*instr && strchr(varchars,*instr)) { + *m++ = *instr++; + } + *m = '\0'; + m = env_getenv(macroname); + if (m) { + while (*m) *outstr++ = *m++; + } + } + else { + *outstr++ = *instr++; + } + } + + *outstr = '\0'; +} + +/* ********************************************************************* + * cfe_tryauto_common(method,loadargs) + * + * Common portion of autoboot + * + * Input parameters: + * method - details on device to boot from + * filename - canonical name of file to load + * loadargs - cfe_loadargs_t of digested load parameters. + * + * Return value: + * does not return if successful + ********************************************************************* */ + +static int cfe_tryauto_common(cfe_autoboot_method_t *method, + char *filename, + cfe_loadargs_t *la) +{ + int res; + + la->la_filename = filename; + la->la_options = env_getenv(bootvar_flags); + la->la_filesys = method->ab_filesys; + la->la_device = method->ab_dev; + la->la_flags = method->ab_flags | LOADFLG_NOISY | LOADFLG_EXECUTE; + la->la_address = 0; + la->la_maxsize = 0; + la->la_entrypt = 0; + + /* okay, go for it. */ + + xprintf("Loader:%s Filesys:%s Dev:%s File:%s Options:%s\n", + method->ab_loader,la->la_filesys,la->la_device,la->la_filename,la->la_options); + + res = cfe_boot(method->ab_loader,&cfe_loadargs); + + return res; + +} + + +/* ********************************************************************* + * cfe_tryauto_network(method) + * + * Try to autoboot from a network device. + * + * Input parameters: + * method - details on device to boot from + * + * Return value: + * does not return unless there is an error + ********************************************************************* */ + +#if CFG_NETWORK +static int cfe_tryauto_network(cfe_autoboot_method_t *method) +{ + int res; + dhcpreply_t *reply = NULL; + cfe_loadargs_t *la = &cfe_loadargs; + char buffer[512]; + char *x; + + /* + * First turn off any network interface that is currently active. + */ + + net_uninit(); + + /* + * Now activate the network hardware. + */ + + res = net_init(method->ab_dev); + if (res < 0) { + printf("Could not initialize network device %s: %s\n", + method->ab_dev, + cfe_errortext(res)); + return res; + } + + /* + * Do a DHCP query. + */ + + res = dhcp_bootrequest(&reply); + if (res < 0) { + printf("DHCP request failed on device %s: %s\n",method->ab_dev, + cfe_errortext(res)); + net_uninit(); + return res; + } + + net_setparam(NET_IPADDR,reply->dr_ipaddr); + net_setparam(NET_NETMASK,reply->dr_netmask); + net_setparam(NET_GATEWAY,reply->dr_gateway); + net_setparam(NET_NAMESERVER,reply->dr_nameserver); + net_setparam(NET_DOMAIN,reply->dr_domainname); + + /* Set all our environment variables. */ + net_setnetvars(); + dhcp_set_envvars(reply); + + if (reply) dhcp_free_reply(reply); + + /* + * Interface is now configured and ready, we can + * load programs now. + */ + + /* + * Construct the file name to load. If the method does not + * specify a file name directly, get it from DHCP. + * + * For network booting, the format of the file name + * is 'hostname:filename' + * + * If the method's filename includes a hostname, ignore + * BOOT_SERVER. Otherwise, combine BOOT_SERVER with the + * filename. This way we can provide the name here + * but have the file come off the server specified in the + * DHCP message. + */ + + if (method->ab_file && strchr(method->ab_file,':')) { + macroexpand(method->ab_file,buffer); + } + else { + buffer[0] = '\0'; + x = env_getenv("BOOT_SERVER"); + if (x) { + strcat(buffer,x); + strcat(buffer,":"); + } + + x = method->ab_file; + if (!x) x = env_getenv(bootvar_file); + if (x) { + strcat(buffer,x); + } + } + + /* Okay, do it. */ + + cfe_tryauto_common(method,buffer,la); + + /* If we get here, something bad happened. */ + + net_uninit(); + + return res; + +} + +#endif + + +/* ********************************************************************* + * cfe_tryauto_disk(method) + * + * Try to autoboot from a disk device. + * + * Input parameters: + * method - details on device to boot from + * + * Return value: + * does not return unless there is an error + ********************************************************************* */ +static int cfe_tryauto_disk(cfe_autoboot_method_t *method) +{ + int res; + cfe_loadargs_t *la = &cfe_loadargs; + char buffer[512]; + char *filename; + + buffer[0] = '\0'; + + if (method->ab_file) { + macroexpand(method->ab_file,buffer); + filename = buffer; + } + else { + filename = env_getenv("BOOT_FILE"); + if (filename) strcpy(buffer,filename); + } + + res = cfe_tryauto_common(method,filename,la); + + return res; +} + +/* ********************************************************************* + * cfe_tryauto(method) + * + * Try a single autoboot method. + * + * Input parameters: + * method - autoboot method to try + * + * Return value: + * does not return if bootstrap is successful + * else error code + ********************************************************************* */ + +static int cfe_tryauto(cfe_autoboot_method_t *method) +{ + switch (method->ab_type) { +#if CFG_NETWORK + case CFE_AUTOBOOT_NETWORK: + return cfe_tryauto_network(method); + break; +#endif + + case CFE_AUTOBOOT_DISK: + case CFE_AUTOBOOT_RAW: + return cfe_tryauto_disk(method); + break; + } + + return -1; +} + +/* ********************************************************************* + * cfe_autoboot(dev,flags) + * + * Try to perform an automatic system bootstrap + * + * Input parameters: + * dev - if not NULL, restrict bootstrap to named device + * flags - controls behaviour of cfe_autoboot + * + * Return value: + * should not return if bootstrap is successful, otherwise + * error code + ********************************************************************* */ +int cfe_autoboot(char *dev,int flags) +{ + queue_t *qb; + cfe_autoboot_method_t *method; + int res; + cfe_timer_t timer; + int forever; + int pollconsole; + + forever = (flags & CFE_AUTOFLG_TRYFOREVER) ? 1 : 0; + pollconsole = (flags & CFE_AUTOFLG_POLLCONSOLE) ? 1 : 0; + + do { /* potentially forever */ + for (qb = cfe_autoboot_list.q_next; qb != &cfe_autoboot_list; qb = qb->q_next) { + + method = (cfe_autoboot_method_t *) qb; + + /* + * Skip other devices if we passed in a specific one. + */ + + if (dev && (strcmp(dev,method->ab_dev) != 0)) continue; + + printf("\n*** Autoboot: Trying device '%s' ", method->ab_dev); + if (method->ab_file) printf("file %s ",method->ab_file); + printf("(%s,%s)\n\n",method->ab_dev,method->ab_filesys,method->ab_loader); + + /* + * Scan keyboard if requested. + */ + if (pollconsole) { + TIMER_SET(timer,CFE_HZ); + while (!TIMER_EXPIRED(timer)) { + POLL(); + if (console_status()) goto done; + } + } + + /* + * Try something. may not return. + */ + + res = cfe_tryauto(method); + } + } while (forever); + + /* bail. */ +done: + + printf("\n*** Autoboot failed.\n\n"); + + return -1; +} + + +/* ********************************************************************* + * cfe_add_autoboot(type,flags,dev,loader,filesys,file) + * + * Add an autoboot method to the table. + * This is typically called in the board_finalinit one or more + * times to provide a list of bootstrap methods to try for autoboot + * + * Input parameters: + * type - CFE_AUTOBOOT_xxx (disk,network,raw) + * flags - loader flags (LOADFLG_xxx) + * loader - loader string (elf, raw, srec) + * filesys - file system string (raw, tftp, fat) + * file - name of file to load (if null, will try to guess) + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int cfe_add_autoboot(int type,int flags,char *dev,char *loader,char *filesys,char *file) +{ + cfe_autoboot_method_t *method; + + method = (cfe_autoboot_method_t *) KMALLOC(sizeof(cfe_autoboot_method_t),0); + + if (!method) return CFE_ERR_NOMEM; + + method->ab_type = type; + method->ab_flags = flags; + method->ab_dev = dev; + method->ab_loader = loader; + method->ab_filesys = filesys; + method->ab_file = file; + + q_enqueue(&cfe_autoboot_list,(queue_t *)method); + return 0; +} diff --git a/cfe/cfe/main/cfe_background.c b/cfe/cfe/main/cfe_background.c new file mode 100644 index 0000000..9a64e0a --- /dev/null +++ b/cfe/cfe/main/cfe_background.c @@ -0,0 +1,174 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Timer routines File: cfe_timer.c + * + * This module manages the list of routines to call periodically + * during "background processing." CFE has no interrupts or + * multitasking, so this is just where all the polling routines + * get called from. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define MAX_BACKGROUND_TASKS 16 + + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +static void (*cfe_bg_tasklist[MAX_BACKGROUND_TASKS])(void *); +static void *cfe_bg_args[MAX_BACKGROUND_TASKS]; + + +/* ********************************************************************* + * cfe_bg_init() + * + * Initialize the background task list + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_bg_init(void) +{ + memset(cfe_bg_tasklist,0,sizeof(cfe_bg_tasklist)); +} + + +/* ********************************************************************* + * cfe_bg_add(func,arg) + * + * Add a function to be called periodically in the background + * polling loop. + * + * Input parameters: + * func - function pointer + * arg - arg to pass to function + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_bg_add(void (*func)(void *x),void *arg) +{ + int idx; + + for (idx = 0; idx < MAX_BACKGROUND_TASKS; idx++) { + if (cfe_bg_tasklist[idx] == NULL) { + cfe_bg_tasklist[idx] = func; + cfe_bg_args[idx] = arg; + return; + } + } +} + +/* ********************************************************************* + * cfe_bg_remove(func) + * + * Remove a function from the background polling loop + * + * Input parameters: + * func - function pointer + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_bg_remove(void (*func)(void *)) +{ + int idx; + + for (idx = 0; idx < MAX_BACKGROUND_TASKS; idx++) { + if (cfe_bg_tasklist[idx] == func) break; + } + + if (idx == MAX_BACKGROUND_TASKS) return; + + for (; idx < MAX_BACKGROUND_TASKS-1; idx++) { + cfe_bg_tasklist[idx] = cfe_bg_tasklist[idx+1]; + cfe_bg_args[idx] = cfe_bg_args[idx+1]; + } + + cfe_bg_tasklist[idx] = NULL; + cfe_bg_args[idx] = NULL; +} + + +/* ********************************************************************* + * background() + * + * The main loop and other places that wait for stuff call + * this routine to make sure the background handlers get their + * time. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void background(void) +{ + int idx; + void (*func)(void *arg); + + for (idx = 0; idx < MAX_BACKGROUND_TASKS; idx++) { + func = cfe_bg_tasklist[idx]; + if (func == NULL) break; + (*func)(cfe_bg_args[idx]); + } +} diff --git a/cfe/cfe/main/cfe_boot.c b/cfe/cfe/main/cfe_boot.c new file mode 100644 index 0000000..12fecaa --- /dev/null +++ b/cfe/cfe/main/cfe_boot.c @@ -0,0 +1,248 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * OS bootstrap File: cfe_boot.c + * + * This module handles OS bootstrap stuff + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "env_subr.h" +#include "cfe.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_api.h" +#include "cfe_fileops.h" +#include "cfe_bootblock.h" +#include "bsp_config.h" +#include "cfe_boot.h" + +#include "cfe_loader.h" + +#if CFG_UI +extern int ui_docommands(char *buf); +#endif + +/* ********************************************************************* + * data + ********************************************************************* */ + +const char *bootvar_device = "BOOT_DEVICE"; +const char *bootvar_file = "BOOT_FILE"; +const char *bootvar_flags = "BOOT_FLAGS"; + +cfe_loadargs_t cfe_loadargs; + +/* ********************************************************************* + * splitpath(path,devname,filename) + * + * Split a path name (a boot path, in the form device:filename) + * into its parts + * + * Input parameters: + * path - pointer to path string + * devname - receives pointer to device name + * filename - receives pointer to file name + * + * Return value: + * nothing + ********************************************************************* */ + +void splitpath(char *path,char **devname,char **filename) +{ + char *x; + + *devname = NULL; + *filename = NULL; + + x = strchr(path,':'); + + if (!x) { + *devname = NULL; /* path consists of device name */ + *filename = path; + } + else { + *x++ = '\0'; /* have both device and file name */ + *filename = x; + *devname = path; + } +} + + +/* ********************************************************************* + * cfe_go(la) + * + * Starts a previously loaded program. cfe_loadargs.la_entrypt + * must be set to the entry point of the program to be started + * + * Input parameters: + * la - loader args + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_go(cfe_loadargs_t *la) +{ + if (la->la_entrypt == 0) { + xprintf("No program has been loaded.\n"); + return; + } + +#if CFG_NETWORK + if (!(la->la_flags & LOADFLG_NOCLOSE)) { + if (net_getparam(NET_DEVNAME)) { + xprintf("Closing network.\n"); + net_uninit(); + } + } +#endif + + xprintf("Starting program at 0x%p\n",la->la_entrypt); + + cfe_start(la->la_entrypt); +} + + +/* ********************************************************************* + * cfe_boot(la) + * + * Bootstrap the system. + * + * Input parameters: + * la - loader arguments + * + * Return value: + * error, or does not return + ********************************************************************* */ +int cfe_boot(char *ldrname,cfe_loadargs_t *la) +{ + int res; + + la->la_entrypt = 0; + + if (la->la_flags & LOADFLG_NOISY) { + xprintf("Loading: "); + } + + res = cfe_load_program(ldrname,la); + + if (res < 0) { + if (la->la_flags & LOADFLG_NOISY) { + xprintf("Failed.\n"); + } + return res; + } + + /* + * Special case: If loading a batch file, just do the commands here + * and return. For batch files we don't want to set up the + * environment variables. + */ + + if (la->la_flags & LOADFLG_BATCH) { +#if CFG_UI + ui_docommands((char *) la->la_entrypt); +#endif + return 0; + } + + /* + * Otherwise set up for running a real program. + */ + + if (la->la_flags & LOADFLG_NOISY) { + xprintf("Entry at 0x%p\n",la->la_entrypt); + } + + /* + * Set up the environment variables for the bootstrap + */ + + if (la->la_device) { + env_setenv(bootvar_device,la->la_device,ENV_FLG_BUILTIN); + } + else { + env_delenv(bootvar_device); + } + + if (la->la_filename) { + env_setenv(bootvar_file,la->la_filename,ENV_FLG_BUILTIN); + } + else { + env_delenv(bootvar_file); + } + + if (la->la_options) { + env_setenv(bootvar_flags,la->la_options,ENV_FLG_BUILTIN); + } + else { + env_delenv(bootvar_flags); + } + + /* + * Banzai! Run the program. + */ + + if ((la->la_flags & LOADFLG_EXECUTE) && + (la->la_entrypt != 0)) { + cfe_go(la); + } + + return 0; +} + diff --git a/cfe/cfe/main/cfe_console.c b/cfe/cfe/main/cfe_console.c new file mode 100755 index 0000000..a9464f1 --- /dev/null +++ b/cfe/cfe/main/cfe_console.c @@ -0,0 +1,1190 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Console Interface File: cfe_console.c + * + * This module contains high-level routines for dealing with + * the console (TTY-style) device. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_error.h" +#include "env_subr.h" +#include "cfe_console.h" +#include "cfe.h" + +#include "bsp_config.h" + + +/* + * Escape sequences: + * + * Sequence Descr Emulator + * + * ESC [ A UP xterm + * ESC [ B DOWN xterm + * ESC [ C RIGHT xterm + * ESC [ D LEFT xterm + * + * ESC O P F1 xterm + * ESC O Q F2 xterm + * ESC O R F3 xterm + * ESC O S F4 xterm + * + * ESC [ 1 1 ~ F1 teraterm + * ESC [ 1 2 ~ F2 teraterm + * ESC [ 1 3 ~ F3 teraterm + * ESC [ 1 4 ~ F4 teraterm + * + * ESC [ 1 5 ~ F5 xterm,teraterm + * ESC [ 1 7 ~ F6 xterm,teraterm + * ESC [ 1 8 ~ F7 xterm,teraterm + * ESC [ 1 9 ~ F8 xterm,teraterm + * ESC [ 2 0 ~ F9 xterm,teraterm + * ESC [ 2 1 ~ F10 xterm,teraterm + * ESC [ 2 3 ~ F11 xterm,teraterm + * ESC [ 2 4 ~ F12 xterm,teraterm + * + * ESC [ 5 ~ PGUP xterm + * ESC [ 6 ~ PGDN xterm + * ESC [ F HOME xterm + * ESC [ H END xterm + * + * ESC [ 2 ~ HOME teraterm + * ESC [ 3 ~ PGUP teraterm + * ESC [ 5 ~ END teraterm + * ESC [ 6 ~ PGDN teraterm + * + */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + + +#define CTRL(x) ((x)-'@') + +#define GETCHAR(x) while (console_read(&(x),1) != 1) { POLL(); } + +#define XTERM 0 +#define TERATERM 1 + +#define MAXSAVELINES 30 +#define MSGQUEUEMAX 10 /* number of chunks of log to keep */ +#define MSGQUEUESIZE 256 /* size of each chunk of console log */ + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct msgqueue_s { /* saved console log message */ + queue_t link; + int len; + char data[MSGQUEUESIZE]; +} msgqueue_t; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +#if !CFG_MINIMAL_SIZE +int console_nextsave = 0; +char *console_savedlines[MAXSAVELINES] = {0}; +static char *console_killbuffer = NULL; +queue_t console_msgq = {&console_msgq,&console_msgq}; +static int console_buffer_flg = 0; +static int console_mode = XTERM; + +static void console_flushbuffer(void); +static void console_save(unsigned char *buffer,int length); + +#endif + +#if defined(CONFIG_MIPS_BRCM) +int g_console_abort = 0; +#endif +int console_handle = -1; +static int console_xprint(const char *str); +char *console_name = NULL; +static int console_inreadline = 0; +static int console_redisplay = 0; + +/* ********************************************************************* + * console_log(tmplt,...) + * + * Sort of like printf, but used during things that might be + * called in the polling loop. If you print out a message + * using this call and it happens to be printed while processing + * the console "readline" loop, the readline and the associated + * prompt will be redisplayed. Don't include the \r\n in the + * string to be displayed. + * + * Input parameters: + * tmplt, ... - printf parameters + * + * Return value: + * nothing + ********************************************************************* */ + +void console_log(const char *tmplt,...) +{ + char buffer[256]; + va_list marker; + int count; + + va_start(marker,tmplt); + count = xvsprintf(buffer,tmplt,marker); + va_end(marker); + xprintf("\r%s\033[J\r\n",buffer); + + if (console_inreadline) console_redisplay = 1; +} + +/* ********************************************************************* + * console_open(name) + * + * Open the specified device and make it the console + * + * Input parameters: + * name - name of device + * + * Return value: + * 0 if ok, else return code. + * console_handle contains the console's handle + ********************************************************************* */ + +int console_open(char *name) +{ +#if CFG_MINIMAL_SIZE + if (console_handle != -1) { + console_close(); + } + + console_handle = cfe_open(name); + if (console_handle < 0) return CFE_ERR_DEVNOTFOUND; + +#else + + int flushbuf; + + console_name = NULL; + + if (console_handle != -1) { + console_close(); + } + + flushbuf = console_buffer_flg; + console_buffer_flg = 0; + + console_handle = cfe_open(name); + if (console_handle < 0) return CFE_ERR_DEVNOTFOUND; + + console_name = name; + if (flushbuf) console_flushbuffer(); +#endif + + return 0; +} + +/* ********************************************************************* + * console_close() + * + * Close the console device + * + * Input parameters: + * nothing + * + * Return value: + * 0 + ********************************************************************* */ + +int console_close(void) +{ + if (console_handle != -1) { + cfe_close(console_handle); + } + + console_handle = -1; + + return 0; +} + +/* ********************************************************************* + * console_read(buffer,length) + * + * Read characters from the console. + * + * Input parameters: + * buffer - pointer to buffer to receive characters + * length - total size of the buffer + * + * Return value: + * number of characters received, or <0 if error code + ********************************************************************* */ + +int console_read(char *buffer,int length) +{ + if (console_handle == -1) return -1; + + return cfe_read(console_handle,(unsigned char*)buffer,length); +} + + +/* ********************************************************************* + * console_write(buffer,length) + * + * Write text to the console. If the console is not open and + * we're "saving" text, put the text on the in-memory queue + * + * Input parameters: + * buffer - pointer to data + * length - number of characters to write + * + * Return value: + * number of characters written or <0 if error + ********************************************************************* */ + +int console_write(char *buffer,int length) +{ + int res; + +#if !CFG_MINIMAL_SIZE + /* + * Buffer text if requested + */ + if (console_buffer_flg) { + console_save(buffer,length); + return length; + } +#endif + + /* + * Do nothing if no console + */ + + if (console_handle == -1) return -1; + + /* + * Write text to device + */ + + for (;;) { + res = cfe_write(console_handle,(unsigned char*)buffer,length); + if (res < 0) break; + buffer += res; + length -= res; + if (length == 0) break; + } + + if (res < 0) return -1; + return 0; +} + +/* ********************************************************************* + * console_status() + * + * Return the status of input for the console. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if no characters are available + * 1 if characters are available. + ********************************************************************* */ + +int console_status(void) +{ + if (console_handle == -1) return 0; + + return cfe_inpstat(console_handle); +} + +/* ********************************************************************* + * console_xprint(str) + * + * printf callback for the console device. the "xprintf" + * routine ends up calling this. This routine also cooks the + * output, turning "\n" into "\r\n" + * + * Input parameters: + * str - string to write + * + * Return value: + * number of characters written + ********************************************************************* */ + +static int console_xprint(const char *str) +{ + int count = 0; + int len; + const char *p; + + /* Convert CR to CRLF as we write things out */ + + while ((p = strchr(str,'\n'))) { + console_write((char*)str,p-str); + console_write("\r\n",2); + count += (p-str); + str = p + 1; + } + + len = strlen(str); + console_write((char*)str, len); + count += len; + + return count; +} + + +/* ********************************************************************* + * console_readline_noedit(str,len) + * + * A simple 'gets' type routine for the console. We support + * backspace and carriage return. No line editing support here, + * this routine is used in places where we don't want it. + * + * Input parameters: + * prompt - prompt string + * str - pointer to user buffer + * len - length of user buffer + * + * Return value: + * number of characters read (terminating newline is not + * placed in the buffer) + ********************************************************************* */ + +int console_readline_noedit(char *prompt,char *str,int len) +{ + int reading = 1; + char ch; + int res = -1; + int idx = 0; + + console_inreadline++; + + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + + POLL(); + while (reading) { + + /* + * If someone used console_log (above) or hit Control-C (below), + * redisplay the prompt and the string we've got so far. + */ + + if (console_redisplay) { + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + console_write(str,idx); + console_redisplay = 0; + continue; + } + +#if defined(CONFIG_MIPS_BRCM) + + /* + * If a background process has set the global g_console_abort flag, stop + * reading from the keyboard. + */ + + if (g_console_abort) { + g_console_abort = 0; + break; + } + +#endif + + /* + * if nobody's typed anything, keep polling + */ + + if (console_status() == 0) { + POLL(); + continue; + } + + /* + * Get the char from the keyboard + */ + + res = console_read(&ch,1); + if (res < 0) break; + if (res == 0) continue; + + /* + * And dispatch it + */ + + switch (ch) { + case 3: /* Ctrl-C */ + console_write("^C\r\n",4); + console_redisplay = 1; + idx = 0; + break; + case 0x7f: + case '\b': + if (idx > 0) { + idx--; + console_write("\b \b",3); + } + break; + case 21: /* Ctrl-U */ + while (idx > 0) { + idx--; + console_write("\b \b",3); + } + break; + case '\r': + case '\n': + console_write("\r\n",2); + reading = 0; + break; + default: + if (ch >= ' ') { + if (idx < (len-1)) { + str[idx] = ch; + idx++; + console_write(&ch,1); + } + } + break; + } + } + POLL(); + + console_inreadline--; + + str[idx] = 0; + return idx; +} + + +/* ********************************************************************* + * cfe_set_console(name) + * + * This routine is usually called from the BSP's initialization + * module to set up the console device. We set the xprintf + * callback and open the console device. If we open a special + * magic console device (CFE_BUFFER_CONSOLE) the console subsystem + * will buffer text instead. A later call to cfe_set_console + * with a real console name will cause this text to be flushed. + * + * Input parameters: + * name - name of console device + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int cfe_set_console(char *name) +{ + xprinthook = console_xprint; + +#if !CFG_MINIMAL_SIZE + if (strcmp(name,CFE_BUFFER_CONSOLE) == 0) { + console_buffer_flg = 1; + return 0; + } +#endif + + if (name) { + int res; + res = env_setenv("BOOT_CONSOLE",name, + ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); + return console_open(name); + } + return -1; +} + +#if !CFG_MINIMAL_SIZE + +/* ********************************************************************* + * console_flushbuffer() + * + * Flush queued (saved) console messages to the real console + * device. This is used if we need to delay console + * initialization until after other devices are initialized, + * for example, with a VGA console that won't work until + * after PCI initialization. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_flushbuffer(void) +{ + msgqueue_t *msg; + char *buffer; + int length; + int res; + + /* + * Remove console messages from the queue + */ + + while ((msg = (msgqueue_t *) q_deqnext(&console_msgq))) { + + buffer = msg->data; + length = msg->len; + res = 0; + + /* + * Write each message to the console + */ + + for (;;) { + res = cfe_write(console_handle,buffer,length); + if (res < 0) break; + buffer += res; + length -= res; + if (length == 0) break; + } + + /* + * Free the storage + */ + + KFREE(msg); + } +} + + +/* ********************************************************************* + * console_save(buffer,length) + * + * This is used when we want to generate console output + * before the device is initialized. The console_save + * routine saves a copy of the log messages in a queue + * for later retrieval when the console device is open. + * + * Input parameters: + * buffer - message text to save + * length - number of bytes + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_save(unsigned char *buffer,int length) +{ + msgqueue_t *msg; + + /* + * Get a pointer to the last message in the queue. If + * it's full, preprare to allocate a new one + */ + + msg = (msgqueue_t *) console_msgq.q_prev; + if (q_isempty(&(console_msgq)) || (msg->len == MSGQUEUESIZE)) { + msg = NULL; + } + + /* + * Stuff characters into message chunks till we're done + */ + + while (length) { + + /* + * New chunk + */ + if (msg == NULL) { + + msg = (msgqueue_t *) KMALLOC(sizeof(msgqueue_t),0); + if (msg == NULL) return; + msg->len = 0; + q_enqueue(&console_msgq,(queue_t *) msg); + + /* + * Remove chunks to prevent chewing too much memory + */ + + while (q_count(&console_msgq) > MSGQUEUEMAX) { + msgqueue_t *dropmsg; + dropmsg = (msgqueue_t *) q_deqnext(&console_msgq); + if (dropmsg) KFREE(dropmsg); + } + } + + /* + * Save text. If we run off the end of the buffer, prepare + * to allocate a new one + */ + msg->data[msg->len++] = *buffer++; + length--; + if (msg->len == MSGQUEUESIZE) msg = NULL; + } +} + + +/* ********************************************************************* + * console_readnum(num,ch) + * + * Read digits from the console until we get a non-digit. This + * is used to process escape sequences like ESC [ digits ~ + * + * Input parameters: + * num - where to put returned number + * ch - pointer to character that starts sequence, returns + * character that terminated sequence + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_readnum(int *num,char *ch) +{ + int total = 0; + + for (;;) { + total = (total * 10) + (*ch - '0'); + while (console_read(ch,1) != 1) { POLL(); } + if (!((*ch >= '0') && (*ch <= '9'))) break; + } + + *num = total; +} + + +/* ********************************************************************* + * console_readkey(void) + * + * Very simple ANSI escape sequence parser, returns virtual + * key codes for function keys, arrows, etc. + * + * Hold your lunch, three levels of nested switch statements! :-) + * + * Input parameters: + * nothing + * + * Return value: + * virtual key code + ********************************************************************* */ + +int console_readkey(void) +{ + unsigned char ch; + int num; + + GETCHAR(ch); + + switch (ch) { + case VKEY_ESC: + GETCHAR(ch); + switch (ch) { + case 'O': + GETCHAR(ch); + switch (ch) { + case 'P': + return VKEY_F1; + case 'Q': + return VKEY_F2; + case 'R': + return VKEY_F3; + case 'S': + return VKEY_F4; + } + return (int)ch; + + case '[': + GETCHAR(ch); + if ((ch >= '0') && (ch <= '9')) { + console_readnum(&num,&ch); + if (ch == '~') { + switch (num) { + case 2: + return VKEY_HOME; + case 3: + return VKEY_PGUP; + case 5: + if (console_mode == XTERM) return VKEY_PGUP; + return VKEY_END; + case 6: + if (console_mode == XTERM) return VKEY_PGDN; + return VKEY_PGDN; + case 11: + return VKEY_F1; + case 12: + return VKEY_F2; + case 13: + return VKEY_F3; + case 14: + return VKEY_F4; + case 15: + return VKEY_F5; + case 17: + return VKEY_F6; + case 18: + return VKEY_F7; + case 19: + return VKEY_F8; + case 20: + return VKEY_F9; + case 21: + return VKEY_F10; + case 23: + return VKEY_F11; + case 24: + return VKEY_F12; + } + return (int)ch; + } + } + else { + switch (ch) { + case 'A': + return VKEY_UP; + case 'B': + return VKEY_DOWN; + case 'C': + return VKEY_RIGHT; + case 'D': + return VKEY_LEFT; + case 'F': + return VKEY_HOME; + case 'H': + return VKEY_END; + default: + return (int) ch; + } + } + default: + return (int)ch; + + } + default: + return (int) ch; + } +} + + +/* ********************************************************************* + * console_xxx(...) + * + * Various small routines to write out cursor control sequences. + * + * Input parameters: + * # of iterations, if necessary + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_backspace(int n) +{ + int t; + + for (t = 0; t < n; t++) console_write("\b",1); +} + +static void console_whiteout(int n) +{ + int t; + + for (t = 0; t < n; t++) console_write(" ",1); + for (t = 0; t < n; t++) console_write("\b",1); +} + + +static void console_eraseeol(void) +{ + console_write("\033[K",3); +} + +static void console_crlf(void) +{ + console_write("\r\n",2); +} + +/* ********************************************************************* + * console_readline(str,len) + * + * A simple 'gets' type routine for the console, with line + * editing support. + * + * Input parameters: + * prompt - prompt string + * str - pointer to user buffer + * len - length of user buffer + * + * Return value: + * number of characters read (terminating newline is not + * placed in the buffer) + ********************************************************************* */ + +int console_readline(char *prompt,char *str,int maxlen) +{ + int reading = 1; + int ch; + int idx = 0; + int len = 0; + int t; + int klen; + int recall; + int nosave = 0; + char *x; + char env[10]; + + console_inreadline++; + recall = console_nextsave; + + if (console_savedlines[console_nextsave]) { + KFREE(console_savedlines[console_nextsave]); + console_savedlines[console_nextsave] = NULL; + } + console_savedlines[console_nextsave] = strdup(""); + + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + + POLL(); + while (reading) { + + /* + * If someone used console_log (above) or hit Control-C (below), + * redisplay the prompt and the string we've got so far. + */ + + if (console_redisplay) { + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + console_write(str,idx); + console_redisplay = 0; + continue; + } + +#if defined(CONFIG_MIPS_BRCM) + + /* + * If a background process has set the global g_console_abort flag, stop + * reading from the keyboard. + */ + + if (g_console_abort) { + g_console_abort = 0; + break; + } + +#endif + + /* + * if nobody's typed anything, keep polling + */ + + if (console_status() == 0) { + POLL(); + continue; + } + + /* + * Get the char from the keyboard + */ + + ch = console_readkey(); + if (ch < 0) break; + if (ch == 0) continue; + + /* + * And dispatch it. Lots of yucky character manipulation follows + */ + + switch (ch) { + case CTRL('C'): /* Ctrl-C - cancel line */ + console_write("^C\r\n",4); + console_redisplay = 1; + nosave = 1; + idx = 0; + break; + + case 0x7f: /* Backspace, Delete */ + case CTRL('H'): + if (idx > 0) { + nosave = 0; + len--; + idx--; + console_write("\b",1); + if (len != idx) { + for (t = idx; t < len; t++) str[t] = str[t+1]; + console_write(&str[idx],len-idx); + console_whiteout(1); + console_backspace(len-idx); + } + else { + console_whiteout(1); + } + } + break; + + case CTRL('D'): /* Ctrl-D */ + if ((idx >= 0) && (len != idx)) { + nosave = 0; + len--; + for (t = idx; t < len; t++) str[t] = str[t+1]; + console_write(&str[idx],len-idx); + console_whiteout(1); + console_backspace(len-idx); + } + break; + + case CTRL('B'): /* cursor left */ + case VKEY_LEFT: + if (idx > 0) { + idx--; + console_backspace(1); + } + break; + + case CTRL('F'): /* cursor right */ + case VKEY_RIGHT: + if (idx < len) { + console_write(&str[idx],1); + idx++; + } + break; + + case CTRL('A'): /* cursor to BOL */ + console_backspace(idx); + idx = 0; + break; + + case CTRL('E'): /* cursor to EOL */ + if (len-idx > 0) console_write(&str[idx],len-idx); + idx = len; + break; + + case CTRL('K'): /* Kill to EOL */ + if (idx != len) { + str[len] = '\0'; + if (console_killbuffer) KFREE(console_killbuffer); + console_killbuffer = strdup(&str[idx]); + console_whiteout(len-idx); + len = idx; + nosave = 0; + } + break; + + case CTRL('Y'): /* Yank killed data */ + if (console_killbuffer == NULL) break; + klen = strlen(console_killbuffer); + if (klen == 0) break; + if (len + klen > maxlen) break; + nosave = 0; + for (t = len + klen; t > idx; t--) { + str[t-1] = str[t-klen-1]; + } + for (t = 0; t < klen; t++) str[t+idx] = console_killbuffer[t]; + len += klen; + console_write(&str[idx],len-idx); + idx += klen; + console_backspace(len-idx-1); + break; + + case CTRL('R'): /* Redisplay line */ + str[len] = 0; + console_crlf(); + console_write(prompt,strlen(prompt)); + console_write(str,len); + console_backspace(len-idx); + break; + + case CTRL('U'): /* Cancel line */ + console_backspace(idx); + console_eraseeol(); + if (len > 0) nosave = 1; + idx = 0; + len = 0; + break; + + case CTRL('M'): /* terminate */ + case CTRL('J'): + console_crlf(); + reading = 0; + break; + + case CTRL('P'): + case VKEY_UP: /* recall previous line */ + t = recall; + t--; + if (t < 0) t = MAXSAVELINES-1; + if (console_savedlines[t] == NULL) break; + recall = t; + console_backspace(idx); + strcpy(str,console_savedlines[recall]); + len = idx = strlen(console_savedlines[recall]); + console_eraseeol(); + console_write(str,len); + nosave = (t == ((console_nextsave - 1) % MAXSAVELINES)); + break; + + case CTRL('N'): + case VKEY_DOWN: /* Recall next line */ + t = recall; + t++; + if (t == MAXSAVELINES) t = 0; + if (console_savedlines[t] == NULL) break; + recall = t; + console_backspace(idx); + strcpy(str,console_savedlines[recall]); + len = idx = strlen(console_savedlines[recall]); + console_eraseeol(); + console_write(str,len); + nosave = 1; + break; + + case VKEY_F1: + case VKEY_F2: + case VKEY_F3: + case VKEY_F4: + case VKEY_F5: + case VKEY_F6: + case VKEY_F7: + case VKEY_F8: + case VKEY_F9: + case VKEY_F10: + case VKEY_F11: + case VKEY_F12: + sprintf(env,"F%d",ch-VKEY_F1+1); + x = env_getenv(env); + if (x) { + console_backspace(idx); + strcpy(str,x); + idx = len = strlen(str); + console_eraseeol(); + console_write(str,len); + console_crlf(); + reading = 0; + nosave = 1; + } + /* + * If F12 is undefined, it means "repeat last command" + */ + if (ch == VKEY_F12) { + t = recall; + t--; + if (t < 0) t = MAXSAVELINES-1; + if (console_savedlines[t] == NULL) break; + recall = t; + console_backspace(idx); + strcpy(str,console_savedlines[recall]); + len = idx = strlen(console_savedlines[recall]); + console_eraseeol(); + console_write(str,len); + console_crlf(); + reading = 0; + nosave = 1; + } + break; + + default: /* insert character */ + if (ch >= ' ') { + if (idx < (maxlen-1)) { + nosave = 0; + for (t = len; t > idx; t--) { + str[t] = str[t-1]; + } + str[idx] = ch; + len++; + if (len != idx) { + console_write(&str[idx],len-idx); + console_backspace(len-idx-1); + } + idx++; + } + } + break; + } + } + POLL(); + + console_inreadline--; + + str[len] = 0; + + if ((len != 0) && !nosave) { + if (console_savedlines[console_nextsave]) { + KFREE(console_savedlines[console_nextsave]); + } + console_savedlines[console_nextsave] = strdup(str); + console_nextsave++; + if (console_nextsave == MAXSAVELINES) console_nextsave = 0; + } + + return len; +} + +#else /* CFG_MINIMAL_SIZE */ +/* ********************************************************************* + * console_readline(str,len) + * + * A simple 'gets' type routine for the console, + * just calls the "noedit" variant for minimal code + * size builds. + * + * Input parameters: + * prompt - prompt string + * str - pointer to user buffer + * len - length of user buffer + * + * Return value: + * number of characters read (terminating newline is not + * placed in the buffer) + ********************************************************************* */ + +int console_readline(char *prompt,char *str,int len) +{ + return console_readline_noedit(prompt,str,len); +} + +#endif diff --git a/cfe/cfe/main/cfe_devfuncs.c b/cfe/cfe/main/cfe_devfuncs.c new file mode 100755 index 0000000..c3ab905 --- /dev/null +++ b/cfe/cfe/main/cfe_devfuncs.c @@ -0,0 +1,279 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device Function stubs File: cfe_devfuncs.c + * + * This module contains device function stubs (small routines to + * call the standard "iocb" interface entry point to CFE). + * There should be one routine here per iocb function call. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" + +extern int cfe_iocb_dispatch(cfe_iocb_t *iocb); + +static int cfe_strlen(char *name) +{ + int count = 0; + + while (*name) { + count++; + name++; + } + + return count; +} + +int cfe_open(char *name) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_OPEN; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = 0; + iocb.plist.iocb_buffer.buf_ptr = (unsigned char*)name; + iocb.plist.iocb_buffer.buf_length = cfe_strlen(name); + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : iocb.iocb_handle; +} + +int cfe_close(int handle) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_CLOSE; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = 0; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status); + +} + +int cfe_readblk(int handle,cfe_offset_t offset,unsigned char *buffer,int length) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_READ; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = offset; + iocb.plist.iocb_buffer.buf_ptr = buffer; + iocb.plist.iocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : iocb.plist.iocb_buffer.buf_retlen; +} + +int cfe_read(int handle,unsigned char *buffer,int length) +{ + return cfe_readblk(handle,0,buffer,length); +} + + +int cfe_writeblk(int handle,cfe_offset_t offset,unsigned char *buffer,int length) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_WRITE; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = offset; + iocb.plist.iocb_buffer.buf_ptr = buffer; + iocb.plist.iocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : iocb.plist.iocb_buffer.buf_retlen; +} + +int cfe_write(int handle,unsigned char *buffer,int length) +{ + return cfe_writeblk(handle,0,buffer,length); +} + + +int cfe_ioctl(int handle,unsigned int ioctlnum, + unsigned char *buffer,int length,int *retlen, + cfe_offset_t offset) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_IOCTL; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = offset; + iocb.plist.iocb_buffer.buf_ioctlcmd = (cfe_offset_t) ioctlnum; + iocb.plist.iocb_buffer.buf_ptr = buffer; + iocb.plist.iocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&iocb); + + if (retlen) *retlen = iocb.plist.iocb_buffer.buf_retlen; + return iocb.iocb_status; +} + +int cfe_inpstat(int handle) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_INPSTAT; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_inpstat_t); + iocb.plist.iocb_inpstat.inp_status = 0; + + cfe_iocb_dispatch(&iocb); + + if (iocb.iocb_status < 0) return iocb.iocb_status; + + return iocb.plist.iocb_inpstat.inp_status; + +} + +long long cfe_getticks(void) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_FW_GETTIME; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_time_t); + iocb.plist.iocb_time.ticks = 0; + + cfe_iocb_dispatch(&iocb); + + return iocb.plist.iocb_time.ticks; + +} + +int cfe_getenv(char *name,char *dest,int destlen) +{ + cfe_iocb_t iocb; + + *dest = NULL; + + iocb.iocb_fcode = CFE_CMD_ENV_GET; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_envbuf_t); + iocb.plist.iocb_envbuf.enum_idx = 0; + iocb.plist.iocb_envbuf.name_ptr = (unsigned char*)name; + iocb.plist.iocb_envbuf.name_length = strlen(name)+1; + iocb.plist.iocb_envbuf.val_ptr = (unsigned char*)dest; + iocb.plist.iocb_envbuf.val_length = destlen; + + cfe_iocb_dispatch(&iocb); + + return iocb.iocb_status; +} + +int cfe_exit(int warm,int code) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_FW_RESTART; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = warm ? CFE_FLG_WARMSTART : 0; + iocb.iocb_psize = sizeof(iocb_exitstat_t); + iocb.plist.iocb_exitstat.status = code; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status); + +} + +int cfe_flushcache(int flg) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_FW_FLUSHCACHE; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = flg; + iocb.iocb_psize = 0; + + cfe_iocb_dispatch(&iocb); + + return iocb.iocb_status; +} + +int cfe_getdevinfo(char *name) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_GETINFO; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = 0; + iocb.plist.iocb_buffer.buf_ptr = (unsigned char*)name; + iocb.plist.iocb_buffer.buf_length = cfe_strlen(name); + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : (int)iocb.plist.iocb_buffer.buf_devflags; +} diff --git a/cfe/cfe/main/cfe_error.c b/cfe/cfe/main/cfe_error.c new file mode 100644 index 0000000..198e7a4 --- /dev/null +++ b/cfe/cfe/main/cfe_error.c @@ -0,0 +1,134 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Error strings File: cfe_error.h + * + * This file contains a mapping from error codes to strings + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "cfe.h" +#include "cfe_error.h" + +/* ********************************************************************* + * Types + ********************************************************************* */ + + +typedef struct errmap_s { + int errcode; + const char *string; +} errmap_t; + +/* ********************************************************************* + * Error code list + ********************************************************************* */ + +errmap_t cfe_errorstrings[] = { + {CFE_OK ,"No error"}, + {CFE_ERR ,"Error"}, + {CFE_ERR_INV_COMMAND ,"Invalid command"}, + {CFE_ERR_EOF ,"End of file reached"}, + {CFE_ERR_IOERR ,"I/O error"}, + {CFE_ERR_NOMEM ,"Insufficient memory"}, + {CFE_ERR_DEVNOTFOUND ,"Device not found"}, + {CFE_ERR_DEVOPEN ,"Device is open"}, + {CFE_ERR_INV_PARAM ,"Invalid parameter"}, + {CFE_ERR_ENVNOTFOUND ,"Environment variable not found"}, + {CFE_ERR_ENVREADONLY ,"Environment variable is read-only"}, + {CFE_ERR_NOTELF ,"Not an ELF-format executable"}, + {CFE_ERR_NOT32BIT ,"Not a 32-bit executable"}, + {CFE_ERR_WRONGENDIAN ,"Executable is wrong-endian"}, + {CFE_ERR_BADELFVERS ,"Invalid ELF file version"}, + {CFE_ERR_NOTMIPS ,"Not a MIPS ELF file"}, + {CFE_ERR_BADELFFMT ,"Invalid ELF file"}, + {CFE_ERR_BADADDR ,"Section would load outside available DRAM"}, + {CFE_ERR_FILENOTFOUND ,"File not found"}, + {CFE_ERR_UNSUPPORTED ,"Unsupported function"}, + {CFE_ERR_HOSTUNKNOWN ,"Host name unknown"}, + {CFE_ERR_TIMEOUT ,"Timeout occured"}, + {CFE_ERR_PROTOCOLERR ,"Network protocol error"}, + {CFE_ERR_NETDOWN ,"Network is down"}, + {CFE_ERR_NONAMESERVER ,"No name server configured"}, + {CFE_ERR_NOHANDLES ,"No more handles"}, + {CFE_ERR_ALREADYBOUND ,"Already bound"}, + {CFE_ERR_CANNOTSET ,"Cannot set network parameter"}, + {CFE_ERR_NOMORE ,"No more enumerated items"}, + {CFE_ERR_BADFILESYS ,"File system not recognized"}, + {CFE_ERR_FSNOTAVAIL ,"File system not available"}, + {CFE_ERR_INVBOOTBLOCK ,"Invalid boot block on disk"}, + {CFE_ERR_WRONGDEVTYPE ,"Device type is incorrect for boot method"}, + {CFE_ERR_BBCHECKSUM ,"Boot block checksum is invalid"}, + {CFE_ERR_BOOTPROGCHKSUM ,"Boot program checksum is invalid"}, + {CFE_ERR_LDRNOTAVAIL, "Loader is not available"}, + {CFE_ERR_NOTREADY, "Device is not ready"}, + {CFE_ERR_GETMEM, "Cannot get memory at specified address"}, + {CFE_ERR_SETMEM, "Cannot set memory at specified address"}, + {CFE_ERR_NOTCONN, "Socket is not connected"}, + {CFE_ERR_ADDRINUSE, "Address is in use"}, + {0,NULL}}; + + +/* ********************************************************************* + * cfe_errortext(err) + * + * Returns the text corresponding to a CFE error code + * + * Input parameters: + * err - error code + * + * Return value: + * string description of error + ********************************************************************* */ + +const char *cfe_errortext(int err) +{ + errmap_t *e = cfe_errorstrings; + + while (e->string) { + if (e->errcode == err) return e->string; + e++; + } + + return (const char *) "Unknown error"; +} + diff --git a/cfe/cfe/main/cfe_fatfs.c b/cfe/cfe/main/cfe_fatfs.c new file mode 100644 index 0000000..f2fa49f --- /dev/null +++ b/cfe/cfe/main/cfe_fatfs.c @@ -0,0 +1,1983 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * FAT file system File: cfe_fatfs.c + * + * This module knows how to read files from a FAT formatted + * file system (12 or 16 bit fats only for now) + * + * Eventually, we'll also include support for the FAT Translation + * Layer (FTL) on PCMCIA flash file systems. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" + +#include "cfe_loader.h" + +#include "cfe.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define SECTORSIZE 512 +#define DIRENTRYSIZE 32 +#define DIRPERSECTOR (SECTORSIZE/DIRENTRYSIZE) + +/*#define _FATFS_DEBUG_*/ + +/* + * Bios Parameter Block offsets and values + */ + +#define BPB_JMPINSTR 0x00 +#define BPB_JMPINSTR_VALUE 0xEB +#define BPB_JMPINSTR_VALUE2 0xE9 +#define BPB_SEAL 0x1FE +#define BPB_SEAL_VALUE 0xAA55 + +#define BPB_BYTESPERSECTOR 0x0B +#define BPB_SECTORSPERCLUSTER 0x0D +#define BPB_RESERVEDSECTORS 0x0E +#define BPB_NUMFATS 0x10 +#define BPB_MAXROOTDIR 0x11 +#define BPB_TOTALSECTORS 0x13 +#define BPB_SECTORSPERFAT 0x16 +#define BPB_SECTORSPERTRACK 0x18 +#define BPB_NUMHEADS 0x1A +#define BPB_HIDDENSECTORS 0x1C +#define BPB_SYSTEMID 54 +#define BPB_MEDIADESCRIPTOR 21 +#define BPB_SIGNATURE 38 +#define BPB_SIGNATURE_VALUE1 0x28 +#define BPB_SIGNATURE_VALUE2 0x29 + +/* + * Partition types + */ + +#define PARTTYPE_EMPTY 0 +#define PARTTYPE_FAT12 1 +#define PARTTYPE_FAT16 4 +#define PARTTYPE_FAT16BIG 6 +#define PARTTYPE_FAT32 0x0B + +/* + * Partition table offsets + */ +#define PTABLE_STATUS 0 +#define PTABLE_STARTHEAD 1 +#define PTABLE_STARTSECCYL 2 /* 2 bytes */ +#define PTABLE_TYPE 4 +#define PTABLE_ENDHEAD 5 +#define PTABLE_ENDSECCYL 6 /* 2 bytes */ +#define PTABLE_BOOTSECTOR 8 /* 4 bytes */ +#define PTABLE_NUMSECTORS 12 /* 4 bytes */ + +#define PTABLE_SIZE 16 +#define PTABLE_COUNT 4 +#define PTABLE_OFFSET (512-2-(PTABLE_COUNT*PTABLE_SIZE)) + +#define PTABLE_STATUS_ACTIVE 0x80 + +/* + * Directory attributes + */ + +#define ATTRIB_NORMAL 0x00 +#define ATTRIB_READONLY 0x01 +#define ATTRIB_HIDDEN 0x02 +#define ATTRIB_SYSTEM 0x04 +#define ATTRIB_LABEL 0x08 +#define ATTRIB_DIR 0x10 +#define ATTRIB_ARCHIVE 0x20 + +#define ATTRIB_LFN 0x0F + +/* + * Macros to read fields in directory & BPB entries + */ + +#define READWORD(buffer,x) (((unsigned int) (buffer)[(x)]) | \ + (((unsigned int) (buffer)[(x)+1]) << 8)) + +#define READWORD32(buffer,x) (READWORD(buffer,(x)) | (READWORD(buffer,(x)+2) << 16)) + +#define READBYTE(buffer,x) ((unsigned int) (buffer)[(x)]) + +/* + * Directory entry offsets and values + */ + +#define DIR_CHECKSUM 13 +#define DIR_FILELENGTH 28 +#define DIR_STARTCLUSTER 26 +#define DIR_ATTRIB 11 +#define DIR_NAMEOFFSET 0 +#define DIR_NAMELEN 8 +#define DIR_EXTOFFSET 8 +#define DIR_EXTLEN 3 + +#define DIRENTRY_CHECKSUM(e) READBYTE(e,DIR_CHECKSUM) +#define DIRENTRY_FILELENGTH(e) READWORD32(e,DIR_FILELENGTH) +#define DIRENTRY_STARTCLUSTER(e) READWORD(e,DIR_STARTCLUSTER) +#define DIRENTRY_ATTRIB(e) READBYTE(e,DIR_ATTRIB) + +#define DIRENTRY_LAST 0 +#define DIRENTRY_DELETED 0xE5 +#define DIRENTRY_PARENTDIR 0x2E + +#define DIRENTRY_LFNIDX(e) READBYTE(e,0) +#define LFNIDX_MASK 0x1F +#define LFNIDX_END 0x40 +#define LFNIDX_MAX 20 + +/* ********************************************************************* + * Types + ********************************************************************* */ + +/* + * Internalized BPB + */ + +typedef struct bpb_s { + unsigned int bpb_bytespersector; + unsigned int bpb_sectorspercluster; + unsigned int bpb_reservedsectors; + unsigned int bpb_numfats; + unsigned int bpb_maxrootdir; + unsigned int bpb_totalsectors; + unsigned int bpb_sectorsperfat; + unsigned int bpb_sectorspertrack; + unsigned int bpb_numheads; + unsigned int bpb_hiddensectors; +} bpb_t; + +/* + * FAT Filesystem descriptor - contains working information + * about an "open" file system + */ + +typedef struct fatfs_s { + int fat_fh; + int fat_refcnt; + bpb_t fat_bpb; + int fat_twelvebit; + int fat_partstart; + uint8_t fat_dirsector[SECTORSIZE]; + int fat_dirsecnum; + uint8_t fat_fatsector[SECTORSIZE]; + int fat_fatsecnum; +} fatfs_t; + +/* + * FAT Chain - describes a series of FAT entries + */ + +typedef struct fatchain_s { + int fat_start; + uint16_t *fat_entries; + int fat_count; +} fatchain_t; + +/* + * FAT File descriptor - contains working information + * about an open file (including the filesystem info) + */ + +typedef struct fatfile_s { + fatfs_t *ff_fat; + int ff_filelength; + fatchain_t ff_chain; + int ff_curpos; + int ff_cursector; + uint8_t ff_sector[SECTORSIZE]; +} fatfile_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int fatfs_fileop_xinit(void **fsctx,void *filename); +static int fatfs_fileop_pinit(void **fsctx,void *filename); +static int fatfs_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int fatfs_fileop_read(void *ref,uint8_t *buf,int len); +static int fatfs_fileop_write(void *ref,uint8_t *buf,int len); +static int fatfs_fileop_seek(void *ref,int offset,int how); +static void fatfs_fileop_close(void *ref); +static void fatfs_fileop_uninit(void *fsctx); + +static int fatfs_check_for_partition_table(fatfs_t *fatfs); + +/* ********************************************************************* + * FAT fileio dispatch table + ********************************************************************* */ + +/* + * Raw FAT (no partition table) - used only on floppies + */ + +const fileio_dispatch_t fatfs_fileops = { + "rfat", + LOADFLG_NOBB, + fatfs_fileop_xinit, + fatfs_fileop_open, + fatfs_fileop_read, + fatfs_fileop_write, + fatfs_fileop_seek, + fatfs_fileop_close, + fatfs_fileop_uninit +}; + +/* + * Partitioned FAT - used on Zip disks, removable hard disks, + * hard disks, flash cards, etc. + */ + +const fileio_dispatch_t pfatfs_fileops = { + "fat", + LOADFLG_NOBB, + fatfs_fileop_pinit, + fatfs_fileop_open, + fatfs_fileop_read, + fatfs_fileop_write, + fatfs_fileop_seek, + fatfs_fileop_close, + fatfs_fileop_uninit +}; + + +/* ********************************************************************* + * fat_readsector(fatfs,sector,numsec,buffer) + * + * Read one or more sectors from the disk into memory + * + * Input parameters: + * fatfs - fat filesystem descriptor + * sector - sector number + * numsec - number of sectors to read + * buffer - buffer to read sectors into + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_readsector(fatfs_t *fatfs,int sector,int numsec,uint8_t *buffer) +{ + int res; + + res = cfe_readblk(fatfs->fat_fh,(sector+fatfs->fat_partstart)*SECTORSIZE, + buffer,numsec*SECTORSIZE); + + if (res != numsec*SECTORSIZE) return CFE_ERR_IOERR; + + return 0; +} + + +/* ********************************************************************* + * fat_dumpbpb(bpb) + * + * Debug function; display fields in a BPB + * + * Input parameters: + * bpb - BIOS parameter block structure + * + * Return value: + * nothing + ********************************************************************* */ + +#ifdef _FATFS_DEBUG_ +static void fat_dumpbpb(bpb_t *bpb) +{ + xprintf("Bytes per sector %d\n",bpb->bpb_bytespersector); + xprintf("Sectors per cluster %d\n",bpb->bpb_sectorspercluster); + xprintf("Reserved sectors %d\n",bpb->bpb_reservedsectors); + xprintf("Number of FATs %d\n",bpb->bpb_numfats); + xprintf("Root dir entries %d\n",bpb->bpb_maxrootdir); + xprintf("Total sectors %d\n",bpb->bpb_totalsectors); + xprintf("Sectors per FAT %d\n",bpb->bpb_sectorsperfat); + xprintf("Sectors per track %d\n",bpb->bpb_sectorspertrack); + xprintf("Number of heads %d\n",bpb->bpb_numheads); + xprintf("Hidden sectors %d\n",bpb->bpb_hiddensectors); +} +#endif + +/* ********************************************************************* + * fat_findpart(fatfs) + * + * For partitioned disks, locate the active partition + * and set "fat_partstart" accordingly + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * + * Return value: + * 0 if we found a valid partition table; else error code + ********************************************************************* */ + +static int fat_findpart(fatfs_t *fatfs) +{ + uint8_t buffer[SECTORSIZE]; + uint8_t *part; + int res; + int idx; + + fatfs->fat_partstart = 0; /* make sure we get real boot sector */ + res = fat_readsector(fatfs,0,1,buffer); + if (res < 0) return res; + + /* + * Normally you're supposed to check for a JMP instruction. + * At least that's what many people do. Flash MBRs don't start + * with JMP instructions, so just look for the seal. + * + * + * if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) { + * return CFE_ERR_BADFILESYS; + * } + */ + + /* + * Check the seal at the end of th sector + */ + + if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS; + + /* + * Look for an active FAT partition. The partition we want must + * be the active one. We do not deal with extended partitions + * here. Hey, this is supposed to be boot code! + */ + + part = &buffer[PTABLE_OFFSET]; + for (idx = 0; idx < PTABLE_COUNT; idx++) { + if ((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) && + ((part[PTABLE_TYPE] == PARTTYPE_FAT12) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) { + break; + } + + part += PTABLE_SIZE; + } + + if (idx == PTABLE_COUNT) return CFE_ERR_BADFILESYS; + + /* + * The info we want is really just the pointer to the + * boot (BPB) sector. Get that and we'll use it for an + * offset into the disk later. + */ + + fatfs->fat_partstart = READWORD32(part,PTABLE_BOOTSECTOR); + + return 0; +} + + +/* ********************************************************************* + * fat_readbpb(fatfs) + * + * Read and internalize the BIOS Parameter Block + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * + * Return value: + * 0 if ok + * else error code (usually, BPB is not valid) + ********************************************************************* */ + +static int fat_readbpb(fatfs_t *fatfs) +{ + uint8_t buffer[SECTORSIZE]; + int res; + + res = fat_readsector(fatfs,0,1,buffer); + if (res < 0) return res; + + if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) return CFE_ERR_BADFILESYS; + if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS; + + fatfs->fat_bpb.bpb_bytespersector = READWORD(buffer,BPB_BYTESPERSECTOR); + fatfs->fat_bpb.bpb_sectorspercluster = READBYTE(buffer,BPB_SECTORSPERCLUSTER); + fatfs->fat_bpb.bpb_reservedsectors = READWORD(buffer,BPB_RESERVEDSECTORS); + fatfs->fat_bpb.bpb_numfats = READBYTE(buffer,BPB_NUMFATS); + fatfs->fat_bpb.bpb_maxrootdir = READWORD(buffer,BPB_MAXROOTDIR); + fatfs->fat_bpb.bpb_totalsectors = READWORD(buffer,BPB_TOTALSECTORS); + fatfs->fat_bpb.bpb_sectorsperfat = READWORD(buffer,BPB_SECTORSPERFAT); + fatfs->fat_bpb.bpb_sectorspertrack = READWORD(buffer,BPB_SECTORSPERTRACK); + fatfs->fat_bpb.bpb_numheads = READWORD(buffer,BPB_NUMHEADS); + fatfs->fat_bpb.bpb_hiddensectors = READWORD(buffer,BPB_HIDDENSECTORS); + + fatfs->fat_twelvebit = 1; + if (memcmp(&buffer[0x36],"FAT16 ",8) == 0) fatfs->fat_twelvebit = 0; + + if (fatfs->fat_bpb.bpb_bytespersector != SECTORSIZE) return CFE_ERR_BADFILESYS; + if (fatfs->fat_bpb.bpb_numfats > 2) return CFE_ERR_BADFILESYS; + + /* + * XXX sanity check other fields + */ + +#ifdef _FATFS_DEBUG_ + fat_dumpbpb(&(fatfs->fat_bpb)); +#endif + + return 0; +} + + + +/* ********************************************************************* + * fat_getentry(fatfs,entry) + * + * Read a FAT entry. This is more involved than you'd think, + * since we have to deal with 12 and 16 (and someday 32) bit FATs, + * and the nasty case where a 12-bit FAT entry crosses a sector + * boundary. + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * entry - index of FAT entry + * + * Return value: + * FAT entry, or <0 if an error occured + ********************************************************************* */ + +static int fat_getfatentry(fatfs_t *fatfs,int entry) +{ + int fatsect; + int byteoffset; + int fatstart; + int fatoffset; + uint8_t b1,b2,b3; + int res; + + fatstart = fatfs->fat_bpb.bpb_reservedsectors; + + if (fatfs->fat_twelvebit) { + int odd; + odd = entry & 1; + byteoffset = ((entry & ~1) * 3) / 2; + fatsect = byteoffset / SECTORSIZE; + fatoffset = byteoffset % SECTORSIZE; + + if (fatfs->fat_fatsecnum != fatsect) { + res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect; + } + + b1 = fatfs->fat_fatsector[fatoffset]; + + if ((fatoffset+1) >= SECTORSIZE) { + res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect+1; + fatoffset -= SECTORSIZE; + } + + b2 = fatfs->fat_fatsector[fatoffset+1]; + + if ((fatoffset+2) >= SECTORSIZE) { + res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect+1; + fatoffset -= SECTORSIZE; + } + + b3 = fatfs->fat_fatsector[fatoffset+2]; + + if (odd) { + return ((unsigned int) b3 << 4) + ((unsigned int) (b2 & 0xF0) >> 4); + } + else { + return ((unsigned int) (b2 & 0x0F) << 8) + ((unsigned int) b1); + } + + } + else { + byteoffset = entry * 2; + fatsect = byteoffset / SECTORSIZE; + fatoffset = byteoffset % SECTORSIZE; + + if (fatfs->fat_fatsecnum != fatsect) { + res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect; + } + + b1 = fatfs->fat_fatsector[fatoffset]; + b2 = fatfs->fat_fatsector[fatoffset+1]; + return ((unsigned int) b1) + (((unsigned int) b2) << 8); + } +} + +/* ********************************************************************* + * fat_getrootdirentry(fatfs,entryidx,entry) + * + * Read a root directory entry. The FAT12/16 root directory + * is a contiguous group of sectors, whose size is specified in + * the BPB. This routine just digs out an entry from there + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * entryidx - 0-based entry index to read + * entry - pointer to directory entry (32 bytes) + * + * Return value: + * 0 if ok + * <0 if error occured + ********************************************************************* */ + +static int fat_getrootdirentry(fatfs_t *fatfs,int entryidx,uint8_t *entry) +{ + int rootdirstart; + int rootdirsize; + int dirsecnum; + int res; + + if (entryidx >= fatfs->fat_bpb.bpb_maxrootdir) { + memset(entry,0,DIRENTRYSIZE); + return CFE_ERR_INV_PARAM; + } + + rootdirstart = fatfs->fat_bpb.bpb_reservedsectors + + fatfs->fat_bpb.bpb_numfats * fatfs->fat_bpb.bpb_sectorsperfat; + + rootdirsize = fatfs->fat_bpb.bpb_maxrootdir / DIRENTRYSIZE; + + dirsecnum = rootdirstart + entryidx / DIRPERSECTOR; + + if (fatfs->fat_dirsecnum != dirsecnum) { + res = fat_readsector(fatfs,dirsecnum,1,fatfs->fat_dirsector); + if (res < 0) { + return res; + } + fatfs->fat_dirsecnum = dirsecnum; + } + + memcpy(entry,&(fatfs->fat_dirsector[(entryidx % DIRPERSECTOR)*DIRENTRYSIZE]), + DIRENTRYSIZE); + + return 0; +} + +/* ********************************************************************* + * fat_checksumname(name) + * + * Calculate the "long filename" checksum for a given short name. + * All LFN directory entries associated with the short name are + * given the same checksum byte, to help keep the long name + * consistent. + * + * Input parameters: + * name - pointer to 32-byte directory entry + * + * Return value: + * checksum value + ********************************************************************* */ + +static uint8_t fat_checksumname(uint8_t *name) +{ + uint8_t sum = 0; + uint8_t newbit; + int idx; + + for (idx = 0; idx < 11; idx++) { + newbit = (sum & 1) ? 0x80 : 0x00; + sum >>= 1; + sum |= newbit; + sum += name[idx]; + } + + return sum; +} + +#ifdef _FATFS_DEBUG_ +void fat_dumpdirentry(uint8_t *entry); +void fat_dumpdirentry(uint8_t *entry) +{ + uint8_t name[32]; + int idx; + + if (entry[11] != ATTRIB_LFN) { + memcpy(name,entry,11); + name[11] = 0; + xprintf("%s %02X %04X %d\n", + name,DIRENTRY_ATTRIB(entry), + DIRENTRY_STARTCLUSTER(entry), + DIRENTRY_FILELENGTH(entry)); + } + else { + for (idx = 0; idx < 5; idx++) { + name[idx] = entry[(idx*2)+1]; + } + for (idx = 0; idx < 6; idx++) { + name[idx+5] = entry[(idx*2)+14]; + } + for (idx = 0; idx < 2; idx++) { + name[idx+11] = entry[(idx*2)+28]; + } + name[13] = '\0'; + xprintf("%02X: %s %04X cksum %02X\n",entry[0], + name,READWORD(entry,0x1A),entry[13]); + } +} +#endif + + +/* ********************************************************************* + * fat_walkfatchain(fat,start,arg,func) + * + * Walk a FAT chain, calling a callback routine for each entry + * we find along the way. + * + * Input parameters: + * fat - FAT filesystem descriptor + * start - starting FAT entry (from the directory, usually) + * arg - argument to pass to callback routine + * func - function to call for each FAT entry + * + * Return value: + * 0 if all elements processed + * <0 if error occured + * >0 if callback routine returned a nonzero value + ********************************************************************* */ + +static int fat_walkfatchain(fatfs_t *fat,int start, + void *arg, + int (*func)(fatfs_t *fat, + int e, + int prev_e, + void *arg)) +{ + int prev_e = 0; + int ending_e; + int e; + int res = 0; + + e = start; + + /* Note: ending FAT entry can be 0x(F)FF8..0x(F)FFF. We assume that the + 'getfatentry' call won't return values above that. */ + if (fat->fat_twelvebit) { + ending_e = 0xFF8; + } + else { + ending_e = 0xFFF8; + } + + while (e < ending_e) { + res = (*func)(fat,e,prev_e,arg); + if (res) break; + prev_e = e; + e = fat_getfatentry(fat,e); + if (e < 0) return e; + } + + return res; +} + +/* ********************************************************************* + * fat_getwalkfunc(fat,e,prev_e,arg) + * + * Callback routien to collect all of the FAT entries into + * a FAT chain descriptor + * + * Input parameters: + * fat - FAT filesystem descriptor + * e - current entry + * prev_e - previous entry (0 if first entry) + * arg - argument passed to fat_walkfatchain + * + * Return value: + * 0 to keep walking + * else value to return from fat_walkfatchain + ********************************************************************* */ + +static int fat_getwalkfunc(fatfs_t *fat,int e, + int prev_e,void *arg) +{ + fatchain_t *chain = arg; + + if (chain->fat_entries) { + chain->fat_entries[chain->fat_count] = (uint16_t) e; + } + + chain->fat_count++; + + return 0; +} + +/* ********************************************************************* + * fat_getchain(fat,start,chain) + * + * Walk an entire FAT chain and remember the chain in a + * FAT chain descriptor + * + * Input parameters: + * fat - FAT filesystem descriptor + * start - starting FAT entry + * chain - chain descriptor + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_getchain(fatfs_t *fat,int start,fatchain_t *chain) +{ + int res; + + chain->fat_entries = NULL; + chain->fat_count = 0; + chain->fat_start = start; + + /* + * walk once to count the entries. + * + * For regular files, you probably don't have to do this + * since you can predict exactly how many FAT entries + * there are given the file length. + */ + + res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc); + if (res < 0) return res; + + /* + * allocate space for the entries. Include one extra + * slot for the first entry, since the first entry + * does not actually appear in the FAT (the fat is + * only the 'next' pointers). + */ + + if (chain->fat_count == 0) return 0; + chain->fat_entries = KMALLOC((chain->fat_count+1)*sizeof(uint16_t),0); + chain->fat_count = 0; + + /* + * walk again to collect entries + */ + res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc); + if (res < 0) return res; + + return chain->fat_count; +} + + +/* ********************************************************************* + * fat_freechain(chain) + * + * Free memory associated with a FAT chain + * + * Input parameters: + * chain - chain descriptor + * + * Return value: + * nothing + ********************************************************************* */ + +static void fat_freechain(fatchain_t *chain) +{ + if (chain->fat_entries) { + KFREE(chain->fat_entries); + chain->fat_entries = NULL; + } + chain->fat_count = 0; +} + +/* ********************************************************************* + * fat_clusteridx(fat,chain,idx) + * + * Index into a FAT chain and return the nth cluster number + * from the chain + * + * Input parameters: + * fat - fat filesystem descriptor + * chain - chain descriptor + * idx - index into FAT chain + * + * Return value: + * FAT entry at the nth index, or + * <0 if an error occured + ********************************************************************* */ +static int fat_clusteridx(fatfs_t *fat,fatchain_t *chain,int idx) +{ + if (idx >= chain->fat_count) return CFE_ERR_INV_PARAM; /* error! */ + return (int) (unsigned int) chain->fat_entries[idx]; +} + +/* ********************************************************************* + * fat_sectoridx(fat,chain,idx) + * + * Return the sector nunber of the nth sector in a given + * FAT chain. This routine knows how to translate cluster + * numbers into sector numbers. + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - FAT chain + * idx - index of which sector to find + * + * Return value: + * sector number + * <0 if an error occured + ********************************************************************* */ +static int fat_sectoridx(fatfs_t *fat,fatchain_t *chain,int idx) +{ + int clusteridx; + int sectoridx; + int sector; + int fatentry; + + clusteridx = idx / fat->fat_bpb.bpb_sectorspercluster; + sectoridx = idx % fat->fat_bpb.bpb_sectorspercluster; + + fatentry = fat_clusteridx(fat,chain,clusteridx); + + if (fatentry < 0) xprintf("ran off end of fat chain!\n"); + if (fatentry < 2) xprintf("fat entries should be >= 2\n"); + + sector = fat->fat_bpb.bpb_reservedsectors + + (fat->fat_bpb.bpb_maxrootdir * DIRENTRYSIZE)/SECTORSIZE + + (fat->fat_bpb.bpb_numfats * fat->fat_bpb.bpb_sectorsperfat) + + (fatentry - 2) * fat->fat_bpb.bpb_sectorspercluster + + sectoridx; + + return sector; +} + +/* ********************************************************************* + * fat_getsubdirentry(fat,chain,idx,direntry) + * + * This routine is similar to fat_getrootdirentry except it + * works on a subdirectory. FAT subdirectories are like files + * containing directory entries, so we use the "get nth sector + * in chain" routines to walk the chains of sectors reading directory + * entries. + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - FAT chain + * idx - index of entry to read + * direntry - place to put directory entry we read + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_getsubdirentry(fatfs_t *fat,fatchain_t *chain, + int idx,uint8_t *direntry) +{ + int sector; + int res; + + sector = fat_sectoridx(fat,chain,idx/DIRPERSECTOR); + + if (sector < 0) return sector; + + if (fat->fat_dirsecnum != sector) { + res = fat_readsector(fat,sector,1,fat->fat_dirsector); + if (res < 0) { + return res; + } + fat->fat_dirsecnum = sector; + } + + memcpy(direntry,&(fat->fat_dirsector[(idx % DIRPERSECTOR)*DIRENTRYSIZE]), + DIRENTRYSIZE); + + return 0; +} + +/* ********************************************************************* + * fat_getshortname(direntry,name) + * + * Read the short filename from a directory entry, converting + * it into its classic 8.3 form + * + * Input parameters: + * direntry - directory entry + * name - place to put 8.3 name + * + * Return value: + * nothing + ********************************************************************* */ + +static void fat_getshortname(uint8_t *direntry,char *name) +{ + int idx; + + /* + * Collect the base file name + */ + + for (idx = DIR_NAMEOFFSET; idx < (DIR_NAMEOFFSET+DIR_NAMELEN); idx++) { + if (direntry[idx] == ' ') break; + *name++ = direntry[idx]; + } + + /* + * Put in the dot for the extension only if there + * is an extension. + */ + + if (direntry[DIR_EXTOFFSET] != ' ') *name++ = '.'; + + /* + * Collect the extension + */ + + for (idx = DIR_EXTOFFSET; idx < (DIR_EXTOFFSET+DIR_EXTLEN); idx++) { + if (direntry[idx] == ' ') break; + *name++ = direntry[idx]; + } + + *name = '\0'; +} + + +/* ********************************************************************* + * fat_getlongname(fat,chain,diridx,shortentry,longname) + * + * Look backwards in the directory to locate the long file name + * that corresponds to the short file name passed in 'shortentry' + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - chain describing current directory, or NULL + * if the current directory is the root directory + * diridx - index of the short file name + * shortentry - points to the short directory entry + * longname - buffer to receive long file name (up to 261 chars) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_getlongname(fatfs_t *fat,fatchain_t *chain,int diridx, + uint8_t *shortentry,char *longname) +{ + int lfnidx = 1; + uint8_t checksum; + uint8_t direntry[DIRENTRYSIZE]; + int idx; + char *lfnptr; + int badlfn = 0; + + *longname = '\0'; + + /* + * idx is the entry # of the short name + */ + + checksum = fat_checksumname(shortentry); + + /* + * Start working backwards from current entry + * and collect pieces of the lfn + */ + + lfnptr = longname; + diridx--; + + while (diridx > 0) { + + /* + * Read previous entry + */ + + if (chain) { + fat_getsubdirentry(fat,chain,diridx,direntry); + } + else { + fat_getrootdirentry(fat,diridx,direntry); + } + + /* + * Checksum must match, it must have the right entry index, + * and it must have the LFN attribute + */ + + if (DIRENTRY_CHECKSUM(direntry) != checksum) { + badlfn = 1; + break; + } + if ((DIRENTRY_LFNIDX(direntry) & LFNIDX_MASK) != lfnidx) { + badlfn = 1; + break; + } + + if (DIRENTRY_ATTRIB(direntry) != ATTRIB_LFN) { + badlfn = 1; + break; + } + + /* + * Collect the chars from the filename. Note we + * don't deal well with real unicode chars here. + */ + + for (idx = 0; idx < 5; idx++) { + *lfnptr++ = direntry[(idx*2)+1]; + } + for (idx = 0; idx < 6; idx++) { + *lfnptr++ = direntry[(idx*2)+14]; + } + for (idx = 0; idx < 2; idx++) { + *lfnptr++ = direntry[(idx*2)+28]; + } + + /* + * Don't go too far + */ + + if (DIRENTRY_LFNIDX(direntry) & LFNIDX_END) break; + lfnidx++; + if (lfnidx > LFNIDX_MAX) { + badlfn = 1; + break; + } + + diridx--; + } + + /* + * Null terminate the lfn + */ + + *lfnptr = 0; + + if (badlfn) { + longname[0] = 0; + return CFE_ERR_FILENOTFOUND; + } + + return 0; +} + + +/* ********************************************************************* + * fat_scandir(fat,chain,name,direntry) + * + * Scan a single directory looking for a file name + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - FAT chain for directory or NULL for root directory + * name - name of file to look for (short or long name) + * direntry - place to put directory entry if we find one + * + * Return value: + * 1 if name was found + * 0 if name was not found + * else <0 is error code + ********************************************************************* */ + + +static int fat_scandir(fatfs_t *fat,fatchain_t *chain, + char *name,uint8_t *direntry) +{ + int idx; + int count; + char shortname[16]; + char longname[280]; + + /* + * Get directory size + */ + + if (chain) { + count = (chain->fat_count * fat->fat_bpb.bpb_sectorspercluster) * DIRPERSECTOR; + } + else { + count = (int) fat->fat_bpb.bpb_maxrootdir; + } + + /* + * Scan whole directory + */ + + for (idx = 0; idx < count; idx++) { + + /* + * Get entry by root or chain depending... + */ + + if (chain) { + fat_getsubdirentry(fat,chain,idx,direntry); + } + else { + fat_getrootdirentry(fat,idx,direntry); + } + + /* + * Ignore stuff we don't want to see + */ + + if (direntry[0] == DIRENTRY_LAST) break; /* stop if at end of dir */ + if (direntry[0] == DIRENTRY_DELETED) continue; /* skip deleted entries */ + if (direntry[0] == DIRENTRY_PARENTDIR) continue; /* skip ./.. entries */ + + if (DIRENTRY_ATTRIB(direntry) == ATTRIB_LFN) continue; /* skip LFNs */ + if (DIRENTRY_ATTRIB(direntry) & ATTRIB_LABEL) continue; /* skip volume labels */ + + /* + * Get actual file names from directory + */ + + fat_getshortname(direntry,shortname); + fat_getlongname(fat,chain,idx,direntry,longname); + + + if (name) { + if (strcmpi(name,shortname) == 0) return 1; + if (longname[0] && (strcmpi(name,longname) == 0)) return 1; + } + else { + xprintf("%-30s",longname[0] ? longname : shortname); +// xprintf(" Clus=%04X",DIRENTRY_STARTCLUSTER(direntry)); +// xprintf(" Attrib=%02X",DIRENTRY_ATTRIB(direntry)); +// xprintf(" Size=%d",DIRENTRY_FILELENGTH(direntry)); + xprintf("%d",DIRENTRY_FILELENGTH(direntry)); + xprintf("\n"); + } + } + + return 0; +} + +/* ********************************************************************* + * fat_findfile(fat,name,direntry) + * + * Locate a directory entry given a complete path name + * + * Input parameters: + * fat - FAT filesystem descriptor + * name - name of file to locate (forward or reverse slashses ok) + * direntry - place to put directory entry we find + * + * Return value: + * 0 if file not found + * 1 if file was found + * <0 if error occurs + ********************************************************************* */ + +static int fat_findfile(fatfs_t *fat,char *name,uint8_t *direntry) +{ + char *namecopy; + char *namepart; + char *ptr; + fatchain_t chain; + int res; + int e; + + /* + * Copy the name, we're going to hack it up + */ + + namecopy = strdup(name); + + /* + * Chew off the first piece up to the first slash. Remove + * a leading slash if it is there. + */ + + ptr = namecopy; + + if ((*ptr == '/') || (*ptr == '\\')) ptr++; + + namepart = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; + if (*ptr) *ptr++ = '\0'; + + /* + * Scan the root directory looking for the first piece + */ + + res = fat_scandir(fat,NULL,namepart,direntry); + if (res == 0) { + KFREE(namecopy); + return 0; /* file not found */ + } + + + /* + * Start scanning subdirectories until we run out + * of directory components. + */ + + namepart = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; + if (*ptr) *ptr++ = '\0'; + if (!*namepart) namepart = NULL; + + + while (namepart) { + + /* + * Scan the subdirectory + */ + + e = DIRENTRY_STARTCLUSTER(direntry); + memset(&chain,0,sizeof(chain)); + fat_getchain(fat,e,&chain); + res = fat_scandir(fat,&chain,namepart,direntry); + if (res == 0) { + break; + } + fat_freechain(&chain); + + /* + * Advance to the next piece + */ + + namepart = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; + if (*ptr) *ptr++ = '\0'; + if (!*namepart) namepart = NULL; + + /* + * If there's more to go and we hit something that + * is not a directory, stop here. + */ + + if (namepart && !(DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) { + res = 0; + } + } + + KFREE(namecopy); + + /* + * The last piece we enumerate has to be a file. + */ + + if ((res > 0) && + (DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) { + return 0; + } + + return res; +} + + +/* ********************************************************************* + * fat_init(fat,name) + * + * Create the filesystem descriptor and attach to the hardware + * device. + * + * Input parameters: + * fat - filesystem descriptor + * name - hardware device name + * part - true to look for partition tables + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_init(fatfs_t *fat,char *name,int part) +{ + int res; + + memset(fat,0,sizeof(fatfs_t)); + fat->fat_dirsecnum = -1; + fat->fat_fatsecnum = -1; + + fat->fat_fh = cfe_open(name); + + if (fat->fat_fh < 0) return fat->fat_fh; + + res = fatfs_check_for_partition_table(fat); + /* If we were able to figure it out, use that as the default */ + if (res >= 0) part = res; + + if (part) { + res = fat_findpart(fat); + if (res < 0) { + cfe_close(fat->fat_fh); + fat->fat_fh = -1; + return res; + } + } + + res = fat_readbpb(fat); + if (res != 0) { + cfe_close(fat->fat_fh); + fat->fat_fh = -1; + return res; + } + + return 0; +} + +/* ********************************************************************* + * fat_uninit(fat) + * + * Uninit the filesystem descriptor and release any resources + * we allocated. + * + * Input parameters: + * fat - filesystem descriptor + * + * Return value: + * nothing + ********************************************************************* */ + +static void fat_uninit(fatfs_t *fat) +{ + if (fat->fat_fh >= 0) cfe_close(fat->fat_fh); + fat->fat_fh = -1; +} + +int fatfs_fileop_dir(void *fsctx); +int fatfs_fileop_dir(void *fsctx) +{ + fatfs_t *fatfs = fsctx; + uint8_t direntry[32]; + + fat_scandir(fatfs,NULL,NULL,direntry); + + return 0; +} + +/* ********************************************************************* + * fatfs_fileop_init(fsctx,devname) + * + * Create a FAT filesystem context and open the associated + * block device. + * + * Input parameters: + * fsctx - file system context (return pointer) + * devname - device name to open + * part - true to look for a partition table + * + * Return value: + * 0 if ok, else error + ********************************************************************* */ + +static int fatfs_fileop_init(void **fsctx,char *devname,int part) +{ + int res; + fatfs_t *fatfs; + + /* + * Allocate a file system context + */ + + fatfs = (fatfs_t *) KMALLOC(sizeof(fatfs_t),0); + if (!fatfs) return CFE_ERR_NOMEM; + + /* + * Open a handle to the underlying device + */ + + res = fat_init(fatfs,devname,part); + if (res != 0) { + KFREE(fatfs); + return res; + } + + *fsctx = fatfs; + + return 0; +} + +/* ********************************************************************* + * fatfs_check_for_partition_table(fatfs) + * + * This routine attempts to determine if the disk contains a + * partition table or if it contains a standard MS-DOS boot recod. + * We try to find both, and return what we find, or an error + * if it is still unclear. + * + * Input parameters: + * fatfs - fat filesystem context + * + * Return value: + * 0 if no partition table + * 1 if partition table + * <0 = error occured, could not tell or I/O error + ********************************************************************* */ + +static int fatfs_check_for_partition_table(fatfs_t *fatfs) +{ + int res; + uint8_t buffer[SECTORSIZE]; + uint8_t *part; + int idx; + int foundit = 0; + + /* + * Read sector 0 + */ + + fatfs->fat_partstart = 0; + res = fat_readsector(fatfs,0,1,buffer); + if (res < 0) return res; + + /* + * Check the seal at the end of th sector. Both + * boot sector and MBR should contain this seal. + */ + if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) { + res = CFE_ERR_BADFILESYS; + return res; + } + + /* + * See Microsoft Knowledgebase article # Q140418, it contains + * a good description of the boot sector format. + * + * If the extended information is present, and SystemID is "FAT" + * and the "bytes per sector" is 512, assume it's a regular boot block + */ + + if (((buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE1) || + (buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE2)) && + (memcmp(&buffer[BPB_SYSTEMID],"FAT",3) == 0) && + (READWORD(buffer,BPB_BYTESPERSECTOR) == 512)) { + /* Not partitioned */ + res = 0; + return res; + } + + /* If no extended information is present, check a few other key values. */ + + if ((READWORD(buffer,BPB_BYTESPERSECTOR) == 512) && + (READWORD(buffer,BPB_RESERVEDSECTORS) >= 1) && + ((READWORD(buffer,BPB_MEDIADESCRIPTOR) & 0xF0) == 0xF0)) { + res = 0; + return res; + } + + /* + * If we're still confused, look for a partition table with a valid FAT + * partition on it. We might not detect a partition table that has + * only non-FAT partitions on it, like a disk with all Linux partitions, + * but that is fine here in the FATFS module, since we only want to + * find FAT partitions anyway. + */ + part = &buffer[PTABLE_OFFSET]; + for (idx = 0; idx < PTABLE_COUNT; idx++) { + + if (((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) || + (part[PTABLE_STATUS] == 0x00)) && + ((part[PTABLE_TYPE] == PARTTYPE_FAT12) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) { + foundit = 1; + res = 1; /*Partition table present*/ + break; + } + part += PTABLE_SIZE; + } + + /* + * If at this point we did not find what we were looking for, + * return an error. + */ + if (foundit) { + res = 1; /*Partition table is present.*/ + } + else { + /*Error! We can't decide if partition table exists or not*/ + res = CFE_ERR_BADFILESYS; + } + + return res; +} + +static int fatfs_fileop_xinit(void **fsctx,void *dev) +{ + char *devname = (char *) dev; + + return fatfs_fileop_init(fsctx,devname,0); +} + +static int fatfs_fileop_pinit(void **fsctx,void *dev) +{ + char *devname = (char *) dev; + + return fatfs_fileop_init(fsctx,devname,1); +} + + + +/* ********************************************************************* + * fatfs_fileop_open(ref,name) + * + * Open a file on the FAT device. + * + * Input parameters: + * ref - place to store pointer to fileinfo + * fsctx - filesystem context + * name - name of file to open + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fatfs_fileop_open(void **ref,void *fsctx,char *name,int mode) +{ + int res; + uint8_t direntry[DIRENTRYSIZE]; + fatfile_t *ff; + fatfs_t *fatfs; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fatfs = (fatfs_t *) fsctx; + + ff = (fatfile_t *) KMALLOC(sizeof(fatfile_t),0); + if (ff == NULL) return CFE_ERR_NOMEM; + + memset(ff,0,sizeof(fatfile_t)); + + ff->ff_fat = fatfs; + + res = fat_findfile(ff->ff_fat,name,direntry); + if (res <= 0) { + return CFE_ERR_FILENOTFOUND; /* not found */ + } + + /* + * Okay, the file was found. Enumerate the FAT chain + * associated with this file. + */ + + ff->ff_filelength = DIRENTRY_FILELENGTH(direntry); + + ff->ff_curpos = 0; + ff->ff_cursector = -1; + + res = fat_getchain(ff->ff_fat, + DIRENTRY_STARTCLUSTER(direntry), + &(ff->ff_chain)); + + if (res < 0) { + KFREE(ff); + return res; + } + + /* + * Return the file handle + */ + + + fatfs->fat_refcnt++; + *ref = (void *) ff; + return 0; +} + + +/* ********************************************************************* + * fatfs_fileop_close(ref) + * + * Close the file. + * + * Input parameters: + * ref - pointer to open file information + * + * Return value: + * nothing + ********************************************************************* */ + +static void fatfs_fileop_close(void *ref) +{ + fatfile_t *file = (fatfile_t *) ref; + fatfs_t *fatctx = file->ff_fat; + + fatctx->fat_refcnt--; + + fat_freechain(&(file->ff_chain)); + KFREE(file); +} + + +/* ********************************************************************* + * fatfs_fileop_uninit(ref) + * + * Uninitialize the file system. + * + * Input parameters: + * fsctx - filesystem context + * + * Return value: + * nothing + ********************************************************************* */ +static void fatfs_fileop_uninit(void *fsctx) +{ + fatfs_t *fatctx = (fatfs_t *) fsctx; + + if (fatctx->fat_refcnt) { + xprintf("fatfs_fileop_unint: warning: refcnt should be zero\n"); + } + + fat_uninit(fatctx); + + KFREE(fatctx); +} + + +/* ********************************************************************* + * fatfs_fileop_seek(ref,offset,how) + * + * Move the file pointer within the file + * + * Input parameters: + * ref - pointer to open file information + * offset - new file location or distance to move + * how - method for moving + * + * Return value: + * new file offset + * <0 if error occured + ********************************************************************* */ + +static int fatfs_fileop_seek(void *ref,int offset,int how) +{ + fatfile_t *file = (fatfile_t *) ref; + + switch (how) { + case FILE_SEEK_BEGINNING: + file->ff_curpos = offset; + break; + case FILE_SEEK_CURRENT: + file->ff_curpos += offset; + break; + default: + break; + } + + if (file->ff_curpos >= file->ff_filelength) { + file->ff_curpos = file->ff_filelength; + } + + return file->ff_curpos; +} + + +/* ********************************************************************* + * fatfs_fileop_read(ref,buf,len) + * + * Read data from the file. + * + * Input parameters: + * ref - pointer to open file information + * buf - buffer to read data into + * len - number of bytes to read + * + * Return value: + * number of bytes read + * <0 if error occured + * 0 means eof + ********************************************************************* */ + +static int fatfs_fileop_read(void *ref,uint8_t *buf,int len) +{ + fatfile_t *file = (fatfile_t *) ref; + int amtcopy; + int ttlcopy = 0; + int offset; + int sector; + int secidx; + int origpos; + int res; + uint8_t temp_buf[SECTORSIZE]; + + /* + * Remember orig position in case we have an error + */ + + origpos = file->ff_curpos; + + /* + * bounds check the length based on the file length + */ + + if ((file->ff_curpos + len) > file->ff_filelength) { + len = file->ff_filelength - file->ff_curpos; + } + + res = 0; + + /* + * while ther is still data to be transferred + */ + + + while (len) { + + /* + * Calculate the sector offset and index in the sector + */ + + offset = file->ff_curpos % SECTORSIZE; + secidx = file->ff_curpos / SECTORSIZE; + + sector = fat_sectoridx(file->ff_fat,&(file->ff_chain),secidx); + + if (sector < 0) { + xprintf("should not happen, sector = -1!\n"); + return sector; + } + + /* + * first transfer up to the sector boundary + */ + + amtcopy = len; + if (amtcopy > (SECTORSIZE-offset)) { + amtcopy = (SECTORSIZE-offset); + } + + /* + * If transferring exactly a sector, on a sector + * boundary, read the data directly into the user buffer + * + * Extra credit: See if we can transfer more than one + * sector at a time, by determining if we can read a run of + * contiguous sectors (very likely) + * + * Otherwise: read into the sector buffer and + * transfer the data to user memory. + */ + + if ((offset == 0) && (amtcopy == SECTORSIZE)) { + res = fat_readsector(file->ff_fat,sector,1,temp_buf); + if (res < 0) { + xprintf("I/O error!\n"); + break; + } + memcpy(buf,temp_buf,amtcopy); + } + else { + if (file->ff_cursector != sector) { + res = fat_readsector(file->ff_fat,sector,1,file->ff_sector); + if (res < 0) { + break; + } + file->ff_cursector = sector; + } + memcpy(buf,&(file->ff_sector[offset]),amtcopy); + } + + /* + * Adjust/update all our pointers. + */ + + buf += amtcopy; + file->ff_curpos += amtcopy; + ttlcopy += amtcopy; + len -= amtcopy; + + /* + * see if we ran off the end of the file. Should not + * be necessary. + */ + + if (file->ff_curpos >= file->ff_filelength) { + /* should not be necessary */ + break; + } + } + + /* + * If an error occured, get out now. + */ + + if (res < 0) { + file->ff_curpos = origpos; + return res; + } + + return ttlcopy; + +} + +static int fatfs_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + + +#if 0 + +void main(int argc,char *argv[]) +{ + fatfs_t fat; + int idx; + unsigned int e; + uint8_t direntry[DIRENTRYSIZE]; + fatchain_t chain; + int res; + + + fat_init(&fat,"floppy.raw"); + + + if (fat_readbpb(&fat) == 0) { + fat_dumpbpb(&fat.fat_bpb); + } + +#if 0 + for (idx = 0; idx < (int) fat.fat_bpb.bpb_maxrootdir; idx++) { + fat_getrootdirentry(&fat,idx,direntry); + if (direntry[0] == 0) break; + if (direntry[0] == 0xE5) continue; + xprintf("%3d: ",idx); + fat_dumpdirentry(direntry); + } +#endif + + fat_scandir(&fat,NULL,NULL,direntry); + + for (e = 0x150; e < 0x160; e++) { + xprintf("Entry %03X is %03X\n",e,fat_getfatentry(&fat,e)); + } + +#if 0 + e = 0x36E; + while (e != 0xFFF) { + e = fat_getfatentry(&fat,e); + xprintf("%03X ",e); + } +#endif + + + xprintf("\n\n"); + e = 0x36E; + memset(&chain,0,sizeof(chain)); + fat_getchain(&fat,e,&chain); + fat_scandir(&fat,&chain,NULL,direntry); + fat_freechain(&chain); + + xprintf("\n\n"); + e = 0x36F; + memset(&chain,0,sizeof(chain)); + fat_getchain(&fat,e,&chain); + fat_scandir(&fat,&chain,NULL,direntry); + fat_freechain(&chain); + + xprintf("\n\n"); + e = 0x370; + memset(&chain,0,sizeof(chain)); + fat_getchain(&fat,e,&chain); + fat_scandir(&fat,&chain,NULL,direntry); + fat_freechain(&chain); + + xprintf("\n\n"); + + res = fat_findfile(&fat,argc > 1 ? argv[1] : "/usr/local/include/ansidecl.h",direntry); + xprintf("res = %d\n",res); + + if (res) fat_dumpdirentry(direntry); + + close(fat.fat_fh); +} + +void main(int argc,char *argv[]) +{ + void *ref; + int res; + char buffer[257]; + int total = 0; + +// res = fatfs_fileop_open(&ref,"floppy.raw:/usr/local/include/bfdlink.h"); + res = fatfs_fileop_open(&ref,"floppy.raw:/idedrv.h"); + + if (res != 0) { + xprintf("Could not open file: %d\n",res); + exit(1); + } + + for (;;) { + res = fatfs_fileop_read(ref,buffer,39); +// xprintf("read returned %d\n",res); + if (res <= 0) break; + + if (res > 0) { + total += res; + buffer[res] = 0; + xprintf("%s",buffer); + } + } + + if (res < 0) xprintf("error! \n"); + + xprintf("[total %d]\n",total); + + fatfs_fileop_close(ref); + + exit(0); + +} + +#endif diff --git a/cfe/cfe/main/cfe_filesys.c b/cfe/cfe/main/cfe_filesys.c new file mode 100755 index 0000000..569d7bc --- /dev/null +++ b/cfe/cfe/main/cfe_filesys.c @@ -0,0 +1,343 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Filesystem manager File: cfe_filesys.c + * + * This module maintains the list of available file systems. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" + +#include "cfe.h" + +#include "bsp_config.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern const fileio_dispatch_t raw_fileops; +#if CFG_NETWORK +extern const fileio_dispatch_t tftp_fileops; +#if (CFG_TCP) && (CFG_HTTPFS) +extern const fileio_dispatch_t http_fileops; +#endif +#endif +#if CFG_FATFS +extern const fileio_dispatch_t fatfs_fileops; +extern const fileio_dispatch_t pfatfs_fileops; +#endif +#if CFG_ZLIB +extern const fileio_dispatch_t zlibfs_fileops; +#endif + +/* ********************************************************************* + * File system list + ********************************************************************* */ + +static const fileio_dispatch_t * const cfe_filesystems[] = { +#if !defined(CONFIG_MIPS_BRCM) + &raw_fileops, +#endif +#if CFG_NETWORK + &tftp_fileops, +#if (CFG_TCP) & (CFG_HTTPFS) + &http_fileops, +#endif +#endif +#if CFG_FATFS + &fatfs_fileops, + &pfatfs_fileops, +#endif +#if CFG_ZLIB + &zlibfs_fileops, +#endif + NULL +}; + +/* ********************************************************************* + * cfe_findfilesys(name) + * + * Locate the dispatch record for a particular file system. + * + * Input parameters: + * name - name of filesys to locate + * + * Return value: + * pointer to dispatch table or NULL if not found + ********************************************************************* */ + +const fileio_dispatch_t *cfe_findfilesys(const char *name) +{ + const fileio_dispatch_t * const *disp; + + disp = cfe_filesystems; + + while (*disp) { + if (strcmp((*disp)->method,name) == 0) return *disp; + disp++; + } + + return NULL; +} + +/* ********************************************************************* + * fs_init(name,fsctx,device) + * + * Initialize a filesystem context + * + * Input parameters: + * name - name of file system + * fsctx - returns a filesystem context + * device - device name or other info + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +int fs_init(char *fsname,fileio_ctx_t **fsctx,void *device) +{ + fileio_ctx_t *ctx; + int res; + const fileio_dispatch_t *ops; + + ops = cfe_findfilesys((const char *)fsname); + if (!ops) return CFE_ERR_FSNOTAVAIL; + + ctx = (fileio_ctx_t *) KMALLOC(sizeof(fileio_ctx_t),0); + if (!ctx) return CFE_ERR_NOMEM; + + ctx->ops = ops; + res = BDINIT(ops,&(ctx->fsctx),device); + + if (res != 0) { + KFREE(ctx); + } + + *fsctx = ctx; + + return res; +} + + +/* ********************************************************************* + * fs_hook(fsctx,name) + * + * "Hook" a filesystem to attach a filter, like a decompression + * or decryption engine. + * + * Input parameters: + * fsctx - result from a previous fs_init + * name - name of fs to hook onto the beginning + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +int fs_hook(fileio_ctx_t *fsctx,char *fsname) +{ + void *hookfsctx; + const fileio_dispatch_t *ops; + int res; + + /* + * Find the hook filesystem (well, actually a filter) + */ + + ops = cfe_findfilesys((const char *)fsname); + if (!ops) return CFE_ERR_FSNOTAVAIL; + + /* + * initialize our hook file filter. + */ + + res = BDINIT(ops,&hookfsctx,fsctx); + if (res != 0) return res; + + /* + * Now replace dispatch table for current filesystem + * with the hook's dispatch table. When fs_read is called, + * we'll go to the hook, and the hook will call the original. + * + * When fs_uninit is called, the hook will call the original's + * uninit routine. + */ + + fsctx->ops = ops; + fsctx->fsctx = hookfsctx; + + return 0; + +} + +/* ********************************************************************* + * fs_uninit(fsctx) + * + * Uninitialize a file system context. + * + * Input parameters: + * fsctx - filesystem context to remove (from fs_init) + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ +int fs_uninit(fileio_ctx_t *fsctx) +{ + BDUNINIT(fsctx->ops,fsctx->fsctx); + + KFREE(fsctx); + + return 0; +} + + +/* ********************************************************************* + * fs_open(fsctx,ref,filename,mode) + * + * Open a file on the file system + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - returns file handle + * filename - name of file to open + * mode - file open mode + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +int fs_open(fileio_ctx_t *fsctx,void **ref,char *filename,int mode) +{ + return BDOPEN2(fsctx->ops,ref,fsctx->fsctx,filename,mode); +} + +/* ********************************************************************* + * fs_close(fsctx,ref) + * + * Close a file on the file system + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +int fs_close(fileio_ctx_t *fsctx,void *ref) +{ + BDCLOSE(fsctx->ops,ref); + + return 0; +} + + +/* ********************************************************************* + * fs_read(fsctx,ref,buffer,len) + * + * Read data from the device. + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * buffer - buffer pointer + * len - length + * + * Return value: + * number of bytes read + * 0=eof + * <0 = error + ********************************************************************* */ + +int fs_read(fileio_ctx_t *fsctx,void *ref,uint8_t *buffer,int len) +{ + return BDREAD(fsctx->ops,ref,buffer,len); +} + +/* ********************************************************************* + * fs_write(fsctx,ref,buffer,len) + * + * write data from the device. + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * buffer - buffer pointer + * len - length + * + * Return value: + * number of bytes written + * 0=eof + * <0 = error + ********************************************************************* */ + +int fs_write(fileio_ctx_t *fsctx,void *ref,uint8_t *buffer,int len) +{ + return BDWRITE(fsctx->ops,ref,buffer,len); +} + +/* ********************************************************************* + * fs_seek(fsctx,ref,offset,how) + * + * move file pointer on the device + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * offset - distance to move + * how - origin (FILE_SEEK_xxx) + * + * Return value: + * new offset + * <0 = error + ********************************************************************* */ + +int fs_seek(fileio_ctx_t *fsctx,void *ref,int offset,int how) +{ + return BDSEEK(fsctx->ops,ref,offset,how); +} diff --git a/cfe/cfe/main/cfe_httpfs.c b/cfe/cfe/main/cfe_httpfs.c new file mode 100644 index 0000000..4ebad4c --- /dev/null +++ b/cfe/cfe/main/cfe_httpfs.c @@ -0,0 +1,396 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "HTTP" file system File: cfe_httpfs.c + * + * This filesystem driver lets you read files from an HTTP + * server. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_console.h" + +#include "cfe.h" + +#include "bsp_config.h" + +#if (CFG_TCP) && (CFG_HTTPFS) + +#include "net_ebuf.h" +#include "net_api.h" + + +/* ********************************************************************* + * HTTP context + ********************************************************************* */ + +/* + * File system context - describes overall file system info, + * such as the handle to the underlying device. + */ + +typedef struct http_fsctx_s { + int http_tmp; /* context not really needed */ +} http_fsctx_t; + +/* + * File context - describes an open file on the file system. + */ + +#define HTTP_BUFSIZE 1024 +typedef struct http_file_s { + http_fsctx_t *http_fsctx; + int http_socket; + uint8_t http_buffer[HTTP_BUFSIZE]; + uint8_t *http_bptr; + int http_blen; + int http_offset; + char *http_filename; +} http_file_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int http_fileop_init(void **fsctx,void *devicename); +static int http_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int http_fileop_read(void *ref,uint8_t *buf,int len); +static int http_fileop_write(void *ref,uint8_t *buf,int len); +static int http_fileop_seek(void *ref,int offset,int how); +static void http_fileop_close(void *ref); +static void http_fileop_uninit(void *fsctx); + +/* ********************************************************************* + * RAW fileio dispatch table + ********************************************************************* */ + +const fileio_dispatch_t http_fileops = { + "http", + FSYS_TYPE_NETWORK, + http_fileop_init, + http_fileop_open, + http_fileop_read, + http_fileop_write, + http_fileop_seek, + http_fileop_close, + http_fileop_uninit +}; + +static int http_fileop_init(void **newfsctx,void *dev) +{ + http_fsctx_t *fsctx; + + *newfsctx = NULL; + + fsctx = KMALLOC(sizeof(http_fsctx_t),0); + if (!fsctx) { + return CFE_ERR_NOMEM; + } + + fsctx->http_tmp = 0; + *newfsctx = fsctx; + + return 0; +} + +static int http_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) +{ + http_fsctx_t *fsctx; + http_file_t *file; + char temp[200]; + char *hostname, *filen; + int hlen; + int termidx; + int res; + int err = 0; + char *hptr; + char *tok; + uint8_t hostaddr[IP_ADDR_LEN]; + uint8_t termstr[4]; + uint8_t b; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fsctx = (http_fsctx_t *) fsctx_arg; + + file = KMALLOC(sizeof(http_file_t),0); + if (!file) { + return CFE_ERR_NOMEM; + } + + file->http_filename = lib_strdup(filename); + if (!file->http_filename) { + KFREE(file); + return CFE_ERR_NOMEM; + } + + lib_chop_filename(file->http_filename,&hostname,&filen); + + /* + * Look up remote host + */ + + res = dns_lookup(hostname,hostaddr); + if (res < 0) { + KFREE(file); + return res; + } + + file->http_socket = tcp_socket(); + if (file->http_socket < 0) { + KFREE(file->http_filename); + KFREE(file); + return -1; + } + + /* + * Connect to remote host. + */ + + tcp_setflags(file->http_socket,0); /* set socket to blocking */ + res = tcp_connect(file->http_socket,hostaddr,80); + + if (res < 0) { + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + return res; + } + + /* + * Send GET command. Supply the hostname (for HTTP 1.1 requirements) + * and set the connection to close as soon as all the data is received. + */ + + hlen = sprintf(temp,"GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",filen,hostname); + + res = tcp_send(file->http_socket,temp,hlen); + if (res < 0) { + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + return res; + } + + /* + * Read bytes until we either reach EOF or we see "\r\n\r\n" + * This is the server's status string. + */ + + termstr[0] = '\r'; termstr[1] = '\n'; + termstr[2] = '\r'; termstr[3] = '\n'; + termidx = 0; + + file->http_offset = 0; + file->http_blen = 0; + file->http_bptr = file->http_buffer; + + res = 0; + for (;;) { + res = tcp_recv(file->http_socket,&b,1); + if (res < 0) break; + if (b == termstr[termidx]) { + termidx++; + if (termidx == 4) break; + } + else { + termidx = 0; + } + + /* + * Save the bytes from the header up to our buffer + * size. It's okay if we don't save it all, + * since all we want is the result code which comes + * first. + */ + + if (file->http_blen < (HTTP_BUFSIZE-1)) { + *(file->http_bptr) = b; + file->http_bptr++; + file->http_blen++; + } + } + + /* + * Premature EOFs are not good, bail now. + */ + + if (res < 0) { + err = CFE_ERR_EOF; + goto protocolerr; + } + + /* + * Skip past the HTTP response header and grab the result code. + * Sanity check it a little. + */ + + *(file->http_bptr) = 0; + + hptr = file->http_buffer; + tok = lib_gettoken(&hptr); + if (!tok || (memcmp(tok,"HTTP",4) != 0)) { + err = CFE_ERR_PROTOCOLERR; + goto protocolerr; + } + + tok = lib_gettoken(&hptr); + if (!tok) { + err = CFE_ERR_PROTOCOLERR; + goto protocolerr; + } + + switch (lib_atoi(tok)) { + case 200: + err = 0; + break; + case 404: + err = CFE_ERR_FILENOTFOUND; + break; + + } + + /* + * If we get to here, the file is okay and we're about to receive data. + */ + + if (err == 0) { + *ref = file; + return 0; + } + +protocolerr: + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + *ref = NULL; + return err; +} + +static int http_fileop_read(void *ref,uint8_t *buf,int len) +{ + http_file_t *file = (http_file_t *) ref; + int res; + + res = tcp_recv(file->http_socket,buf,len); + + if (res > 0) { + file->http_offset += res; + return res; + } + + return 0; /* Any error becomes "EOF" */ +} + +static int http_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + +static int http_fileop_seek(void *ref,int offset,int how) +{ + http_file_t *file = (http_file_t *) ref; + int newoffset; + int res; + int buflen; + + switch (how) { + case FILE_SEEK_BEGINNING: + newoffset = offset; + break; + case FILE_SEEK_CURRENT: + newoffset = file->http_offset + offset; + break; + default: + newoffset = offset; + break; + } + + /* + * Can't seek backwards. + */ + if (newoffset < file->http_offset) { + return CFE_ERR_UNSUPPORTED; + } + + /* + * Eat data till offset reaches where we want. + */ + + while (file->http_offset != newoffset) { + buflen = HTTP_BUFSIZE; + if (buflen > (newoffset - file->http_offset)) buflen = (newoffset-file->http_offset); + res = tcp_recv(file->http_socket,file->http_buffer,buflen); + if (res < 0) break; + file->http_offset += res; + } + + return file->http_offset; +} + + +static void http_fileop_close(void *ref) +{ + http_file_t *file = (http_file_t *) ref; + + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); +} + +static void http_fileop_uninit(void *fsctx_arg) +{ + http_fsctx_t *fsctx = (http_fsctx_t *) fsctx_arg; + + KFREE(fsctx); +} + +#endif diff --git a/cfe/cfe/main/cfe_iocb_dispatch.c b/cfe/cfe/main/cfe_iocb_dispatch.c new file mode 100755 index 0000000..24aea0a --- /dev/null +++ b/cfe/cfe/main/cfe_iocb_dispatch.c @@ -0,0 +1,647 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB dispatcher File: cfe_iocb_dispatch.c + * + * This routine is the main API dispatch for CFE. User API + * calls, via the ROM entry point, get dispatched to routines + * in this module. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_error.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_mem.h" +#include "cfe_fileops.h" +#include "cfe_boot.h" +#include "env_subr.h" +#include "cfe.h" +#include "cfe_console.h" +#include "bsp_config.h" +#include "initdata.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define HV 1 /* handle valid */ + +#ifndef CFG_BOARD_ID +#define CFG_BOARD_ID 0 +#endif + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +cfe_devctx_t *cfe_handle_table[CFE_MAX_HANDLE]; + +extern void _cfe_flushcache(int); + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int cfe_iocb_dispatch(cfe_iocb_t *iocb); +void cfe_device_poll(void *); + +#if CFG_MULTI_CPUS +extern int altcpu_cmd_start(uint64_t,uint64_t *); +extern int altcpu_cmd_stop(uint64_t); +#endif + +/* ********************************************************************* + * Dispatch table + ********************************************************************* */ + +struct cfe_cmd_dispatch_s { + int plistsize; + int flags; + int (*func)(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +}; + + +static int cfe_cmd_fw_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_restart(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_boot(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_cpuctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_gettime(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_memenum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_flushcache(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +static int cfe_cmd_dev_gethandle(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_open(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_inpstat(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_read(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_write(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_ioctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_close(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +static int cfe_cmd_env_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_get(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_set(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_del(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +const static struct cfe_cmd_dispatch_s cfe_cmd_dispatch_table[CFE_CMD_MAX] = { + {sizeof(iocb_fwinfo_t), 0, cfe_cmd_fw_getinfo}, /* 0 : CFE_CMD_FW_GETINFO */ + {sizeof(iocb_exitstat_t),0, cfe_cmd_fw_restart}, /* 1 : CFE_CMD_FW_RESTART */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_fw_boot}, /* 2 : CFE_CMD_FW_BOOT */ + {sizeof(iocb_cpuctl_t), 0, cfe_cmd_fw_cpuctl}, /* 3 : CFE_CMD_FW_CPUCTL */ + {sizeof(iocb_time_t), 0, cfe_cmd_fw_gettime}, /* 4 : CFE_CMD_FW_GETTIME */ + {sizeof(iocb_meminfo_t),0, cfe_cmd_fw_memenum}, /* 5 : CFE_CMD_FW_MEMENUM */ + {0, 0, cfe_cmd_fw_flushcache}, /* 6 : CFE_CMD_FW_FLUSHCACHE */ + {-1, 0, NULL}, /* 7 : */ + {-1, 0, NULL}, /* 8 : */ + {0, 0, cfe_cmd_dev_gethandle}, /* 9 : CFE_CMD_DEV_GETHANDLE */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_dev_enum}, /* 10 : CFE_CMD_DEV_ENUM */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_dev_open}, /* 11 : CFE_CMD_DEV_OPEN */ + {sizeof(iocb_inpstat_t),HV, cfe_cmd_dev_inpstat}, /* 12 : CFE_CMD_DEV_INPSTAT */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_read}, /* 13 : CFE_CMD_DEV_READ */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_write}, /* 14 : CFE_CMD_DEV_WRITE */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_ioctl}, /* 15 : CFE_CMD_DEV_IOCTL */ + {0, HV, cfe_cmd_dev_close}, /* 16 : CFE_CMD_DEV_CLOSE */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_dev_getinfo}, /* 17 : CFE_CMD_DEV_GETINFO */ + {-1, 0, NULL}, /* 18 : */ + {-1, 0, NULL}, /* 19 : */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_enum}, /* 20 : CFE_CMD_ENV_ENUM */ + {-1, 0, NULL}, /* 21 : */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_get}, /* 22 : CFE_CMD_ENV_GET */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_set}, /* 23 : CFE_CMD_ENV_SET */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_del}, /* 24 : CFE_CMD_ENV_DEL */ + {-1, 0, NULL}, /* 25 : */ + {-1, 0, NULL}, /* 26 : */ + {-1, 0, NULL}, /* 27 : */ + {-1, 0, NULL}, /* 28 : */ + {-1, 0, NULL}, /* 29 : */ + {-1, 0, NULL}, /* 30 : */ + {-1, 0, NULL} /* 31 : */ +}; + +/* ********************************************************************* + * IOCB dispatch routines + ********************************************************************* */ + +void cfe_device_poll(void *x) +{ + int idx; + cfe_devctx_t **ctx = cfe_handle_table; + + for (idx = 0; idx < CFE_MAX_HANDLE; idx++,ctx++) { + if ((*ctx) && ((*ctx)->dev_dev->dev_dispatch->dev_poll)) { + (*ctx)->dev_dev->dev_dispatch->dev_poll(*ctx,cfe_ticks); + } + } +} + +int cfe_iocb_dispatch(cfe_iocb_t *iocb) +{ + const struct cfe_cmd_dispatch_s *disp; + int res; + cfe_devctx_t *ctx; + + /* + * Check for commands codes out of range + */ + + if ((iocb->iocb_fcode < 0) || (iocb->iocb_fcode >= CFE_CMD_MAX)) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for command codes in range but invalid + */ + + disp = &cfe_cmd_dispatch_table[iocb->iocb_fcode]; + + if (disp->plistsize < 0) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for invalid parameter list size + */ + + if (disp->plistsize != iocb->iocb_psize) { + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + + /* + * Determine handle + */ + + ctx = NULL; + if (disp->flags & HV) { + if ((iocb->iocb_handle >= CFE_MAX_HANDLE) || + (iocb->iocb_handle < 0) || + (cfe_handle_table[iocb->iocb_handle] == NULL)){ + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + ctx = cfe_handle_table[iocb->iocb_handle]; + } + + /* + * Dispatch to handler routine + */ + + res = (*disp->func)(ctx,iocb); + + iocb->iocb_status = res; + return res; +} + +static int cfe_newhandle(void) +{ + int idx; + + for (idx = 0; idx < CFE_MAX_HANDLE; idx++) { + if (cfe_handle_table[idx] == NULL) break; + } + + if (idx == CFE_MAX_HANDLE) return -1; + + return idx; +} + + +/* ********************************************************************* + * Implementation routines for each IOCB function + ********************************************************************* */ + +static int cfe_cmd_fw_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + iocb_fwinfo_t *info = &iocb->plist.iocb_fwinfo; + + info->fwi_version = (CFE_VER_MAJOR << 16) | + (CFE_VER_MINOR << 8) | + (CFE_VER_BUILD); + info->fwi_totalmem = ((cfe_int64_t) mem_totalsize) << 20; + info->fwi_flags = +#ifdef __long64 + CFE_FWI_64BIT | +#else + CFE_FWI_32BIT | +#endif +#if (CFG_EMBEDDED_PIC) + CFE_FWI_RELOC | +#endif +#if (!CFG_RUNFROMKSEG0) + CFE_FWI_UNCACHED | +#endif +#if CFG_MULTI_CPUS + CFE_FWI_MULTICPU | +#endif +#ifdef _VERILOG_ + CFE_FWI_RTLSIM | +#endif +#ifdef _FUNCSIM_ + CFE_FWI_FUNCSIM | +#endif + 0; + + info->fwi_boardid = CFG_BOARD_ID; + info->fwi_bootarea_pa = (cfe_int64_t) mem_bootarea_start; + info->fwi_bootarea_va = BOOT_START_ADDRESS; + info->fwi_bootarea_size = (cfe_int64_t) mem_bootarea_size; + info->fwi_reserved1 = 0; + info->fwi_reserved2 = 0; + info->fwi_reserved3 = 0; + + return CFE_OK; +} + +static int cfe_cmd_fw_restart(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + if (iocb->iocb_flags & CFE_FLG_WARMSTART) { + cfe_warmstart(iocb->plist.iocb_exitstat.status); + } + else { + cfe_restart(); + } + + /* should not get here */ + + return CFE_OK; +} + +static int cfe_cmd_fw_boot(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + return CFE_ERR_INV_COMMAND; /* not implemented yet */ +} + +static int cfe_cmd_fw_cpuctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ +#if CFG_MULTI_CPUS + int res; + uint64_t startargs[4]; + + switch (iocb->plist.iocb_cpuctl.cpu_command) { + case CFE_CPU_CMD_START: + + startargs[0] = iocb->plist.iocb_cpuctl.start_addr; + startargs[1] = iocb->plist.iocb_cpuctl.sp_val; + startargs[2] = iocb->plist.iocb_cpuctl.gp_val; + startargs[3] = iocb->plist.iocb_cpuctl.a1_val; + + res = altcpu_cmd_start(iocb->plist.iocb_cpuctl.cpu_number, + startargs); + break; + case CFE_CPU_CMD_STOP: + res = altcpu_cmd_stop(iocb->plist.iocb_cpuctl.cpu_number); + break; + default: + res = CFE_ERR_INV_PARAM; + } + + return res; +#else + return CFE_ERR_INV_COMMAND; +#endif +} + +static int cfe_cmd_fw_gettime(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + POLL(); + + iocb->plist.iocb_time.ticks = cfe_ticks; + + return CFE_OK; +} + +static int cfe_cmd_fw_memenum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int type; + int res; + uint64_t addr,size; + + res = cfe_arena_enum(iocb->plist.iocb_meminfo.mi_idx, + &type, + &addr, + &size, + (iocb->iocb_flags & CFE_FLG_FULL_ARENA) ? TRUE : FALSE); + + iocb->plist.iocb_meminfo.mi_addr = addr; + iocb->plist.iocb_meminfo.mi_size = size; + iocb->plist.iocb_meminfo.mi_type = type; + + if (res == 0) { + if (type == MEMTYPE_DRAM_AVAILABLE) { + iocb->plist.iocb_meminfo.mi_type = CFE_MI_AVAILABLE; + } + else { + iocb->plist.iocb_meminfo.mi_type = CFE_MI_RESERVED; + } + } + + return res; +} + +static int cfe_cmd_fw_flushcache(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + _cfe_flushcache(iocb->iocb_flags); + return CFE_OK; +} + +static int cfe_cmd_dev_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + return CFE_ERR_INV_COMMAND; +} + +static int cfe_cmd_dev_gethandle(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + switch (iocb->iocb_flags) { + case CFE_STDHANDLE_CONSOLE: + if (console_handle == -1) return CFE_ERR_DEVNOTFOUND; + iocb->iocb_handle = console_handle; + return CFE_OK; + break; + default: + return CFE_ERR_INV_PARAM; + } +} + +static int cfe_cmd_dev_open(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int h; + cfe_device_t *dev; + char devname[64]; + int res; + + /* + * Get device name + */ + + xstrncpy(devname,(char*)iocb->plist.iocb_buffer.buf_ptr,sizeof(devname)); + + /* + * Find device in device table + */ + + dev = cfe_finddev(devname); + if (!dev) return CFE_ERR_DEVNOTFOUND; + + /* + * Fail if someone else already has the device open + */ + + if (dev->dev_opencount > 0) return CFE_ERR_DEVOPEN; + + /* + * Generate a new handle + */ + + h = cfe_newhandle(); + if (h < 0) return CFE_ERR_NOMEM; + + /* + * Allocate a context + */ + + ctx = (cfe_devctx_t *) KMALLOC(sizeof(cfe_devctx_t),0); + if (ctx == NULL) return CFE_ERR_NOMEM; + + /* + * Fill in the context + */ + + ctx->dev_dev = dev; + ctx->dev_softc = dev->dev_softc; + ctx->dev_openinfo = NULL; + + /* + * Call driver's open func + */ + + res = dev->dev_dispatch->dev_open(ctx); + + if (res != 0) { + KFREE(ctx); + return res; + } + + /* + * Increment refcnt and save handle + */ + + dev->dev_opencount++; + cfe_handle_table[h] = ctx; + iocb->iocb_handle = h; + + /* + * Success! + */ + + return CFE_OK; +} + +static int cfe_cmd_dev_inpstat(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_inpstat(ctx,&(iocb->plist.iocb_inpstat)); + + return status; +} + +static int cfe_cmd_dev_read(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_read(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_write(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_write(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_ioctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_ioctl(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_close(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + /* + * Call device close function + */ + + ctx->dev_dev->dev_dispatch->dev_close(ctx); + + /* + * Decrement refcnt + */ + + ctx->dev_dev->dev_opencount--; + + /* + * Wipe out handle + */ + + cfe_handle_table[iocb->iocb_handle] = NULL; + + /* + * Release device context + */ + + KFREE(ctx); + + return CFE_OK; +} + +static int cfe_cmd_dev_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + cfe_device_t *dev; + char devname[64]; + char *x; + + /* + * Get device name + */ + + xstrncpy(devname,(char*)iocb->plist.iocb_buffer.buf_ptr,sizeof(devname)); + + /* + * Find device in device table + */ + + if ((x = strchr(devname,':'))) *x = '\0'; + dev = cfe_finddev(devname); + if (!dev) return CFE_ERR_DEVNOTFOUND; + + /* + * Return device class + */ + + iocb->plist.iocb_buffer.buf_devflags = dev->dev_class; + + return CFE_OK; +} + +static int cfe_cmd_env_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int vallen,namelen,res; + + namelen = iocb->plist.iocb_envbuf.name_length; + vallen = iocb->plist.iocb_envbuf.val_length; + + res = env_enum(iocb->plist.iocb_envbuf.enum_idx, + (char*)iocb->plist.iocb_envbuf.name_ptr, + &namelen, + (char*)iocb->plist.iocb_envbuf.val_ptr, + &vallen); + + if (res < 0) return CFE_ERR_ENVNOTFOUND; + + return CFE_OK; +} + + +static int cfe_cmd_env_get(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + char *env; + + env = env_getenv((char*)iocb->plist.iocb_envbuf.name_ptr); + + if (env == NULL) return CFE_ERR_ENVNOTFOUND; + + xstrncpy((char*)iocb->plist.iocb_envbuf.val_ptr, + env, + iocb->plist.iocb_envbuf.val_length); + + return CFE_OK; +} + +static int cfe_cmd_env_set(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int res; + int flg; + + + flg = (iocb->iocb_flags & CFE_FLG_ENV_PERMANENT) ? + ENV_FLG_NORMAL : ENV_FLG_BUILTIN; + + res = env_setenv((char*)iocb->plist.iocb_envbuf.name_ptr, + (char*)iocb->plist.iocb_envbuf.val_ptr, + flg); + + if (res == 0) { + if (iocb->iocb_flags & CFE_FLG_ENV_PERMANENT) res = env_save(); + } + + if (res < 0) return res; + + return CFE_OK; +} + +static int cfe_cmd_env_del(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int res; + + res = env_delenv((char*)iocb->plist.iocb_envbuf.name_ptr); + + return res; +} + + + diff --git a/cfe/cfe/main/cfe_ldr_elf.c b/cfe/cfe/main/cfe_ldr_elf.c new file mode 100644 index 0000000..0581241 --- /dev/null +++ b/cfe/cfe/main/cfe_ldr_elf.c @@ -0,0 +1,396 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * ELF Program Loader File: cfe_ldr_elf.c + * + * This program parses ELF executables and loads them into memory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_mem.h" + +#include "cfe.h" +#include "cfe_loader.h" +#include "cfe_fileops.h" +#include "elf.h" + +#include "cfe_boot.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +static int cfe_elfload(cfe_loadargs_t *la); + +const cfe_loader_t elfloader = { + "elf", + cfe_elfload, + 0}; + +/* ********************************************************************* + * readprogsegment(fsctx,ref,addr,size) + * + * Read a program segment, generally corresponding to one + * section of the file. + * + * Input parameters: + * fsctx - file I/O dispatch + * ref - reference data for open file handle + * addr - target virtual address + * size - size of region to read + * + * Return value: + * Number of bytes copied or <0 if error occured + ********************************************************************* */ + +static int readprogsegment(fileio_ctx_t *fsctx,void *ref, + void *addr,int size,int flags) +{ + int res; + +#ifdef __long64 + if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size); +#else + if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size); +#endif + + if (!cfe_arena_loadcheck((uintptr_t) addr,size)) { + return CFE_ERR_BADADDR; + } + + res = fs_read(fsctx,ref,addr,size); + + if (res < 0) return CFE_ERR_IOERR; + if (res != size) return CFE_ERR_BADELFFMT; + + return size; +} + + +/* ********************************************************************* + * readclearbss(addr,size) + * + * Process a BSS section, zeroing memory corresponding to + * the BSS. + * + * Input parameters: + * addr - address to zero + * size - length of area to zero + * + * Return value: + * number of zeroed bytes or <0 if error occured + ********************************************************************* */ + +static int readclearbss(void *addr,int size,int flags) +{ + +#ifdef __long64 + if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size); +#else + if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size); +#endif + + if (!cfe_arena_loadcheck((uintptr_t) addr,size)) { + return CFE_ERR_BADADDR; + } + + if (size > 0) memset(addr,0,size); + return size; +} + + +/* ********************************************************************* + * elfgetshdr(ops,ref,ep) + * + * Get a section header from the ELF file + * + * Input parameters: + * ops - file I/O dispatch + * ref - reference data for open file + * ep - extended header info + * + * Return value: + * copy of section header (malloc'd) or NULL if no memory + ********************************************************************* */ + +static Elf32_Shdr *elfgetshdr(fileio_ctx_t *fsctx,void *ref,Elf32_Ehdr *ep) +{ + Elf32_Shdr *shtab; + unsigned size = ep->e_shnum * sizeof(Elf32_Shdr); + + shtab = (Elf32_Shdr *) KMALLOC(size,0); + if (!shtab) { + return NULL; + } + + if (fs_seek(fsctx,ref,ep->e_shoff,FILE_SEEK_BEGINNING) != ep->e_shoff || + fs_read(fsctx,ref,(uint8_t *)shtab,size) != size) { + KFREE(shtab); + return NULL; + } + + return (shtab); +} + +/* ********************************************************************* + * elfload_internal(ops,ref,entrypt,flags) + * + * Read an ELF file (main routine) + * + * Input parameters: + * ops - file I/O dispatch + * ref - open file handle + * entrypt - filled in with entry vector + * flags - generic boot flags + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int elfload_internal(fileio_ctx_t *fsctx,void *ref, + unsigned long *entrypt,int flags) +{ + Elf32_Ehdr *ep; + Elf32_Phdr *phtab = 0; + Elf32_Shdr *shtab = 0; + unsigned int nbytes; + int i; + int res; + Elf32_Ehdr ehdr; + + ep = &ehdr; + if (fs_read(fsctx,ref,(uint8_t *) ep,sizeof(*ep)) != sizeof(*ep)) { + return CFE_ERR_IOERR; + } + + /* check header validity */ + if (ep->e_ident[EI_MAG0] != ELFMAG0 || + ep->e_ident[EI_MAG1] != ELFMAG1 || + ep->e_ident[EI_MAG2] != ELFMAG2 || + ep->e_ident[EI_MAG3] != ELFMAG3) { + return CFE_ERR_NOTELF; + } + + if (ep->e_ident[EI_CLASS] != ELFCLASS32) return CFE_ERR_NOT32BIT; + +#ifdef __MIPSEB + if (ep->e_ident[EI_DATA] != ELFDATA2MSB) return CFE_ERR_WRONGENDIAN; /* big endian */ +#endif +#ifdef __MIPSEL + if (ep->e_ident[EI_DATA] != ELFDATA2LSB) return CFE_ERR_WRONGENDIAN; /* little endian */ +#endif + + if (ep->e_ident[EI_VERSION] != EV_CURRENT) return CFE_ERR_BADELFVERS; + if (ep->e_machine != EM_MIPS) return CFE_ERR_NOTMIPS; + + /* Is there a program header? */ + if (ep->e_phoff == 0 || ep->e_phnum == 0 || + ep->e_phentsize != sizeof(Elf32_Phdr)) { + return CFE_ERR_BADELFFMT; + } + + /* Load program header */ + nbytes = ep->e_phnum * sizeof(Elf32_Phdr); + phtab = (Elf32_Phdr *) KMALLOC(nbytes,0); + if (!phtab) { + return CFE_ERR_NOMEM; + } + + if (fs_seek(fsctx,ref,ep->e_phoff,FILE_SEEK_BEGINNING) != ep->e_phoff || + fs_read(fsctx,ref,(uint8_t *)phtab,nbytes) != nbytes) { + KFREE(phtab); + return CFE_ERR_IOERR; + } + + /* + * From now on we've got no guarantee about the file order, + * even where the section header is. Hopefully most linkers + * will put the section header after the program header, when + * they know that the executable is not demand paged. We assume + * that the symbol and string tables always follow the program + * segments. + */ + + /* read section table (if before first program segment) */ + if (ep->e_shoff < phtab[0].p_offset) { + shtab = elfgetshdr(fsctx,ref,ep); + } + + /* load program segments */ + /* We cope with a badly sorted program header, as produced by + * older versions of the GNU linker, by loading the segments + * in file offset order, not in program header order. */ + + while (1) { + Elf32_Off lowest_offset = ~0; + Elf32_Phdr *ph = 0; + + /* find nearest loadable segment */ + for (i = 0; i < ep->e_phnum; i++) + if ((phtab[i].p_type == PT_LOAD) && (phtab[i].p_offset < lowest_offset)) { + ph = &phtab[i]; + lowest_offset = ph->p_offset; + } + if (!ph) { + break; /* none found, finished */ + } + + /* load the segment */ + if (ph->p_filesz) { + if (fs_seek(fsctx,ref,ph->p_offset,FILE_SEEK_BEGINNING) != ph->p_offset) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return CFE_ERR_BADELFFMT; + } + res = readprogsegment(fsctx,ref, + (void *)(intptr_t)(signed)ph->p_vaddr, + ph->p_filesz,flags); + if (res != ph->p_filesz) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return res; + } + } + + if (ph->p_filesz < ph->p_memsz) { + res = readclearbss((void *)(intptr_t)(signed)ph->p_vaddr + ph->p_filesz, + ph->p_memsz - ph->p_filesz,flags); + if (res < 0) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return res; + } + } + + ph->p_type = PT_NULL; /* remove from consideration */ + } + + KFREE(phtab); + + *entrypt = (intptr_t)(signed)ep->e_entry; /* return entry point */ + return 0; +} + + + +/* ********************************************************************* + * cfe_elfload(ops,file,flags) + * + * Read an ELF file (main entry point) + * + * Input parameters: + * ops - fileio dispatch + * file - name of file to read + * ept - where to put entry point + * flags - load flags + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int cfe_elfload(cfe_loadargs_t *la) +{ + fileio_ctx_t *fsctx; + void *ref; + int res; + + /* + * Look up the file system type and get a context + */ + + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (la->la_flags & LOADFLG_COMPRESSED) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the remote file + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return CFE_ERR_FILENOTFOUND; + } + + /* + * Load the image. + */ + + la->la_entrypt = 0; + res = elfload_internal(fsctx,ref,&(la->la_entrypt),la->la_flags); + + /* + * All done, release resources + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + return res; +} + + diff --git a/cfe/cfe/main/cfe_ldr_raw.c b/cfe/cfe/main/cfe_ldr_raw.c new file mode 100644 index 0000000..d436849 --- /dev/null +++ b/cfe/cfe/main/cfe_ldr_raw.c @@ -0,0 +1,360 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * RAW Program Loader File: cfe_ldr_raw.c + * + * This program reads raw binaries into memory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_boot.h" +#include "cfe_bootblock.h" + +#include "cfe_loader.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +static int cfe_rawload(cfe_loadargs_t *la); + +const cfe_loader_t rawloader = { + "raw", + cfe_rawload, + 0}; + +/* ********************************************************************* + * cfe_findbootblock(la,fsctx,ref) + * + * Find the boot block on the specified device. + * + * Input parameters: + * la - loader args (to be filled in) + * ops - file operations + * ref - reference for open file handle + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +static int cfe_findbootblock(cfe_loadargs_t *la, + fileio_ctx_t *fsctx, + void *ref, + struct boot_block *bootblock) +{ + uint32_t checksum = 0; + uint32_t calcsum; + uint32_t secsize = 0; + uint64_t secoffset = 0; + int res; + int curblk; + + /* + * Search for the boot block. Stop when we find + * something with a matching checksum and magic + * number. + */ + + fs_seek(fsctx,ref,0,FILE_SEEK_BEGINNING); + + for (curblk = 0; curblk < BOOT_BLOCK_MAXLOC; curblk++) { + + + /* Read a block */ + + res = fs_read(fsctx,ref, + (unsigned char *) bootblock, + sizeof(struct boot_block)); + + if (res != sizeof(struct boot_block)) { + return CFE_ERR_IOERR; + } + + /* Verify magic number */ + + if (bootblock->bb_magic != BOOT_MAGIC_NUMBER) { + continue; + } + + /* Extract fields from block */ + + checksum = ((uint32_t) (bootblock->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK)); + bootblock->bb_hdrinfo &= ~BOOT_HDR_CHECKSUM_MASK; + secsize = ((uint32_t) (bootblock->bb_secsize & BOOT_SECSIZE_MASK)); + secoffset = bootblock->bb_secstart; + + /* Verify block's checksum */ + + CHECKSUM_BOOT_DATA(&(bootblock->bb_magic),BOOT_BLOCK_SIZE,&calcsum); + + if (checksum == calcsum) { + break; + } + } + + /* + * Okay, determine if we were successful. + */ + + if (bootblock->bb_magic != BOOT_MAGIC_NUMBER) { + return CFE_ERR_INVBOOTBLOCK; + } + + if (checksum != calcsum) { + return CFE_ERR_BBCHECKSUM; + } + + /* + * If we get here, we had a valid boot block. + */ + + return 0; +} + + +/* ********************************************************************* + * cfe_rawload(la) + * + * Read a raw (unformatted) boot file + * + * Input parameters: + * la - loader args + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +static int cfe_rawload(cfe_loadargs_t *la) +{ + int res; + fileio_ctx_t *fsctx; + const fileio_dispatch_t *ops; + void *ref; + int ttlcopy = 0; + int findbb; + int devinfo; + struct boot_block bootblock; + uint8_t *ptr; + uint8_t *bootcode; + uint32_t checksum,calcsum; + uint64_t secoffset = 0; + int32_t maxsize; + int amtcopy; + int thisamt; + uint32_t loadflags; + int onedot; + + loadflags = la->la_flags; + + /* + * Set starting address and maximum size. You can either + * explicitly set this (with LOADFLG_SPECADDR) or + * let CFE decide. If CFE decides, the load address + * will be BOOT_START_ADDRESS in all cases. + * The size is dependant on the device type: block and flash + * devices will get this info from the boot block, + * and network devices will get the info by reaching EOF + * on reads, up to the maximum size of the boot area. + */ + + if (loadflags & LOADFLG_SPECADDR) { + bootcode = (uint8_t *) la->la_address; + maxsize = la->la_maxsize; + findbb = FALSE; /* don't find a boot block */ + } + else { + bootcode = (uint8_t *) BOOT_START_ADDRESS; + maxsize = BOOT_AREA_SIZE; + findbb = FALSE; + devinfo = la->la_device ? cfe_getdevinfo(la->la_device) : 0; + + /* + * If the device is either a disk or a flash device, + * we will expect to find a boot block. + * Serial and network devices do not have boot blocks. + */ + if ((devinfo >= 0) && + ( ((devinfo & CFE_DEV_MASK) == CFE_DEV_DISK) || + ((devinfo & CFE_DEV_MASK) == CFE_DEV_FLASH) )) { + findbb = TRUE; + } + } + + + /* + * merge in any filesystem-specific flags + */ + + ops = cfe_findfilesys(la->la_filesys); + if (!ops) return CFE_ERR_FSNOTAVAIL; + loadflags |= ops->loadflags; + + /* + * turn off the boot block if requested. + */ + + if (loadflags & LOADFLG_NOBB) findbb = FALSE; + + /* + * Create a file system context + */ + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (!findbb && (la->la_flags & LOADFLG_COMPRESSED)) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the boot device + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return res; + } + + /* + * If we need to find a boot block, do it now. + */ + + if (findbb) { + res = cfe_findbootblock(la,fsctx,ref,&bootblock); + + /* + * If we found the boot block, seek to the part of the + * disk where the boot code is. + * Otherwise, get out now, since the disk has no boot block. + */ + + if (res == 0) { + maxsize = (int) ((uint32_t) (bootblock.bb_secsize & BOOT_SECSIZE_MASK)); + secoffset = bootblock.bb_secstart; + fs_seek(fsctx,ref,secoffset,FILE_SEEK_BEGINNING); + } + else { + fs_close(fsctx,ref); + fs_uninit(fsctx); + return res; + } + + } + + /* + * Okay, go load the boot file. + */ + + ptr = bootcode; + amtcopy = maxsize; + ttlcopy = 0; + + onedot = amtcopy / 10; /* ten dots for entire load */ + if (onedot < 4096) onedot = 4096; /* but minimum 4096 bytes per dot */ + onedot = (onedot + 1) & ~4095; /* round to multiple of 4096 */ + + while (amtcopy > 0) { + thisamt = onedot; + if (thisamt > amtcopy) thisamt = amtcopy; + + res = fs_read(fsctx,ref,ptr,thisamt); + if (la->la_flags & LOADFLG_NOISY) { + xprintf("."); + } + if (res <= 0) break; + ptr += res; + amtcopy -= res; + ttlcopy += res; + } + + /* + * We're done with the file. + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + /* + * Verify the boot loader checksum if we were reading + * the disk. + */ + + if (findbb) { + CHECKSUM_BOOT_DATA(bootcode,maxsize,&calcsum); + checksum = (uint32_t) ((bootblock.bb_secsize & BOOT_DATA_CHECKSUM_MASK) + >> BOOT_DATA_CHECKSUM_SHIFT); + + if (checksum != calcsum) { + return CFE_ERR_BOOTPROGCHKSUM; + } + } + + la->la_entrypt = (uintptr_t) bootcode; + + if (la->la_flags & LOADFLG_NOISY) xprintf(" %d bytes read\n",ttlcopy); + + return (res < 0) ? res : ttlcopy; + +} + diff --git a/cfe/cfe/main/cfe_ldr_srec.c b/cfe/cfe/main/cfe_ldr_srec.c new file mode 100644 index 0000000..b067f2b --- /dev/null +++ b/cfe/cfe/main/cfe_ldr_srec.c @@ -0,0 +1,557 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * SREC Program Loader File: cfe_ldr_srec.c + * + * This program reads Motorola S-record files into memory + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_boot.h" +#include "cfe_bootblock.h" + +#include "cfe_loader.h" + +#include "cfe_mem.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +static int cfe_srecload(cfe_loadargs_t *la); + +const cfe_loader_t srecloader = { + "srec", + cfe_srecload, + 0}; + + +typedef struct linebuf_s { + char linebuf[256]; + int curidx; + int buflen; + int eof; + void *ref; + fileio_ctx_t *fsctx; +} linebuf_t; + +#define initlinebuf(b,r,o) (b)->curidx = 0; (b)->buflen = 0; \ + (b)->eof = 0 ; (b)->ref = r; (b)->fsctx = o + + +/* ********************************************************************* + * readchar(file) + * + * Read a character from a file. It's kind of like getchar + * on "C" FILE devices, but not so fancy. + * + * Input parameters: + * file - pointer to a linebuf_t containing reader state + * + * Return value: + * character, or -1 if at EOF + ********************************************************************* */ + +static int readchar(linebuf_t *file) +{ + int ch; + int res; + + if (file->eof) return -1; + + if (file->curidx == file->buflen) { + for (;;) { + res = fs_read(file->fsctx,file->ref,file->linebuf,sizeof(file->linebuf)); + if (res < 0) { + file->eof = -1; + return -1; + } + if (res == 0) continue; + file->buflen = res; + file->curidx = 0; + break; + } + } + + ch = file->linebuf[file->curidx]; + file->curidx++; + return ch; +} + + +/* ********************************************************************* + * readline(file,buffer,maxlen) + * + * Read a line of text from a file using our crude file stream + * mechanism. + * + * Input parameters: + * file - pointer to a linebuf_t containing reader state + * buffer - will receive line of text + * maxlen - number of bytes that will fit in buffer + * + * Return value: + * 0 if ok, else <0 if at EOF + ********************************************************************* */ + +static int readline(linebuf_t *file,char *buffer,int maxlen) +{ + int ch; + char *ptr; + + ptr = buffer; + maxlen--; /* account for terminating null */ + + while (maxlen) { + ch = readchar(file); + if (ch == -1) return -1; + if (ch == 27) return -1; /* ESC */ + if ((ch == '\n') || (ch == '\r')) break; + *ptr++ = (char) ch; + maxlen--; + } + + *ptr = '\0'; + + return 0; +} + + +/* ********************************************************************* + * getxdigit(c) + * + * Convert a hex digit into its numeric equivalent + * + * Input parameters: + * c - character + * + * Return value: + * value + ********************************************************************* */ + +static int getxdigit(char c) +{ + if ((c >= '0') && (c <= '9')) return c - '0'; + if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10; + if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10; + return -1; +} + +/* ********************************************************************* + * getbyte(line) + * + * Process two hex digits and return the value + * + * Input parameters: + * line - pointer to pointer to characters (updated on exit) + * + * Return value: + * byte value, or <0 if bad hex digits + ********************************************************************* */ + +static int getbyte(char **line) +{ + int res; + int c1,c2; + + c1 = getxdigit(*(*(line)+0)); + if (c1 < 0) return -1; + + c2 = getxdigit(*(*(line)+1)); + if (c2 < 0) return -1; + + res = (c1*16+c2); + (*line) += 2; + + return res; +} + + +/* ********************************************************************* + * procsrec(line,loadaddr,blklen,data) + * + * Process an S-record, reading the data into a local buffer + * and returning the block's address. + * + * Input parameters: + * line - line of text (s-record line) + * loadaddr - will be filled with address where data should go + * blklen - will be filled in with size of record + * data - points to buffer to receive data + * + * Return value: + * <0 if error occured (not an s-record) + ********************************************************************* */ + +static int procsrec(char *line, + unsigned int *loadaddr, + unsigned int *blklen, + unsigned char *data) +{ + char rectype; + unsigned char b; + unsigned int len; + unsigned int minlen; + unsigned int linelen; + unsigned int addr; + unsigned int chksum; + + int idx; + int ret = 0; + + addr = 0; + + if (*line++ != 'S') + return -1; /* not an S record */ + + rectype = *line++; + + minlen = 3; /* type 1 record */ + switch (rectype) { + case '0': + break; + + /* + * data bytes + */ + case '3': + minlen++; + /* fall through */ + case '2': + minlen++; + /* fall through */ + case '1': + chksum = 0; + linelen = getbyte(&line); + if (linelen < minlen) { + xprintf("srec: line too short\n"); + return -1; + } + chksum += (unsigned int)linelen; + + /* + * There are two address bytes in a type 1 record, and three + * in a type 2 record. The high-order byte is first, then + * one or two lower-order bytes. Build up the adddress. + */ + b = getbyte(&line); + chksum += (unsigned int)b; + addr = b; + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + if (rectype == '2') { + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + } + if (rectype == '3') { + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + } + +#if VERBOSE + printf("Addr: %08X Len: %3u(0x%x)\n", addr , linelen - minlen, + linelen-minlen); +#endif + + *loadaddr = addr; + len = linelen - minlen; + *blklen = len; + + for (idx = 0; idx < len; idx++) { + b = getbyte(&line); + chksum += (unsigned int) b; + data[idx] = (unsigned char ) b; + } + + b = getbyte(&line); + chksum = (~chksum) & 0x000000FF; + if (chksum != b) { + xprintf("Checksum error in s-record file\n"); + return -1; + } + ret = 1; + break; + + case '9': + linelen = getbyte(&line); + b = getbyte(&line); + addr = b; + b = getbyte(&line); + addr <<= 8; + addr += b; + *loadaddr = addr; + ret = -2; + break; + + case '8': + linelen = getbyte(&line); + b = getbyte(&line); + addr = b; + b = getbyte(&line); + addr <<= 8; + addr += b; + b = getbyte(&line); + addr <<= 8; + addr += b; + *loadaddr = addr; + ret = -2; + break; + + case '7': + linelen = getbyte(&line); + b = getbyte(&line); + addr = b; + b = getbyte(&line); + addr <<= 8; + addr += b; + b = getbyte(&line); + addr <<= 8; + addr += b; + b = getbyte(&line); + addr <<= 8; + addr += b; + *loadaddr = addr; + ret = -2; + break; + + default: + xprintf("Unknown S-record type: %c\n",rectype); + return -1; + break; + } + + return ret; +} + + +/* ********************************************************************* + * cfe_srecload(la) + * + * Read an s-record file + * + * Input parameters: + * la - loader args + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +static int cfe_srecload(cfe_loadargs_t *la) +{ + int res; + fileio_ctx_t *fsctx; + void *ref; + int devinfo; + int serial = FALSE; + unsigned int loadaddr; + unsigned int blklen; + linebuf_t lb; + char line[256]; + uint8_t data[256]; + int cnt; + unsigned int specaddr; /* current address if loading to a special address */ + int specflg; /* true if in "special address" mode */ + int firstrec = 1; /* true if we have not seen the first record */ + + /* + * We might want to know something about the boot device. + */ + + devinfo = la->la_device ? cfe_getdevinfo(la->la_device) : 0; + + /* + * Figure out if we're loading to a "special address". This lets + * us load S-records into a temporary buffer, ignoring the + * addresses in the records (but using them so we'll know where + * they go relative to each other + */ + + specflg = (la->la_flags & LOADFLG_SPECADDR) ? 1 : 0; + specaddr = 0; + + /* + * If the device is a serial port, we want to know that. + */ + + if ((devinfo >= 0) && + ((devinfo & CFE_DEV_MASK) == CFE_DEV_SERIAL)) { + serial = TRUE; + } + + /* + * Create a file system context + */ + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (la->la_flags & LOADFLG_COMPRESSED) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the boot device + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return res; + } + + /* + * Okay, go load the boot file. Process S-records until + * we get an entry point record (usually at the end). + * + * XXX what if it's *not* at the end? + */ + + initlinebuf(&lb,ref,fsctx); + + cnt = 0; + for (;;) { + /* + * Read a line of text + */ + res = readline(&lb,line,sizeof(line)); + if (res < 0) break; /* reached EOF */ + + /* + * Process the S-record. If at EOF, procsrec returns 0. + * Invalid s-records returns -1. + */ + + if (line[0] == 0) continue; + + res = procsrec(line,&loadaddr,&blklen,data); + +#if 0 + if (res == -2 || res >= 0) + xprintf("."); +#endif + if (res < 0) break; + + /* + * Handle "special address" mode. All S-records will be + * loaded into a buffer passed by the caller to the loader. + * We use the addresses in the S-records to determine + * relative placement of the data, keying on the first + * S-record in the file. + */ + + if ((res == 1) && (specflg)) { + if (firstrec) { + /* First S-record seen sets the base for all that follow */ + specaddr = loadaddr; + firstrec = 0; + } + loadaddr = la->la_address + (intptr_t) (loadaddr - specaddr); + } + + cnt++; + + if (res == 1) { + if (!cfe_arena_loadcheck((intptr_t) loadaddr,blklen)) { + xprintf("Invalid address: %P\n",loadaddr); + res = -1; + break; + } + memcpy((uint8_t *) (intptr_t) (signed)loadaddr,data,blklen); + } + } + + /* + * We're done with the file. + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + /* + * Say something cute on the LEDs. + * Don't do this for every s-record, because if logging the LED + * changes out the serial port, that can take a Long Time. Just + * goes to show: too much cuteness is a _very_ bad thing. + */ + xsprintf(line,"%04d",cnt); + cfe_ledstr(line); + + if (res == -2) { + la->la_entrypt = (intptr_t) (signed) loadaddr; + res = 0; + } + + return res; +} + + diff --git a/cfe/cfe/main/cfe_link.mk b/cfe/cfe/main/cfe_link.mk new file mode 100644 index 0000000..7529dc4 --- /dev/null +++ b/cfe/cfe/main/cfe_link.mk @@ -0,0 +1,26 @@ +# +# This Makefile snippet takes care of linking the firmware. +# + +pci : $(PCICOMMON) $(PCIMACHDEP) + echo done + +cfe cfe.bin : $(CRT0OBJS) $(BSPOBJS) $(LIBCFE) + $(GLD) -o cfe -Map cfe.map $(LDFLAGS) $(CRT0OBJS) $(BSPOBJS) -L. -lcfe $(LDLIBS) + $(OBJDUMP) -d cfe > cfe.dis + $(OBJCOPY) --output-target=binary cfe cfe.bin + $(OBJCOPY) --input-target=binary --output-target=srec cfe.bin cfe.srec + +cfe.flash : cfe.bin mkflashimage + ./mkflashimage -v ${ENDIAN} -B ${CFG_BOARDNAME} -V ${CFE_VER_MAJ}.${CFE_VER_MIN}.${CFE_VER_ECO} cfe.bin cfe.flash + $(OBJCOPY) --input-target=binary --output-target=srec cfe.flash cfe.flash.srec + + +clean : + rm -f *.o *~ cfe cfe.bin cfe.dis cfe.map cfe.srec + rm -f makereg ${CPU}_socregs.inc mkpcidb pcidevs_data2.h mkflashimage + rm -f build_date.c + rm -f libcfe.a + rm -f cfe.flash cfe.flash.srec $(CLEANOBJS) + +distclean : clean diff --git a/cfe/cfe/main/cfe_loader.c b/cfe/cfe/main/cfe_loader.c new file mode 100644 index 0000000..bbd3eb4 --- /dev/null +++ b/cfe/cfe/main/cfe_loader.c @@ -0,0 +1,135 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Loader API File: cfe_loader.c + * + * This is the main API for the program loader. CFE supports + * multiple "installable" methods for loading programs, allowing + * us to deal with a variety of methods for moving programs + * into memory for execution. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "cfe_error.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_loader.h" + +#include "bsp_config.h" + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern const cfe_loader_t elfloader; +extern const cfe_loader_t rawloader; +extern const cfe_loader_t srecloader; + +/* ********************************************************************* + * Loader list + ********************************************************************* */ + +const cfe_loader_t * const cfe_loaders[] = { + &elfloader, +#if !CFG_MINIMAL_SIZE + &rawloader, + &srecloader, +#endif + NULL}; + +/* ********************************************************************* + * cfe_findloader(name) + * + * Find a loader by name + * + * Input parameters: + * name - name of loader to find + * + * Return value: + * pointer to loader structure or NULL + ********************************************************************* */ + +const cfe_loader_t *cfe_findloader(char *name) +{ + const cfe_loader_t * const *ldr; + + ldr = cfe_loaders; + + while (*ldr) { + if (strcmp(name,(*ldr)->name) == 0) return (*ldr); + ldr++; + } + + return NULL; +} + + +/* ********************************************************************* + * cfe_load_progam(name,args) + * + * Look up a loader and call it. + * + * Input parameters: + * name - name of loader to run + * args - arguments to pass + * + * Return value: + * return value + ********************************************************************* */ + +int cfe_load_program(char *name,cfe_loadargs_t *la) +{ + const cfe_loader_t *ldr; + int res; + + ldr = cfe_findloader(name); + if (!ldr) return CFE_ERR_LDRNOTAVAIL; + + res = LDRLOAD(ldr,la); + + return res; +} diff --git a/cfe/cfe/main/cfe_main.c b/cfe/cfe/main/cfe_main.c new file mode 100644 index 0000000..1a451a6 --- /dev/null +++ b/cfe/cfe/main/cfe_main.c @@ -0,0 +1,636 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Main Module File: cfe_main.c + * + * This module contains the main "C" routine for CFE and + * the main processing loop. There should not be any board-specific + * stuff in here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_timer.h" + +#include "env_subr.h" +#include "ui_command.h" +#include "cfe_mem.h" +#include "cfe.h" + +#include "exception.h" + +#include "bsp_config.h" + +#include "segtable.h" + +#include "initdata.h" + +#if CFG_PCI +#include "pcivar.h" +#endif + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#ifndef CFG_STACK_SIZE +#define STACK_SIZE 8192 +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +void cfe_main(int,int); +extern void cfe_device_poll(void *x); + +extern int ui_init_envcmds(void); +extern int ui_init_devcmds(void); +extern int ui_init_netcmds(void); +extern int ui_init_memcmds(void); +extern int ui_init_loadcmds(void); +extern int ui_init_pcicmds(void); +extern int ui_init_examcmds(void); +extern int ui_init_flashcmds(void); +extern int ui_init_misccmds(void); +#if CFG_VAPI +extern int ui_init_vapicmds(void); +#endif + +#if CFG_VENDOR_EXTENSIONS +extern int ui_init_vendorcmds(void); +#endif + +void cfe_command_restart(uint64_t status); + +extern segtable_t *_getsegtbl(void); + +extern const char *builddate; +extern const char *builduser; + +#if CFG_MULTI_CPUS +extern int altcpu_cmd_start(uint64_t,uint64_t *); +extern int altcpu_cmd_stop(uint64_t); +#endif + + + + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +const char *cfe_boardname = CFG_BOARDNAME; +unsigned int cfe_startflags = +#if CFG_PCI + CFE_INIT_PCI | +#endif + 0; + +/* ********************************************************************* + * cfe_setup_default_env() + * + * Initialize the default environment for CFE. These are all + * the temporary variables that do not get stored in the NVRAM + * but are available to other programs and command-line macros. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_setup_default_env(void) +{ + char buffer[80]; + + xsprintf(buffer,"%d.%d.%d",CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD); + env_setenv("CFE_VERSION",buffer,ENV_FLG_BUILTIN | ENV_FLG_READONLY); + + if (cfe_boardname) { + env_setenv("CFE_BOARDNAME",(char *) cfe_boardname, + ENV_FLG_BUILTIN | ENV_FLG_READONLY); + } + + xsprintf(buffer,"%d",mem_totalsize); + env_setenv("CFE_MEMORYSIZE",buffer,ENV_FLG_BUILTIN | ENV_FLG_READONLY); + +} + + +/* ********************************************************************* + * cfe_init_ui() + * + * Call all the other UI initialization modules. Each of these + * modules usually calls back to the UI dispatcher to add command + * tables. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +#if CFG_MINIMAL_SIZE +#define OPTIONAL(x) +#else +#define OPTIONAL(x) x +#endif + +static void cfe_init_ui(void) +{ + ui_init_cmddisp(); + + ui_init_envcmds(); + OPTIONAL(ui_init_devcmds()); +#if CFG_NETWORK + ui_init_netcmds(); +#endif + ui_init_loadcmds(); + OPTIONAL(ui_init_memcmds()); + +#if CFG_PCI + ui_init_pcicmds(); +#endif + OPTIONAL(ui_init_examcmds()); + ui_init_flashcmds(); +#if CFG_VAPI + ui_init_vapicmds(); +#endif + +#if CFG_VENDOR_EXTENSIONS + ui_init_vendorcmds(); +#endif + + OPTIONAL(ui_init_misccmds()); + +} + + +/* ********************************************************************* + * cfe_ledstr(leds) + * + * Display a string on the board's LED display, if it has one. + * This routine depends on the board-support package to + * include a "driver" to write to the actual LED, if the board + * does not have one this routine will do nothing. + * + * The LEDs are written at various places in the initialization + * sequence, to debug board problems. + * + * Input parameters: + * leds - pointer to four-character ASCII string + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_ledstr(const char *leds) +{ + unsigned int val; + + val = ((((unsigned int) leds[0]) << 24) | + (((unsigned int) leds[1]) << 16) | + (((unsigned int) leds[2]) << 8) | + ((unsigned int) leds[3])); + + cfe_leds(val); +} + + +/* ********************************************************************* + * cfe_say_hello() + * + * Print out the CFE startup message and copyright notice + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + + +static void cfe_say_hello(void) +{ + xprintf("\n\n"); + xprintf("CFE version 2.0.2" +#ifdef CFE_VER_RELEASE + ".%d" +#endif + " for DGN2200v2 (%s)\n", + //CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD, +#ifdef CFE_VER_RELEASE + CFE_VER_RELEASE, +#endif + //cfe_boardname, +#ifdef __long64 + "64bit," +#else + "32bit," +#endif +#if CFG_MULTI_CPUS + "MP," +#else + "SP," +#endif +#ifdef __MIPSEL + "LE" +#endif +#ifdef __MIPSEB + "BE" +#endif +#if CFG_VAPI + ",VAPI" +#endif + ); + + xprintf("Build Date: %s (%s)\n",builddate,builduser); + xprintf("Copyright (C) 2000,2001,2002,2003 Broadcom Corporation.\n"); + xprintf("\n"); +} + + +/* ********************************************************************* + * cfe_restart() + * + * Restart CFE from scratch, jumping back to the boot vector. + * + * Input parameters: + * nothing + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_restart(void) +{ + _exc_restart(); +} + + +/* ********************************************************************* + * cfe_start(ept) + * + * Start a user program + * + * Input parameters: + * ept - entry point + * + * Return value: + * nothing + ********************************************************************* */ +void cfe_start(unsigned long ept) +{ + SETLEDS("RUN!"); + cfe_launch(ept); +} + + +/* ********************************************************************* + * cfe_startup_info() + * + * Display startup memory configuration messages + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_startup_info(void) +{ + segtable_t *segtbl; + + segtbl = _getsegtbl(); + xprintf("CPU type 0x%X: ",(uint32_t)cpu_prid); + if (cfe_cpu_speed < 1000000) xprintf("%dKHz\n",cfe_cpu_speed/1000); + else xprintf("%dMHz\n",cfe_cpu_speed/1000000); + xprintf("Total memory: 0x%llX bytes (%dMB)\n", + (((uint64_t)mem_totalsize) << 20),(uint32_t)mem_totalsize); + + xprintf("\n"); + xprintf("Total memory used by CFE: 0x%08X - 0x%08X (%d)\n", + (uint32_t) mem_bottomofmem, + (uint32_t) mem_topofmem, + (uint32_t) mem_topofmem-mem_bottomofmem); + xprintf("Initialized Data: 0x%08X - 0x%08X (%d)\n", + (uint32_t) (segtbl[R_SEG_FDATA] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_EDATA] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_EDATA] - segtbl[R_SEG_FDATA])); + xprintf("BSS Area: 0x%08X - 0x%08X (%d)\n", + (uint32_t) (segtbl[R_SEG_FBSS] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_END] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_END] - segtbl[R_SEG_FBSS])); + xprintf("Local Heap: 0x%08X - 0x%08X (%d)\n", + (uint32_t)(mem_heapstart), + (uint32_t)(mem_heapstart + (CFG_HEAP_SIZE*1024)), + (CFG_HEAP_SIZE*1024)); + xprintf("Stack Area: 0x%08X - 0x%08X (%d)\n", + (uint32_t)(mem_heapstart + (CFG_HEAP_SIZE*1024)), + (uint32_t)(mem_heapstart + (CFG_HEAP_SIZE*1024) + STACK_SIZE), + STACK_SIZE); + xprintf("Text (code) segment: 0x%08X - 0x%08X (%d)\n", + (uint32_t)mem_textbase, + (uint32_t)(mem_textbase+mem_textsize), + (uint32_t) mem_textsize); + xprintf("Boot area (physical): 0x%08X - 0x%08X\n", + mem_bootarea_start,mem_bootarea_start+mem_bootarea_size); + xprintf("Relocation Factor: I:%08X - D:%08X\n", + (uint32_t) mem_textreloc,(uint32_t) mem_datareloc); + +} + + +/* ********************************************************************* + * cfe_autostart() + * + * Process automatic commands at startup + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_autostart(void) +{ + char *env; + int noauto = 0; + char ch; + + env = env_getenv("STARTUP"); + if (!env) return; + + while (console_status()) { + console_read(&ch,1); + if (ch == 3) noauto = TRUE; /* Ctrl-C means no auto */ + } + + if (noauto) { + xprintf("Automatic startup canceled via Ctrl-C\n"); + return; + } + + ui_docommands(env); +} + +/* ********************************************************************* + * cfe_main(a,b) + * + * It's gotta start somewhere. + * + * Input parameters: + * a,b - not used + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_main(int a,int b) +{ + + /* + * By the time this routine is called, the following things have + * already been done: + * + * 1. The processor(s) is(are) initialized. + * 2. The caches are initialized. + * 3. The memory controller is initialized. + * 4. BSS has been zeroed. + * 5. The data has been moved to R/W space. + * 6. The "C" Stack has been initialized. + */ + + cfe_bg_init(); /* init background processing */ + cfe_attach_init(); + cfe_timer_init(); /* Timer process */ + cfe_bg_add(cfe_device_poll,NULL); + + /* + * Initialize the memory allocator + */ + + SETLEDS("KMEM"); + KMEMINIT((unsigned char *) (uintptr_t) mem_heapstart, + ((CFG_HEAP_SIZE)*1024)); + + /* + * Initialize the console. It is done before the other devices + * get turned on. The console init also sets the variable that + * contains the CPU speed. + */ + + SETLEDS("CONS"); + board_console_init(); + + /* + * Set up the exception vectors + */ + + cfe_setup_exceptions(); + + /* + * Say hello. + */ + + SETLEDS("CIOK"); + cfe_say_hello(); + + /* + * Initialize the other devices. + */ + + SETLEDS("AREN"); + xprintf("Initializing Arena.\n"); + cfe_arena_init(); + +#if CFG_PCI + if (cfe_startflags & CFE_INIT_PCI) { + pci_flags_t flags = PCI_FLG_NORMAL | PCI_FLG_LDT_PREFETCH; + char *str; + extern cons_t pci_optnames[]; + + flags = PCI_FLG_NORMAL | PCI_FLG_LDT_PREFETCH; +#if CFG_LDT_REV_017 + flags |= PCI_FLG_LDT_REV_017; +#endif + str = env_getenv("PCI_OPTIONS"); + setoptions(pci_optnames,str,&flags); + + xprintf("Initializing PCI. [%s]\n",str ? str : "normal"); + pci_configure(flags); + } +#endif + + SETLEDS("DEVI"); + xprintf("Initializing Devices.\n"); + board_device_init(); + + cfe_startup_info(); + SETLEDS("ENVI"); + cfe_setup_default_env(); + + xprintf("\n"); + + cfe_init_ui(); + + board_final_init(); + + cfe_autostart(); + + cfe_command_loop(); +} + +/* ********************************************************************* + * cfe_command_restart() + * + * This routine is called when an application wants to restart + * the firmware's command processor. Reopen the console and + * jump back into the command loop. + * + * Input parameters: + * status - A0 value of program returning to firmware + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_command_restart(uint64_t status) +{ + /* + * Stop alternate CPU(s). If they're already stopped, this + * command will make sure they're stopped. + */ + +#if CFG_MULTI_CPUS + altcpu_cmd_stop(1); /* stop CPU 1 (XXX more CPUs?) */ +#endif + + /* + * Call board reset functions + */ + board_device_reset(); + + /* + * Reset devices + */ + cfe_device_reset(); + + /* + * Reset timers + */ + cfe_timer_init(); + + /* + * Reopen console + */ + console_open(console_name); + + /* + * Display program return status + */ + + xprintf("*** program exit status = %d\n", (int)status); + + /* + * Back to processing user commands + */ + cfe_command_loop(); +} + + + +/* ********************************************************************* + * cfe_command_loop() + * + * This routine reads and processes user commands + * + * Input parameters: + * nothing + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_command_loop() +{ + char buffer[300]; + int status; + char *prompt; + + SETLEDS("CFE "); + + for (;;) { + prompt = env_getenv("PROMPT"); +#if CFG_RAMAPP + SETLEDS("CFE*"); + if (!prompt) prompt = "CFE_RAM> "; +#else + if (!prompt) prompt = "CFE> "; +#endif + console_readline(prompt,buffer,sizeof(buffer)); + + status = ui_docommands(buffer); + + if (status != CMD_ERR_BLANK) { + xprintf("*** command status = %d\n", status); + } + } +} + + + + + diff --git a/cfe/cfe/main/cfe_mem.c b/cfe/cfe/main/cfe_mem.c new file mode 100644 index 0000000..1c424e1 --- /dev/null +++ b/cfe/cfe/main/cfe_mem.c @@ -0,0 +1,256 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Physical Memory (arena) manager File: cfe_mem.c + * + * This module describes the physical memory available to the + * firmware. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_arena.h" + +#include "cfe_error.h" + +#include "cfe.h" +#include "cfe_mem.h" + +#include "initdata.h" + +#define _NOPROTOS_ +#include "cfe_boot.h" +#undef _NOPROTOS_ + +#include "cpu_config.h" /* for definition of CPUCFG_ARENAINIT */ + +#include "addrspace.h" /* for macros dealing with addresses */ + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define ARENA_RANGE(bottom,top,type) arena_markrange(&cfe_arena,(uint64_t)(bottom), \ + (uint64_t)(top)-(uint64_t)bottom+1,(type),NULL) + +#define MEG (1024*1024) +#define KB 1024 +#define PAGESIZE 4096 +#define CFE_BOOTAREA_SIZE (256*KB) +#define CFE_BOOTAREA_ADDR 0x20000000 + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +arena_t cfe_arena; +extern void _setcontext(int64_t); + +unsigned int mem_bootarea_start; +unsigned int mem_bootarea_size; + +extern void CPUCFG_ARENAINIT(void); +extern void cfe_bootarea_init(void); +extern void CPUCFG_PAGETBLINIT(uint64_t *ptaddr,unsigned int ptstart); + + + +/* ********************************************************************* + * cfe_arena_init() + * + * Create the initial map of physical memory + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_arena_init(void) +{ + uint64_t memlo,memhi; + + /* + * This macro expands via cpu_config.h to an appropriate function + * name for creating an empty arena appropriately for our CPU + */ + + CPUCFG_ARENAINIT(); + + /* + * Round the area used by the firmware to a page boundary and + * mark it in use + */ + + memhi = PHYSADDR((mem_topofmem + 4095) & ~4095); + memlo = PHYSADDR(mem_bottomofmem) & ~4095; + + ARENA_RANGE(memlo,memhi-1,MEMTYPE_DRAM_USEDBYFIRMWARE); + + /* + * Create the initial page table + */ + + cfe_bootarea_init(); + +} + + +/* ********************************************************************* + * cfe_arena_enum(idx,type,start,size) + * + * Enumerate available memory. This is called by the user + * API dispatcher so that operating systems can determine what + * memory regions are available to them. + * + * Input parameters: + * idx - index. Start at zero and increment until an error + * is returned. + * type,start,size: pointers to variables to receive the + * arena entry's information + * allrecs - true to retrieve all records, false to retrieve + * only available DRAM + * + * Return value: + * 0 if ok + * CFE_ERR_NOMORE if idx is beyond the last entry + ********************************************************************* */ + +int cfe_arena_enum(int idx,int *type,uint64_t *start,uint64_t *size,int allrecs) +{ + arena_node_t *node; + queue_t *qb; + arena_t *arena = &cfe_arena; + + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + node = (arena_node_t *) qb; + + if (allrecs || (!allrecs && (node->an_type == MEMTYPE_DRAM_AVAILABLE))) { + if (idx == 0) { + *type = node->an_type; + *start = node->an_address; + *size = node->an_length; + return 0; + } + idx--; + } + } + + return CFE_ERR_NOMORE; + +} + +/* ********************************************************************* + * cfe_arena_loadcheck(start,size) + * + * Determine if the specified memory area is within the available + * DRAM. This is used while loading executables to be sure we + * don't trash the firmware. + * + * Input parameters: + * start - starting physical address + * size - size of requested region + * + * Return value: + * true - ok to copy memory here + * false - not ok, memory overlaps firmware + ********************************************************************* */ + +int cfe_arena_loadcheck(uintptr_t start,unsigned int size) +{ + arena_node_t *node; + queue_t *qb; + arena_t *arena = &cfe_arena; + + /* + * If the address is in our boot area, it's okay + * for it to be a virtual address. + */ + + if ((start >= BOOT_START_ADDRESS) && + ((start+size) <= (BOOT_START_ADDRESS+BOOT_AREA_SIZE))) { + return TRUE; + } + + /* + * Otherwise, make a physical address. + */ + + start = PHYSADDR(start); + + /* + * Because all of the arena nodes of the same type are + * coalesced together, all we need to do is determine if the + * requested region is entirely within an arena node, + * so there's no need to look for things that span nodes. + */ + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + node = (arena_node_t *) qb; + + /* If the memory is available, the region is OK. */ + + if ((start >= node->an_address) && + ((start+size) <= (node->an_address+node->an_length)) && + (node->an_type == MEMTYPE_DRAM_AVAILABLE)) { + return TRUE; + } + } + + /* + * Otherwise, it's not. We could go through the arena again and + * look for regions of other types that intersect the requested + * region, to get a more detailed error, but this'll do. + */ + + return FALSE; + +} + diff --git a/cfe/cfe/main/cfe_rawfs.c b/cfe/cfe/main/cfe_rawfs.c new file mode 100644 index 0000000..4c29349 --- /dev/null +++ b/cfe/cfe/main/cfe_rawfs.c @@ -0,0 +1,293 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "Raw" file system File: cfe_rawfs.c + * + * This filesystem dispatch is used to read files directly + * from a block device. For example, you can 'dd' an elf + * file directly onto a disk or flash card and then run + * it using this module. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_console.h" + +#include "cfe.h" + +/* ********************************************************************* + * RAW context + ********************************************************************* */ + +/* + * File system context - describes overall file system info, + * such as the handle to the underlying device. + */ + +typedef struct raw_fsctx_s { + int raw_dev; + int raw_isconsole; + int raw_refcnt; +} raw_fsctx_t; + +/* + * File context - describes an open file on the file system. + * For raw devices, this is pretty meaningless, but we do + * keep track of where we are. + */ + +typedef struct raw_file_s { + raw_fsctx_t *raw_fsctx; + int raw_fileoffset; + int raw_baseoffset; /* starting offset of raw "file" */ + int raw_length; /* length of file, -1 for whole device */ +} raw_file_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int raw_fileop_init(void **fsctx,void *devicename); +static int raw_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int raw_fileop_read(void *ref,uint8_t *buf,int len); +static int raw_fileop_write(void *ref,uint8_t *buf,int len); +static int raw_fileop_seek(void *ref,int offset,int how); +static void raw_fileop_close(void *ref); +static void raw_fileop_uninit(void *fsctx); + +/* ********************************************************************* + * RAW fileio dispatch table + ********************************************************************* */ + +const fileio_dispatch_t raw_fileops = { + "raw", + 0, + raw_fileop_init, + raw_fileop_open, + raw_fileop_read, + raw_fileop_write, + raw_fileop_seek, + raw_fileop_close, + raw_fileop_uninit +}; + +static int raw_fileop_init(void **newfsctx,void *dev) +{ + raw_fsctx_t *fsctx; + char *devicename = (char *) dev; + + *newfsctx = NULL; + + fsctx = KMALLOC(sizeof(raw_fsctx_t),0); + if (!fsctx) { + return CFE_ERR_NOMEM; + } + + if (strcmp(devicename,console_name) == 0) { + fsctx->raw_dev = console_handle; + fsctx->raw_isconsole = TRUE; + } + else { + fsctx->raw_dev = cfe_open(devicename); + fsctx->raw_isconsole = FALSE; + } + + fsctx->raw_refcnt = 0; + + if (fsctx->raw_dev >= 0) { + *newfsctx = fsctx; + return 0; + } + + KFREE(fsctx); + + return CFE_ERR_FILENOTFOUND; +} + +static int raw_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) +{ + raw_fsctx_t *fsctx; + raw_file_t *file; + char temp[100]; + char *len; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fsctx = (raw_fsctx_t *) fsctx_arg; + + file = KMALLOC(sizeof(raw_file_t),0); + if (!file) { + return CFE_ERR_NOMEM; + } + + file->raw_fileoffset = 0; + file->raw_fsctx = fsctx; + + /* Assume the whole device. */ + file->raw_baseoffset = 0; + file->raw_length = -1; + + /* + * If a filename was specified, it will be in the form + * offset,length - for example, 0x10000,0x200 + * Parse this into two pieces and set up our internal + * file extent information. you can use either decimal + * or "0x" notation. + */ + if (filename) { + lib_trimleading(filename); + strncpy(temp,filename,sizeof(temp)); + len = strchr(temp,','); + if (len) *len++ = '\0'; + if (temp[0]) { + file->raw_baseoffset = lib_atoi(temp); + } + if (len) { + file->raw_length = lib_atoi(len); + } + } + + fsctx->raw_refcnt++; + + *ref = file; + return 0; +} + +static int raw_fileop_read(void *ref,uint8_t *buf,int len) +{ + raw_file_t *file = (raw_file_t *) ref; + int res; + + /* + * Bound the length based on our "file length" if one + * was specified. + */ + + if (file->raw_length >= 0) { + if ((file->raw_length - file->raw_fileoffset) < len) { + len = file->raw_length - file->raw_fileoffset; + } + } + + if (len == 0) return 0; + + /* + * Read the data, adding in the base address. + */ + + res = cfe_readblk(file->raw_fsctx->raw_dev, + file->raw_baseoffset + file->raw_fileoffset, + buf,len); + + if (res > 0) { + file->raw_fileoffset += res; + } + + return res; +} + +static int raw_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + +static int raw_fileop_seek(void *ref,int offset,int how) +{ + raw_file_t *file = (raw_file_t *) ref; + + switch (how) { + case FILE_SEEK_BEGINNING: + file->raw_fileoffset = offset; + break; + case FILE_SEEK_CURRENT: + file->raw_fileoffset += offset; + if (file->raw_fileoffset < 0) file->raw_fileoffset = 0; + break; + default: + break; + } + + /* + * Make sure we don't attempt to seek past the end of the file. + */ + + if (file->raw_length >= 0) { + if (file->raw_fileoffset > file->raw_length) { + file->raw_fileoffset = file->raw_length; + } + } + + return file->raw_fileoffset; +} + + +static void raw_fileop_close(void *ref) +{ + raw_file_t *file = (raw_file_t *) ref; + + file->raw_fsctx->raw_refcnt--; + + KFREE(file); +} + +static void raw_fileop_uninit(void *fsctx_arg) +{ + raw_fsctx_t *fsctx = (raw_fsctx_t *) fsctx_arg; + + if (fsctx->raw_refcnt) { + xprintf("raw_fileop_uninit: warning: refcnt not zero\n"); + } + + if (fsctx->raw_isconsole == FALSE) { + cfe_close(fsctx->raw_dev); + } + + KFREE(fsctx); +} diff --git a/cfe/cfe/main/cfe_savedata.c b/cfe/cfe/main/cfe_savedata.c new file mode 100644 index 0000000..e1d27c4 --- /dev/null +++ b/cfe/cfe/main/cfe_savedata.c @@ -0,0 +1,123 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Data Save routine File: cfe_savedata.c + * + * This module is used for dumping memory to an output device + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_loader.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +/* ********************************************************************* + * cfe_savedata(fsname,filename,start,end) + * + * Write memory contents to the specified device + * + * Input parameters: + * fsname - name of file system + * filename - name of file within file system + * start - starting address (pointer) + * end - ending address (pointer) + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +int cfe_savedata(char *fsname,char *devname,char *filename,uint8_t *start,uint8_t *end) +{ + int res; + fileio_ctx_t *fsctx; + void *ref; + + /* + * Create a file system context + */ + + res = fs_init(fsname,&fsctx,devname); + if (res != 0) { + return res; + } + + /* + * Open the device + */ + + res = fs_open(fsctx,&ref,filename,FILE_MODE_WRITE); + if (res != 0) { + fs_uninit(fsctx); + return res; + } + + /* + * Write the data + */ + + res = fs_write(fsctx,ref,start,end-start); + + /* + * Close + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + return res; + +} + diff --git a/cfe/cfe/main/cfe_timer.c b/cfe/cfe/main/cfe_timer.c new file mode 100644 index 0000000..2b8a0fc --- /dev/null +++ b/cfe/cfe/main/cfe_timer.c @@ -0,0 +1,286 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Timer routines File: cfe_timer.c + * + * This module contains routines to keep track of the system time,. + * Since we don't have any interrupts in the firmware, even the + * timer is polled. The timer must be called often enough + * to prevent missing the overflow of the CP0 COUNT + * register, approximately 2 billion cycles (half the count) + * + * Be sure to use the POLL() macro each time you enter a loop + * where you are waiting for some I/O event to occur or + * are waiting for time to elapse. + * + * It is *not* a time-of-year clock. The timer is only used + * for timing I/O events. + * + * Internally, time is maintained in units of "CLOCKSPERTICK", + * which should be about tenths of seconds. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +#include "cfe.h" + +#include "bsp_config.h" +#include "cpu_config.h" + +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ +#include "boardparms.h" +#include "bcm63xx_util.h" +#include "tftpd.h" +/* Foxconn add end by Jenny Zhao, 07/02/2008*/ + +#ifndef CFG_CPU_SPEED +#define CFG_CPU_SPEED 500000 /* CPU speed in Hz */ +#endif + +#ifndef CPUCFG_CYCLESPERCPUTICK +#define CPUCFG_CYCLESPERCPUTICK 1 /* CPU clock ticks per CP0 COUNT */ +#endif + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern int32_t _getticks(void); /* return value of CP0 COUNT */ + +/* ********************************************************************* + * Data + ********************************************************************* */ + +volatile int64_t cfe_ticks; /* current system time */ + +int cfe_cpu_speed = CFG_CPU_SPEED; /* CPU speed in clocks/second */ + +static unsigned int cfe_clocks_per_usec; +static unsigned int cfe_clocks_per_tick; + +static int32_t cfe_oldcount; /* For keeping track of ticks */ +static int32_t cfe_remticks; +static int cfe_timer_initflg = 0; + +/* + * C0_COUNT clocks per microsecond and per tick. Some CPUs tick CP0 + * every 'n' cycles, that's what CPUCFG_CYCLESPERCPUTICK is for. */ +#define CFE_CLOCKSPERUSEC (cfe_cpu_speed/1000000/(CPUCFG_CYCLESPERCPUTICK)) +#define CFE_CLOCKSPERTICK (cfe_cpu_speed/(CFE_HZ)/(CPUCFG_CYCLESPERCPUTICK)) + +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ +extern int ui_docommands(char *str); + +extern int g_tftp_upgrade_success; +extern int nmrp_server_detected; + +//extern int g_reboot; +///* Foxconn add end by Jenny Zhao, 07/02/2008*/ + +/* ********************************************************************* + * cfe_timer_task() + * + * This routine is called as part of normal device polling to + * update the system time. We read the CP0 COUNT register, + * add the delta into our current time, convert to ticks, + * and keep track of the COUNT register overflow + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + + +static void cfe_timer_task(void *arg) +{ + int32_t count; + int32_t deltaticks; + int32_t clockspertick; + + /* Foxconn add start by Jenny Zhao, 07/02/2008*/ + static int64_t nmrp_previous_trigger_ticks = 0; + static int64_t tftp_previous_trigger_ticks = 0; + static int tftp_led_state = 0; + /* Foxconn add start by Jenny Zhao, 07/02/2008*/ + + clockspertick = CFE_CLOCKSPERTICK; + + count = _getticks(); + + if (count >= cfe_oldcount) { + deltaticks = (count - cfe_oldcount) / clockspertick; + cfe_remticks += (count - cfe_oldcount) % clockspertick; + } + else { + deltaticks = (cfe_oldcount - count) / clockspertick; + cfe_remticks += (cfe_oldcount - count) % clockspertick; + } + + cfe_ticks += deltaticks + (cfe_remticks / clockspertick); + cfe_remticks %= clockspertick; + cfe_oldcount = count; + + /* Foxconn add start by Jenny Zhao, 07/02/2008*/ + if(g_tftp_upgrade_success==1) + { + if((cfe_ticks - nmrp_previous_trigger_ticks) > 5) //500 ms + { + nmrp_previous_trigger_ticks = cfe_ticks; + nmrp_led_toggle(); + } + } + + /* Blink Power LED in tftpd mode */ + if ( (get_tftpd_state() != TFTPD_STATE_OFF) && (nmrp_server_detected==0) ) + { + if(tftp_led_state == 0) //led is off + { + if((cfe_ticks - tftp_previous_trigger_ticks) > 7) //700ms, spec. is 750ms + { + tftp_led_state = 1; + power_led_toggle(tftp_led_state); + tftp_previous_trigger_ticks = cfe_ticks; + } + } + else // led is currently on + { + if((cfe_ticks - tftp_previous_trigger_ticks) > 3) //300ms, spec. is 250ms + { + tftp_led_state = 0; + power_led_toggle(tftp_led_state); + tftp_previous_trigger_ticks = cfe_ticks; + } + } + } + /* Foxconn add end by Jenny Zhao, 07/02/2008*/ +} + + +/* ********************************************************************* + * cfe_timer_init() + * + * Initialize the timer module. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_timer_init(void) +{ + cfe_clocks_per_tick = CFE_CLOCKSPERTICK; + cfe_clocks_per_usec = CFE_CLOCKSPERUSEC; + if (cfe_clocks_per_usec == 0) + cfe_clocks_per_usec = 1; /* for the simulator */ + + cfe_oldcount = _getticks(); /* get current COUNT register */ + cfe_ticks = 0; + + if (!cfe_timer_initflg) { + cfe_bg_add(cfe_timer_task,NULL); /* add task for background polling */ + cfe_timer_initflg = 1; + } +} + + +/* ********************************************************************* + * cfe_sleep(ticks) + * + * Sleep for 'ticks' ticks. Background tasks are processed while + * we wait. + * + * Input parameters: + * ticks - number of ticks to sleep (note: *not* clocks!) + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_sleep(int ticks) +{ + int64_t timer; + + TIMER_SET(timer,ticks); + while (!TIMER_EXPIRED(timer)) { + POLL(); + } +} + + + +/* ********************************************************************* + * cfe_usleep(usec) + * + * Sleep for approximately the specified number of microseconds. + * + * Input parameters: + * usec - number of microseconds to wait + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_usleep(int usec) +{ + uint32_t newcount; + uint32_t now; + + /* XXX fix the wrap problem */ + + now = _getticks(); + newcount = now + usec*cfe_clocks_per_usec; + + if (newcount < now) /* wait for wraparound */ + while (_getticks() > now) + ; + + + while (_getticks() < newcount) + ; +} diff --git a/cfe/cfe/main/cfe_version.mk b/cfe/cfe/main/cfe_version.mk new file mode 100755 index 0000000..653cbf9 --- /dev/null +++ b/cfe/cfe/main/cfe_version.mk @@ -0,0 +1,12 @@ + +# +# CFE's version number +# Warning: Don't put spaces on either side of the equal signs +# Put just the version number in here. This file is sourced +# like a shell script in some cases! +# + +CFE_VER_MAJ=1 +CFE_VER_MIN=0 +CFE_VER_ECO=37 + diff --git a/cfe/cfe/main/cfe_xreq.c b/cfe/cfe/main/cfe_xreq.c new file mode 100644 index 0000000..d12b1f2 --- /dev/null +++ b/cfe/cfe/main/cfe_xreq.c @@ -0,0 +1,346 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB dispatcher File: cfe_xreq.c + * + * This routine is the main API dispatch for CFE. User API + * calls, via the ROM entry point, get dispatched to routines + * in this module. + * + * This module looks similar to cfe_iocb_dispatch - it is different + * in that the data structure used, cfe_xiocb_t, uses fixed + * size field members (specifically, all 64-bits) no matter how + * the firmware is compiled. This ensures a consistent API + * interface on any implementation. When you call CFE + * from another program, the entry vector comes here first. + * + * Should the normal cfe_iocb interface change, this one should + * be kept the same for backward compatibility reasons. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "bsp_config.h" +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_xiocb.h" +#if CFG_VENDOR_EXTENSIONS +#include "cfe_vendor_iocb.h" +#include "cfe_vendor_xiocb.h" +#endif +#include "cfe_error.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_mem.h" +#include "env_subr.h" +#include "cfe.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* enum values for various plist types */ + +#define PLBUF 1 /* iocb_buffer_t */ +#define PLCPU 2 /* iocb_cpuctl_t */ +#define PLMEM 3 /* iocb_meminfo_t */ +#define PLENV 4 /* iocb_envbuf_t */ +#define PLINP 5 /* iocb_inpstat_t */ +#define PLTIM 6 /* iocb_time_t */ +#define PLINF 7 /* iocb_fwinfo_t */ +#define PLEXIT 8 /* iocb_exitstat_t */ + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +struct cfe_xcmd_dispatch_s { + int xplistsize; + int iplistsize; + int plisttype; +}; + + +/* ********************************************************************* + * Command conversion table + * This table contains useful information for converting + * iocbs to xiocbs. + ********************************************************************* */ + +const static struct cfe_xcmd_dispatch_s cfe_xcmd_dispatch_table[CFE_CMD_MAX] = { + {sizeof(xiocb_fwinfo_t), sizeof(iocb_fwinfo_t), PLINF}, /* 0 : CFE_CMD_FW_GETINFO */ + {sizeof(xiocb_exitstat_t),sizeof(iocb_exitstat_t),PLEXIT}, /* 1 : CFE_CMD_FW_RESTART */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 2 : CFE_CMD_FW_BOOT */ + {sizeof(xiocb_cpuctl_t), sizeof(iocb_cpuctl_t), PLCPU}, /* 3 : CFE_CMD_FW_CPUCTL */ + {sizeof(xiocb_time_t), sizeof(iocb_time_t), PLTIM}, /* 4 : CFE_CMD_FW_GETTIME */ + {sizeof(xiocb_meminfo_t),sizeof(iocb_meminfo_t),PLMEM}, /* 5 : CFE_CMD_FW_MEMENUM */ + {0, 0, 0}, /* 6 : CFE_CMD_FW_FLUSHCACHE */ + {-1, 0, 0}, /* 7 : */ + {-1, 0, 0}, /* 8 : */ + {0, 0, 0}, /* 9 : CFE_CMD_DEV_GETHANDLE */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 10 : CFE_CMD_DEV_ENUM */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 11 : CFE_CMD_DEV_OPEN_*/ + {sizeof(xiocb_inpstat_t),sizeof(iocb_inpstat_t),PLINP}, /* 12 : CFE_CMD_DEV_INPSTAT */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 13 : CFE_CMD_DEV_READ */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 14 : CFE_CMD_DEV_WRITE */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 15 : CFE_CMD_DEV_IOCTL */ + {0, 0, 0}, /* 16 : CFE_CMD_DEV_CLOSE */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 17 : CFE_CMD_DEV_GETINFO */ + {-1, 0, 0}, /* 18 : */ + {-1, 0, 0}, /* 19 : */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 20 : CFE_CMD_ENV_ENUM */ + {-1, 0, 0}, /* 21 : */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 22 : CFE_CMD_ENV_GET */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 23 : CFE_CMD_ENV_SET */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 24 : CFE_CMD_ENV_DEL */ + {-1, 0, 0}, /* 25 : */ + {-1, 0, 0}, /* 26 : */ + {-1, 0, 0}, /* 27 : */ + {-1, 0, 0}, /* 28 : */ + {-1, 0, 0}, /* 29 : */ + {-1, 0, 0}, /* 30 : */ + {-1, 0, 0} /* 31 : */ +}; + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern int cfe_iocb_dispatch(cfe_iocb_t *iocb); +cfe_int_t cfe_doxreq(cfe_xiocb_t *xiocb); +#if CFG_VENDOR_EXTENSIONS +extern cfe_int_t cfe_vendor_doxreq(cfe_vendor_xiocb_t *xiocb); +#endif + +/* ********************************************************************* + * cfe_doxreq(xiocb) + * + * Process an xiocb request. This routine converts an xiocb + * into an iocb, calls the IOCB dispatcher, converts the results + * back into the xiocb, and returns. + * + * Input parameters: + * xiocb - pointer to user xiocb + * + * Return value: + * command status, <0 if error occured + ********************************************************************* */ + +cfe_int_t cfe_doxreq(cfe_xiocb_t *xiocb) +{ + const struct cfe_xcmd_dispatch_s *disp; + cfe_iocb_t iiocb; + cfe_int_t res; + + /* + * Call out to customer-specific IOCBs. Customers may choose + * to implement their own XIOCBs directly, or go through their own + * translation layer (xiocb->iocb like CFE does) to insulate + * themselves from IOCB changes in the future. + */ + if (xiocb->xiocb_fcode >= CFE_CMD_VENDOR_USE) { +#if CFG_VENDOR_EXTENSIONS + return cfe_vendor_doxreq((cfe_vendor_xiocb_t *)xiocb); +#else + return CFE_ERR_INV_COMMAND; +#endif + } + + /* + * Check for commands codes out of range + */ + + if ((xiocb->xiocb_fcode < 0) || (xiocb->xiocb_fcode >= CFE_CMD_MAX)) { + xiocb->xiocb_status = CFE_ERR_INV_COMMAND; + return xiocb->xiocb_status; + } + + /* + * Check for command codes in range but invalid + */ + + disp = &cfe_xcmd_dispatch_table[xiocb->xiocb_fcode]; + + if (disp->xplistsize < 0) { + xiocb->xiocb_status = CFE_ERR_INV_COMMAND; + return xiocb->xiocb_status; + } + + /* + * Check for invalid parameter list size + */ + + if (disp->xplistsize != xiocb->xiocb_psize) { + xiocb->xiocb_status = CFE_ERR_INV_PARAM; + return xiocb->xiocb_status; + } + + /* + * Okay, copy parameters into the internal IOCB. + * First, the fixed header. + */ + + iiocb.iocb_fcode = (unsigned int) xiocb->xiocb_fcode; + iiocb.iocb_status = (int) xiocb->xiocb_status; + iiocb.iocb_handle = (int) xiocb->xiocb_handle; + iiocb.iocb_flags = (unsigned int) xiocb->xiocb_flags; + iiocb.iocb_psize = (unsigned int) disp->iplistsize; + + /* + * Now the parameter list + */ + + switch (disp->plisttype) { + case PLBUF: + iiocb.plist.iocb_buffer.buf_offset = (cfe_offset_t) xiocb->plist.xiocb_buffer.buf_offset; + iiocb.plist.iocb_buffer.buf_ptr = (unsigned char *) (uintptr_t) xiocb->plist.xiocb_buffer.buf_ptr; + iiocb.plist.iocb_buffer.buf_length = (unsigned int) xiocb->plist.xiocb_buffer.buf_length; + iiocb.plist.iocb_buffer.buf_retlen = (unsigned int) xiocb->plist.xiocb_buffer.buf_retlen; + iiocb.plist.iocb_buffer.buf_ioctlcmd = (unsigned int) xiocb->plist.xiocb_buffer.buf_ioctlcmd; + break; + case PLCPU: + iiocb.plist.iocb_cpuctl.cpu_number = (unsigned int) xiocb->plist.xiocb_cpuctl.cpu_number; + iiocb.plist.iocb_cpuctl.cpu_command = (unsigned int) xiocb->plist.xiocb_cpuctl.cpu_command; + iiocb.plist.iocb_cpuctl.start_addr = (unsigned long) xiocb->plist.xiocb_cpuctl.start_addr; + iiocb.plist.iocb_cpuctl.gp_val = (unsigned long) xiocb->plist.xiocb_cpuctl.gp_val; + iiocb.plist.iocb_cpuctl.sp_val = (unsigned long) xiocb->plist.xiocb_cpuctl.sp_val; + iiocb.plist.iocb_cpuctl.a1_val = (unsigned long) xiocb->plist.xiocb_cpuctl.a1_val; + break; + case PLMEM: + iiocb.plist.iocb_meminfo.mi_idx = (int) xiocb->plist.xiocb_meminfo.mi_idx; + iiocb.plist.iocb_meminfo.mi_type = (int) xiocb->plist.xiocb_meminfo.mi_type; + iiocb.plist.iocb_meminfo.mi_addr = (unsigned long long) xiocb->plist.xiocb_meminfo.mi_addr; + iiocb.plist.iocb_meminfo.mi_size = (unsigned long long) xiocb->plist.xiocb_meminfo.mi_size; + break; + case PLENV: + iiocb.plist.iocb_envbuf.enum_idx = (int) xiocb->plist.xiocb_envbuf.enum_idx; + iiocb.plist.iocb_envbuf.name_ptr = (unsigned char *) (uintptr_t) xiocb->plist.xiocb_envbuf.name_ptr; + iiocb.plist.iocb_envbuf.name_length = (int) xiocb->plist.xiocb_envbuf.name_length; + iiocb.plist.iocb_envbuf.val_ptr = (unsigned char *) (uintptr_t) xiocb->plist.xiocb_envbuf.val_ptr; + iiocb.plist.iocb_envbuf.val_length = (int) xiocb->plist.xiocb_envbuf.val_length; + break; + case PLINP: + iiocb.plist.iocb_inpstat.inp_status = (int) xiocb->plist.xiocb_inpstat.inp_status; + break; + case PLTIM: + iiocb.plist.iocb_time.ticks = (long long) xiocb->plist.xiocb_time.ticks; + break; + case PLINF: + break; + case PLEXIT: + iiocb.plist.iocb_exitstat.status = (long long) xiocb->plist.xiocb_exitstat.status; + break; + } + + /* + * Do the internal function dispatch + */ + + res = (cfe_int_t) cfe_iocb_dispatch(&iiocb); + + /* + * Now convert the parameter list members back + */ + + switch (disp->plisttype) { + case PLBUF: + xiocb->plist.xiocb_buffer.buf_offset = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_offset; + xiocb->plist.xiocb_buffer.buf_ptr = (cfe_xptr_t) (uintptr_t) iiocb.plist.iocb_buffer.buf_ptr; + xiocb->plist.xiocb_buffer.buf_length = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_length; + xiocb->plist.xiocb_buffer.buf_retlen = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_retlen; + xiocb->plist.xiocb_buffer.buf_ioctlcmd = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_ioctlcmd; + break; + case PLCPU: + xiocb->plist.xiocb_cpuctl.cpu_number = (cfe_uint_t) iiocb.plist.iocb_cpuctl.cpu_number; + xiocb->plist.xiocb_cpuctl.cpu_command = (cfe_uint_t) iiocb.plist.iocb_cpuctl.cpu_command; + xiocb->plist.xiocb_cpuctl.start_addr = (cfe_uint_t) iiocb.plist.iocb_cpuctl.start_addr; + break; + case PLMEM: + xiocb->plist.xiocb_meminfo.mi_idx = (cfe_int_t) iiocb.plist.iocb_meminfo.mi_idx; + xiocb->plist.xiocb_meminfo.mi_type = (cfe_int_t) iiocb.plist.iocb_meminfo.mi_type; + xiocb->plist.xiocb_meminfo.mi_addr = (cfe_int64_t) iiocb.plist.iocb_meminfo.mi_addr; + xiocb->plist.xiocb_meminfo.mi_size = (cfe_int64_t) iiocb.plist.iocb_meminfo.mi_size; + break; + case PLENV: + xiocb->plist.xiocb_envbuf.enum_idx = (cfe_int_t) iiocb.plist.iocb_envbuf.enum_idx; + xiocb->plist.xiocb_envbuf.name_ptr = (cfe_xptr_t) (uintptr_t) iiocb.plist.iocb_envbuf.name_ptr; + xiocb->plist.xiocb_envbuf.name_length = (cfe_int_t) iiocb.plist.iocb_envbuf.name_length; + xiocb->plist.xiocb_envbuf.val_ptr = (cfe_xptr_t) (uintptr_t) iiocb.plist.iocb_envbuf.val_ptr; + xiocb->plist.xiocb_envbuf.val_length = (cfe_int_t) iiocb.plist.iocb_envbuf.val_length; + break; + case PLINP: + xiocb->plist.xiocb_inpstat.inp_status = (cfe_int_t) iiocb.plist.iocb_inpstat.inp_status; + break; + case PLTIM: + xiocb->plist.xiocb_time.ticks = (cfe_int_t) iiocb.plist.iocb_time.ticks; + break; + case PLINF: + xiocb->plist.xiocb_fwinfo.fwi_version = iiocb.plist.iocb_fwinfo.fwi_version; + xiocb->plist.xiocb_fwinfo.fwi_totalmem = iiocb.plist.iocb_fwinfo.fwi_totalmem; + xiocb->plist.xiocb_fwinfo.fwi_flags = iiocb.plist.iocb_fwinfo.fwi_flags; + xiocb->plist.xiocb_fwinfo.fwi_boardid = iiocb.plist.iocb_fwinfo.fwi_boardid; + xiocb->plist.xiocb_fwinfo.fwi_bootarea_va = iiocb.plist.iocb_fwinfo.fwi_bootarea_va; + xiocb->plist.xiocb_fwinfo.fwi_bootarea_pa = iiocb.plist.iocb_fwinfo.fwi_bootarea_pa; + xiocb->plist.xiocb_fwinfo.fwi_bootarea_size = iiocb.plist.iocb_fwinfo.fwi_bootarea_size; + xiocb->plist.xiocb_fwinfo.fwi_reserved1 = iiocb.plist.iocb_fwinfo.fwi_reserved1; + xiocb->plist.xiocb_fwinfo.fwi_reserved2 = iiocb.plist.iocb_fwinfo.fwi_reserved2; + xiocb->plist.xiocb_fwinfo.fwi_reserved3 = iiocb.plist.iocb_fwinfo.fwi_reserved3; + break; + case PLEXIT: + xiocb->plist.xiocb_exitstat.status = (cfe_int_t) iiocb.plist.iocb_exitstat.status; + break; + } + + /* + * And the fixed header + */ + + xiocb->xiocb_status = (cfe_int_t) iiocb.iocb_status; + xiocb->xiocb_handle = (cfe_int_t) iiocb.iocb_handle; + xiocb->xiocb_flags = (cfe_uint_t) iiocb.iocb_flags; + + return xiocb->xiocb_status; +} diff --git a/cfe/cfe/main/cfe_zlibfs.c b/cfe/cfe/main/cfe_zlibfs.c new file mode 100644 index 0000000..7ad0847 --- /dev/null +++ b/cfe/cfe/main/cfe_zlibfs.c @@ -0,0 +1,453 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "Compressed" file system File: cfe_zlibfs.c + * + * This is more of a filesystem "hook" than an actual file system. + * You can stick it on the front of the chain of file systems + * that CFE calls and it will route data read from the + * underlying filesystem through ZLIB before passing it up to the + * user. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#if CFG_ZLIB + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_console.h" + +#include "cfe.h" + +#include "zlib.h" + +/* ********************************************************************* + * ZLIBFS context + ********************************************************************* */ + +/* + * File system context - describes overall file system info, + * such as the handle to the underlying device. + */ + +typedef struct zlibfs_fsctx_s { + void *zlibfsctx_subfsctx; + const fileio_dispatch_t *zlibfsctx_subops; + int zlibfsctx_refcnt; +} zlibfs_fsctx_t; + +/* + * File context - describes an open file on the file system. + * For raw devices, this is pretty meaningless, but we do + * keep track of where we are. + */ + +#define ZLIBFS_BUFSIZE 1024 +typedef struct zlibfs_file_s { + zlibfs_fsctx_t *zlibfs_fsctx; + int zlibfs_fileoffset; + void *zlibfs_subfile; + z_stream zlibfs_stream; + uint8_t *zlibfs_inbuf; + uint8_t *zlibfs_outbuf; + int zlibfs_outlen; + uint8_t *zlibfs_outptr; + int zlibfs_eofseen; +} zlibfs_file_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int zlibfs_fileop_init(void **fsctx,void *ctx); +static int zlibfs_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int zlibfs_fileop_read(void *ref,uint8_t *buf,int len); +static int zlibfs_fileop_write(void *ref,uint8_t *buf,int len); +static int zlibfs_fileop_seek(void *ref,int offset,int how); +static void zlibfs_fileop_close(void *ref); +static void zlibfs_fileop_uninit(void *fsctx); + +voidpf zcalloc(voidpf opaque,unsigned items, unsigned size); +void zcfree(voidpf opaque,voidpf ptr); + +/* ********************************************************************* + * ZLIB fileio dispatch table + ********************************************************************* */ + + +static uint8_t gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +const fileio_dispatch_t zlibfs_fileops = { + "z", + 0, + zlibfs_fileop_init, + zlibfs_fileop_open, + zlibfs_fileop_read, + zlibfs_fileop_write, + zlibfs_fileop_seek, + zlibfs_fileop_close, + zlibfs_fileop_uninit +}; + +/* + * Utility functions needed by the ZLIB routines + */ +voidpf zcalloc(voidpf opaque,unsigned items, unsigned size) +{ + void *ptr; + + ptr = KMALLOC(items*size,0); + if (ptr) lib_memset(ptr,0,items*size); + return ptr; +} + +void zcfree(voidpf opaque,voidpf ptr) +{ + KFREE(ptr); +} + + +static int zlibfs_fileop_init(void **newfsctx,void *curfsvoid) +{ + zlibfs_fsctx_t *fsctx; + fileio_ctx_t *curfsctx = (fileio_ctx_t *) curfsvoid; + + *newfsctx = NULL; + + fsctx = KMALLOC(sizeof(zlibfs_fsctx_t),0); + if (!fsctx) { + return CFE_ERR_NOMEM; + } + + fsctx->zlibfsctx_refcnt = 0; + fsctx->zlibfsctx_subops = curfsctx->ops; + fsctx->zlibfsctx_subfsctx = curfsctx->fsctx; + + *newfsctx = fsctx; + + return 0; +} + + +static int get_byte(zlibfs_file_t *file,uint8_t *ch) +{ + int res; + + res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops, + file->zlibfs_subfile, + ch, + 1); + + return res; +} + + +static int check_header(zlibfs_file_t *file) +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + uint8_t c; + int res; + + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + res = get_byte(file,&c); + if (c != gz_magic[len]) { + return -1; + } + } + + get_byte(file,&c); method = (int) c; + get_byte(file,&c); flags = (int) c; + + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + return -1; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(file,&c); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + get_byte(file,&c); + len = (uInt) c; + get_byte(file,&c); + len += ((uInt)c)<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while ((len-- != 0) && (get_byte(file,&c) == 1)) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((get_byte(file,&c) == 1) && (c != 0)) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((get_byte(file,&c) == 1) && (c != 0)) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(file,&c); + } + + return 0; +} + +static int zlibfs_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) +{ + zlibfs_fsctx_t *fsctx; + zlibfs_file_t *file; + int err; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fsctx = (zlibfs_fsctx_t *) fsctx_arg; + + file = KMALLOC(sizeof(zlibfs_file_t),0); + if (!file) { + return CFE_ERR_NOMEM; + } + + file->zlibfs_fileoffset = 0; + file->zlibfs_fsctx = fsctx; + file->zlibfs_inbuf = NULL; + file->zlibfs_outbuf = NULL; + file->zlibfs_eofseen = 0; + + err = BDOPEN(fsctx->zlibfsctx_subops,&(file->zlibfs_subfile), + fsctx->zlibfsctx_subfsctx,filename); + + if (err != 0) { + goto error2; + return err; + } + + /* Open the zstream */ + + file->zlibfs_inbuf = KMALLOC(ZLIBFS_BUFSIZE,0); + file->zlibfs_outbuf = KMALLOC(ZLIBFS_BUFSIZE,0); + + if (!file->zlibfs_inbuf || !file->zlibfs_outbuf) { + err = CFE_ERR_NOMEM; + goto error; + } + + file->zlibfs_stream.next_in = NULL; + file->zlibfs_stream.avail_in = 0; + file->zlibfs_stream.next_out = file->zlibfs_outbuf; + file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE; + file->zlibfs_stream.zalloc = (alloc_func)0; + file->zlibfs_stream.zfree = (free_func)0; + + file->zlibfs_outlen = 0; + file->zlibfs_outptr = file->zlibfs_outbuf; + + err = inflateInit2(&(file->zlibfs_stream),-15); + if (err != Z_OK) { + err = CFE_ERR; + goto error; + } + + check_header(file); + + fsctx->zlibfsctx_refcnt++; + + *ref = file; + return 0; + +error: + BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile); +error2: + if (file->zlibfs_inbuf) KFREE(file->zlibfs_inbuf); + if (file->zlibfs_outbuf) KFREE(file->zlibfs_outbuf); + KFREE(file); + return err; +} + +static int zlibfs_fileop_read(void *ref,uint8_t *buf,int len) +{ + zlibfs_file_t *file = (zlibfs_file_t *) ref; + int res = 0; + int err; + int amtcopy; + int ttlcopy = 0; + + if (len == 0) return 0; + + while (len) { + + /* Figure the amount to copy. This is the min of what we + have left to do and what is available. */ + amtcopy = len; + if (amtcopy > file->zlibfs_outlen) { + amtcopy = file->zlibfs_outlen; + } + + /* Copy the data. */ + + if (buf) { + memcpy(buf,file->zlibfs_outptr,amtcopy); + buf += amtcopy; + } + + /* Update the pointers. */ + file->zlibfs_outptr += amtcopy; + file->zlibfs_outlen -= amtcopy; + len -= amtcopy; + ttlcopy += amtcopy; + + /* If we've eaten all of the output, reset and call inflate + again. */ + + if (file->zlibfs_outlen == 0) { + /* If no input data to decompress, get some more if we can. */ + if (file->zlibfs_eofseen) break; + if (file->zlibfs_stream.avail_in == 0) { + res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops, + file->zlibfs_subfile, + file->zlibfs_inbuf, + ZLIBFS_BUFSIZE); + /* If at EOF or error, get out. */ + if (res <= 0) break; + file->zlibfs_stream.next_in = file->zlibfs_inbuf; + file->zlibfs_stream.avail_in = res; + } + + /* inflate the input data. */ + file->zlibfs_stream.next_out = file->zlibfs_outbuf; + file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE; + file->zlibfs_outptr = file->zlibfs_outbuf; + err = inflate(&(file->zlibfs_stream),Z_SYNC_FLUSH); + if (err == Z_STREAM_END) { + /* We can get a partial buffer fill here. */ + file->zlibfs_eofseen = 1; + } + else if (err != Z_OK) { + res = CFE_ERR; + break; + } + file->zlibfs_outlen = file->zlibfs_stream.next_out - + file->zlibfs_outptr; + } + + } + + file->zlibfs_fileoffset += ttlcopy; + + return (res < 0) ? res : ttlcopy; +} + +static int zlibfs_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + +static int zlibfs_fileop_seek(void *ref,int offset,int how) +{ + zlibfs_file_t *file = (zlibfs_file_t *) ref; + int res; + int delta; + + switch (how) { + case FILE_SEEK_BEGINNING: + delta = offset - file->zlibfs_fileoffset; + break; + case FILE_SEEK_CURRENT: + delta = offset; + break; + default: + return CFE_ERR_UNSUPPORTED; + break; + } + + /* backward seeking not allowed on compressed streams */ + if (delta < 0) { + return CFE_ERR_UNSUPPORTED; + } + + res = zlibfs_fileop_read(ref,NULL,delta); + + if (res < 0) return res; + + return file->zlibfs_fileoffset; +} + + +static void zlibfs_fileop_close(void *ref) +{ + zlibfs_file_t *file = (zlibfs_file_t *) ref; + + file->zlibfs_fsctx->zlibfsctx_refcnt--; + + inflateEnd(&(file->zlibfs_stream)); + + BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile); + + KFREE(file); +} + +static void zlibfs_fileop_uninit(void *fsctx_arg) +{ + zlibfs_fsctx_t *fsctx = (zlibfs_fsctx_t *) fsctx_arg; + + if (fsctx->zlibfsctx_refcnt) { + xprintf("zlibfs_fileop_uninit: warning: refcnt not zero\n"); + } + + BDUNINIT(fsctx->zlibfsctx_subops,fsctx->zlibfsctx_subfsctx); + + KFREE(fsctx); +} + + +#endif diff --git a/cfe/cfe/main/env_subr.c b/cfe/cfe/main/env_subr.c new file mode 100644 index 0000000..5f12359 --- /dev/null +++ b/cfe/cfe/main/env_subr.c @@ -0,0 +1,474 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Environment variable subroutines File: env_subr.c + * + * This module contains routines to muck with environment variables + * (manage the list, read/write to nvram, etc.) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "env_subr.h" +#include "nvram_subr.h" + +#include "cfe_error.h" +#include "cfe.h" + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef struct cfe_envvar_s { + queue_t qb; + int flags; + char *name; + char *value; + /* name and value go here */ +} cfe_envvar_t; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +queue_t env_envvars = {&env_envvars,&env_envvars}; +extern unsigned int cfe_startflags; + +/* ********************************************************************* + * env_findenv(name) + * + * Locate an environment variable in the in-memory list + * + * Input parameters: + * name - name of env var to find + * + * Return value: + * cfe_envvar_t pointer, or NULL if not found + ********************************************************************* */ + +static cfe_envvar_t *env_findenv(const char *name) +{ + queue_t *qb; + cfe_envvar_t *env; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + env = (cfe_envvar_t *) qb; + if (strcmp(env->name,name) == 0) break; + } + + if (qb == &env_envvars) return NULL; + + return (cfe_envvar_t *) qb; + +} + +/* ********************************************************************* + * env_enum(idx,name,namelen,val,vallen) + * + * Enumerate environment variables. This routine locates + * the nth environment variable and copies its name and value + * to user buffers. + * + * The namelen and vallen variables must be preinitialized to + * the maximum size of the output buffer. + * + * Input parameters: + * idx - variable index to find (starting with zero) + * name,namelen - name buffer and length + * val,vallen - value buffer and length + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_enum(int idx,char *name,int *namelen,char *val,int *vallen) +{ + queue_t *qb; + cfe_envvar_t *env; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + if (idx == 0) break; + idx--; + } + + if (qb == &env_envvars) return CFE_ERR_ENVNOTFOUND; + env = (cfe_envvar_t *) qb; + + *namelen = xstrncpy(name,env->name,*namelen); + *vallen = xstrncpy(val,env->value,*vallen); + + return 0; + +} + +/* ********************************************************************* + * env_envtype(name) + * + * Return the type of the environment variable + * + * Input parameters: + * name - name of environment variable + * + * Return value: + * flags, or <0 if error occured + ********************************************************************* */ +int env_envtype(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (env) { + return env->flags; + } + + return CFE_ERR_ENVNOTFOUND; +} + + + +/* ********************************************************************* + * env_delenv(name) + * + * Delete an environment variable + * + * Input parameters: + * name - environment variable to delete + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_delenv(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (!env) return 0; + + if (!(env->flags & ENV_FLG_READONLY)) { + q_dequeue((queue_t *) env); + KFREE(env); + return 0; + } + + return CFE_ERR_ENVNOTFOUND; +} + +/* ********************************************************************* + * env_getenv(name) + * + * Retrieve the value of an environment variable + * + * Input parameters: + * name - name of environment variable to find + * + * Return value: + * value, or NULL if variable is not found + ********************************************************************* */ + +char *env_getenv(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (env) { + return env->value; + } + + return NULL; +} + + +/* ********************************************************************* + * env_setenv(name,value,flags) + * + * Set the value of an environment variable + * + * Input parameters: + * name - name of variable + * value - value of variable + * flags - flags for variable (ENV_FLG_xxx) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_setenv(const char *name,char *value,int flags) +{ + cfe_envvar_t *env; + int namelen; + + env = env_findenv(name); + if (env) { + if (!(flags & ENV_FLG_ADMIN)) { + if (env->flags & ENV_FLG_READONLY) return CFE_ERR_ENVREADONLY; + } + q_dequeue((queue_t *) env); + KFREE(env); + } + + namelen = strlen(name); + + env = KMALLOC(sizeof(cfe_envvar_t) + namelen + 1 + strlen(value) + 1,0); + if (!env) return CFE_ERR_NOMEM; + + env->name = (char *) (env+1); + env->value = env->name + namelen + 1; + env->flags = (flags & ENV_FLG_MASK); + + strcpy(env->name,name); + strcpy(env->value,value); + + q_enqueue(&env_envvars,(queue_t *) env); + + return 0; +} + + +/* ********************************************************************* + * env_load() + * + * Load the environment from the NVRAM device. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + + +int env_load(void) +{ + int size; + unsigned char *buffer; + unsigned char *ptr; + unsigned char *envval; + unsigned int reclen; + unsigned int rectype; + int offset; + int flg; + int retval = -1; + char valuestr[256]; + + /* + * If in 'safe mode', don't read the environment the first time. + */ + + if (cfe_startflags & CFE_INIT_SAFE) { + cfe_startflags &= ~CFE_INIT_SAFE; + return 0; + } + + flg = nvram_open(); + if (flg < 0) return flg; + + size = nvram_getsize(); + buffer = KMALLOC(size,0); + + if (buffer == NULL) return CFE_ERR_NOMEM; + + ptr = buffer; + offset = 0; + + /* Read the record type and length */ + if (nvram_read(ptr,offset,1) != 1) { + retval = CFE_ERR_IOERR; + goto error; + } + + while ((*ptr != ENV_TLV_TYPE_END) && (size > 1)) { + + /* Adjust pointer for TLV type */ + rectype = *(ptr); + offset++; + size--; + + /* + * Read the length. It can be either 1 or 2 bytes + * depending on the code + */ + if (rectype & ENV_LENGTH_8BITS) { + /* Read the record type and length - 8 bits */ + if (nvram_read(ptr,offset,1) != 1) { + retval = CFE_ERR_IOERR; + goto error; + } + reclen = *(ptr); + size--; + offset++; + } + else { + /* Read the record type and length - 16 bits, MSB first */ + if (nvram_read(ptr,offset,2) != 2) { + retval = CFE_ERR_IOERR; + goto error; + } + reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1); + size -= 2; + offset += 2; + } + + if (reclen > size) break; /* should not happen, bad NVRAM */ + + switch (rectype) { + case ENV_TLV_TYPE_ENV: + /* Read the TLV data */ + if (nvram_read(ptr,offset,reclen) != reclen) goto error; + flg = *ptr++; + envval = (unsigned char *) strnchr(ptr,'=',(reclen-1)); + if (envval) { + *envval++ = '\0'; + memcpy(valuestr,envval,(reclen-1)-(envval-ptr)); + valuestr[(reclen-1)-(envval-ptr)] = '\0'; + env_setenv(ptr,valuestr,flg); + } + break; + + default: + /* Unknown TLV type, skip it. */ + break; + } + + /* + * Advance to next TLV + */ + + size -= (int)reclen; + offset += reclen; + + /* Read the next record type */ + ptr = buffer; + if (nvram_read(ptr,offset,1) != 1) goto error; + } + + retval = 0; /* success! */ + +error: + KFREE(buffer); + nvram_close(); + + return retval; + +} + + +/* ********************************************************************* + * env_save() + * + * Write the environment to the NVRAM device. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int env_save(void) +{ + int size; + unsigned char *buffer; + unsigned char *buffer_end; + unsigned char *ptr; + queue_t *qb; + cfe_envvar_t *env; + int namelen; + int valuelen; + int flg; + + flg = nvram_open(); + if (flg < 0) return flg; + + nvram_erase(); + + size = nvram_getsize(); + buffer = KMALLOC(size,0); + + if (buffer == NULL) return CFE_ERR_NOMEM; + + buffer_end = buffer + size; + + ptr = buffer; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + env = (cfe_envvar_t *) qb; + + if (env->flags & (ENV_FLG_BUILTIN)) continue; + + namelen = strlen(env->name); + valuelen = strlen(env->value); + + if ((ptr + 2 + namelen + valuelen + 1 + 1 + 1) > buffer_end) break; + + *ptr++ = ENV_TLV_TYPE_ENV; /* TLV record type */ + *ptr++ = (namelen + valuelen + 1 + 1); /* TLV record length */ + + *ptr++ = (unsigned char)env->flags; + memcpy(ptr,env->name,namelen); /* TLV record data */ + ptr += namelen; + *ptr++ = '='; + memcpy(ptr,env->value,valuelen); + ptr += valuelen; + + } + + *ptr++ = ENV_TLV_TYPE_END; + + size = nvram_write(buffer,0,ptr-buffer); + + KFREE(buffer); + + nvram_close(); + + return (size == (ptr-buffer)) ? 0 : CFE_ERR_IOERR; +} diff --git a/cfe/cfe/main/nvram_subr.c b/cfe/cfe/main/nvram_subr.c new file mode 100644 index 0000000..2c44bca --- /dev/null +++ b/cfe/cfe/main/nvram_subr.c @@ -0,0 +1,300 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NVRAM subroutines File: nvram_subr.c + * + * High-level routines to read/write the NVRAM device. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" + +#include "cfe_error.h" +#include "env_subr.h" +#include "nvram_subr.h" +#include "cfe.h" + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +static int nvram_handle = -1; +static nvram_info_t nvram_info; +static char *nvram_devname = NULL; + +/* ********************************************************************* + * nvram_getinfo(info) + * + * Obtain information about the NVRAM device from the device + * driver. A flash device might only dedicate a single sector + * to the environment, so we need to ask the driver first. + * + * Input parameters: + * info - nvram info + * + * Return value: + * 0 if ok + * <0 = error code + ********************************************************************* */ + +static int nvram_getinfo(nvram_info_t *info) +{ + int retlen; + + if (nvram_handle == -1) return -1; + + cfe_ioctl(nvram_handle,IOCTL_NVRAM_UNLOCK,NULL,0,NULL,0); + + if (cfe_ioctl(nvram_handle,IOCTL_NVRAM_GETINFO, + (unsigned char *) info, + sizeof(nvram_info_t), + &retlen,0) != 0) { + return -1; + } + + return 0; + +} + +/* ********************************************************************* + * nvram_open() + * + * Open the default NVRAM device and get the information from the + * device driver. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int nvram_open(void) +{ + if (nvram_handle != -1) { + nvram_close(); + } + + if (nvram_devname == NULL) { + return CFE_ERR_DEVNOTFOUND; + } + + nvram_handle = cfe_open(nvram_devname); + + if (nvram_handle < 0) { + return CFE_ERR_DEVNOTFOUND; + } + + if (nvram_getinfo(&nvram_info) < 0) { + nvram_close(); + return CFE_ERR_IOERR; + } + + return 0; +} + +/* ********************************************************************* + * nvram_close() + * + * Close the NVRAM device + * + * Input parameters: + * nothing + * + * Return value: + * 0 + ********************************************************************* */ + +int nvram_close(void) +{ + if (nvram_handle != -1) { + cfe_close(nvram_handle); + nvram_handle = -1; + } + + return 0; +} + + +/* ********************************************************************* + * nvram_getsize() + * + * Return the total size of the NVRAM device. Note that + * this is the total size that is used for the NVRAM functions, + * not the size of the underlying media. + * + * Input parameters: + * nothing + * + * Return value: + * size. <0 if error + ********************************************************************* */ + +int nvram_getsize(void) +{ + if (nvram_handle < 0) return 0; + return nvram_info.nvram_size; +} + + +/* ********************************************************************* + * nvram_read(buffer,offset,length) + * + * Read data from the NVRAM device + * + * Input parameters: + * buffer - destination buffer + * offset - offset of data to read + * length - number of bytes to read + * + * Return value: + * number of bytes read, or <0 if error occured + ********************************************************************* */ +int nvram_read(unsigned char *buffer,int offset,int length) +{ + if (nvram_handle == -1) return -1; + + return cfe_readblk(nvram_handle, + (cfe_offset_t) (offset+nvram_info.nvram_offset), + buffer, + length); +} + +/* ********************************************************************* + * nvram_write(buffer,offset,length) + * + * Write data to the NVRAM device + * + * Input parameters: + * buffer - source buffer + * offset - offset of data to write + * length - number of bytes to write + * + * Return value: + * number of bytes written, or -1 if error occured + ********************************************************************* */ +int nvram_write(unsigned char *buffer,int offset,int length) +{ + if (nvram_handle == -1) return -1; + + return cfe_writeblk(nvram_handle, + (cfe_offset_t) (offset+nvram_info.nvram_offset), + buffer, + length); +} + + +/* ********************************************************************* + * nvram_erase() + * + * Erase the NVRAM device. Not all devices need to be erased, + * but flash memory does. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int nvram_erase(void) +{ + int retlen; + + if (nvram_handle < 0) { + return -1; + } + + if (nvram_info.nvram_eraseflg == FALSE) return 0; + + if (cfe_ioctl(nvram_handle,IOCTL_NVRAM_ERASE, + (unsigned char *) &nvram_info, + sizeof(nvram_info_t), + &retlen,0) != 0) { + return -1; + } + + return 0; +} + + +/* ********************************************************************* + * cfe_set_envdevice(name) + * + * Set the environment NVRAM device name + * + * Input parameters: + * name - name of device to use for NVRAM + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int cfe_set_envdevice(char *name) +{ + int res; + + nvram_devname = strdup(name); + + res = nvram_open(); + + if (res != 0) { + xprintf("!! Could not open NVRAM device %s\n",nvram_devname); + return res; + } + + nvram_close(); + + res = env_load(); + + return res; +} diff --git a/cfe/cfe/main/nvram_subr.h b/cfe/cfe/main/nvram_subr.h new file mode 100644 index 0000000..f614ec2 --- /dev/null +++ b/cfe/cfe/main/nvram_subr.h @@ -0,0 +1,54 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NVRAM prototypes File: nvram_subr.h + * + * Prototypes for NVRAM routines. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +int nvram_getsize(void); +int nvram_read(unsigned char *buffer,int,int); +int nvram_write(unsigned char *buffer,int,int); +int nvram_open(void); +int nvram_close(void); +int nvram_erase(void); + diff --git a/cfe/cfe/net/README b/cfe/cfe/net/README new file mode 100644 index 0000000..f4c1c8c --- /dev/null +++ b/cfe/cfe/net/README @@ -0,0 +1,17 @@ + +This directory contains the network modules for CFE. The +following standards are implemented here: + +* Ethernet datalink +* ARP +* IP +* UDP +* ICMP +* TFTP +* BOOTP/DHCP +* DNS (for queries only) +* TCP + +If anyone really screams for it, I've considered putting a simple +(very simple) TCP stack in here as well, but it doesn't seem worth it. + diff --git a/cfe/cfe/net/dev_tcpconsole.c b/cfe/cfe/net/dev_tcpconsole.c new file mode 100644 index 0000000..43b4f1c --- /dev/null +++ b/cfe/cfe/net/dev_tcpconsole.c @@ -0,0 +1,341 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TCP Console Driver File: dev_tcpconsole.c + * + * Evil hack: A console driver that uses a TCP socket. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "addrspace.h" + +#include "cfe_timer.h" + +#include "bsp_config.h" + +#if CFG_TCP +#include "net_ebuf.h" +#include "net_api.h" + +/* + * Friendly warning: Don't put printfs in here or enable any + * debugging messages in the TCP stack if you're really + * going to use this for your console device. You'll end up + * with a recursion loop! + */ + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define TCPCONSOLE_DEFAULT_PORT 23 /* telnet */ + +/* ********************************************************************* + * Forward + ********************************************************************* */ + +static void tcpconsole_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +static int tcpconsole_open(cfe_devctx_t *ctx); +static int tcpconsole_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tcpconsole_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int tcpconsole_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tcpconsole_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int tcpconsole_close(cfe_devctx_t *ctx); + +const static cfe_devdisp_t tcpconsole_dispatch = { + tcpconsole_open, + tcpconsole_read, + tcpconsole_inpstat, + tcpconsole_write, + tcpconsole_ioctl, + tcpconsole_close, + NULL, + NULL +}; + +const cfe_driver_t tcpconsole = { + "TCP Console", + "tcpconsole", + CFE_DEV_SERIAL, + &tcpconsole_dispatch, + tcpconsole_probe +}; + + +/* ********************************************************************* + * tcpconsole structure + ********************************************************************* */ + +/* + * States our connection can be in + */ + +#define TCPCONSTAT_IDLE 0 +#define TCPCONSTAT_LISTEN 1 +#define TCPCONSTAT_CONNECTED 2 +#define TCPCONSTAT_DISCONNECTED 3 +#define TCPCONSTAT_BROKEN 4 + +/* + * state information + */ + +typedef struct tcpconsole_s { + int tcp_socket; + int tcp_status; + int tcp_port; +} tcpconsole_t; + + +static void tcpconsole_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + tcpconsole_t *softc; + char descr[80]; + + softc = (tcpconsole_t *) KMALLOC(sizeof(tcpconsole_t),0); + if (softc) { + softc->tcp_socket = -1; + softc->tcp_status = TCPCONSTAT_IDLE; + xsprintf(descr, "%s", drv->drv_description); + + if (probe_a == 0) probe_a = TCPCONSOLE_DEFAULT_PORT; + + softc->tcp_port = (int)probe_a; + + cfe_attach(drv, softc, NULL, descr); + } +} + + +static int tcpconsole_isready(tcpconsole_t *softc,int *rxbytes) +{ + int res; + int connstat,rxeof; + + res = tcp_status(softc->tcp_socket,&connstat,rxbytes,&rxeof); + + /* + * Return: + * -1 if we could not get status + * 0 if we are not connected or are connected and at EOF + * 1 if we are connected. + */ + + if (res < 0) return res; + if (connstat != TCPSTATUS_CONNECTED) return 0; + if (!rxeof) return 1; + + return 0; +} + + +static int tcpconsole_process(tcpconsole_t *softc) +{ + int res = 0; + + switch (softc->tcp_status) { + case TCPCONSTAT_IDLE: + /* Idle, set up listening socket */ + res = tcp_socket(); + if (res < 0) { + softc->tcp_status = TCPCONSTAT_BROKEN; + return res; + } + softc->tcp_socket = res; + + res = tcp_listen(softc->tcp_socket,softc->tcp_port); + + if (res < 0) { + tcp_close(softc->tcp_socket); + softc->tcp_status = TCPCONSTAT_BROKEN; + softc->tcp_socket = -1; + return res; + } + softc->tcp_status = TCPCONSTAT_LISTEN; + break; + + case TCPCONSTAT_LISTEN: + /* Still waiting for a connection */ + res = 0; + if (tcpconsole_isready(softc,NULL) > 0) { + softc->tcp_status = TCPCONSTAT_CONNECTED; + } + break; + + case TCPCONSTAT_CONNECTED: + res = 0; /* do nothing, we're okay */ + break; + + case TCPCONSTAT_DISCONNECTED: + /* Currently connected, kill off this connection */ + tcp_close(softc->tcp_socket); + softc->tcp_socket = -1; + softc->tcp_status = TCPCONSTAT_IDLE; + break; + + case TCPCONSTAT_BROKEN: + /* Broken. Stay broken. */ + res = 0; + break; + } + + return res; +} + + +static int tcpconsole_open(cfe_devctx_t *ctx) +{ + return 0; +} + +static int tcpconsole_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tcpconsole_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + int res; + + POLL(); + tcpconsole_process(softc); + + buffer->buf_retlen = 0; + + if (softc->tcp_status == TCPCONSTAT_CONNECTED) { + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + if (tcpconsole_isready(softc,NULL) <= 0) { + softc->tcp_status = TCPCONSTAT_DISCONNECTED; + return 0; + } + + res = tcp_recv(softc->tcp_socket,bptr,blen); + + if (res > 0) { + buffer->buf_retlen = res; + } + } + + return 0; +} + +static int tcpconsole_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + tcpconsole_t *softc = ctx->dev_softc; + unsigned int rxbytes; + + POLL(); + tcpconsole_process(softc); + + inpstat->inp_status = 0; + + if (softc->tcp_status == TCPCONSTAT_CONNECTED) { + if (tcpconsole_isready(softc,&rxbytes) <= 0) { + softc->tcp_status = TCPCONSTAT_DISCONNECTED; + } + else { + inpstat->inp_status = (rxbytes > 0); + } + } + + return 0; +} + +static int tcpconsole_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + tcpconsole_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + int res; + + POLL(); + tcpconsole_process(softc); + + buffer->buf_retlen = 0; + + if (softc->tcp_status == TCPCONSTAT_CONNECTED) { + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + if (tcpconsole_isready(softc,NULL) <= 0) { + softc->tcp_status = TCPCONSTAT_DISCONNECTED; + return 0; + } + + res = tcp_send(softc->tcp_socket,bptr,blen); + + if (res > 0) { + buffer->buf_retlen = res; + } + } + + return 0; +} + +static int tcpconsole_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + return -1; +} + +static int tcpconsole_close(cfe_devctx_t *ctx) +{ + tcpconsole_t *softc = ctx->dev_softc; + + if (softc->tcp_status == TCPCONSTAT_CONNECTED) { + softc->tcp_status = TCPCONSTAT_DISCONNECTED; + } + + return 0; +} + + +#endif diff --git a/cfe/cfe/net/mii.h b/cfe/cfe/net/mii.h new file mode 100644 index 0000000..ac56958 --- /dev/null +++ b/cfe/cfe/net/mii.h @@ -0,0 +1,187 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * MII register definitions File: mii.h + * + * Register and bit definitions for the standard MII management + * interface. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _MII_H_ +#define _MII_H_ + +/* Access/command codes */ + +#define MII_COMMAND_START 0x01 +#define MII_COMMAND_READ 0x02 +#define MII_COMMAND_WRITE 0x01 +#define MII_COMMAND_ACK 0x02 + + +/* Registers */ + +#define MII_BMCR 0x00 /* Basic Mode Control (rw) */ +#define MII_BMSR 0x01 /* Basic Mode Status (ro) */ +#define MII_PHYIDR1 0x02 +#define MII_PHYIDR2 0x03 +#define MII_ANAR 0x04 /* Autonegotiation Advertisement */ +#define MII_ANLPAR 0x05 /* Autonegotiation Link Partner Ability (rw) */ +#define MII_ANER 0x06 /* Autonegotiation Expansion */ +#define MII_K1CTL 0x09 /* 1000baseT control */ +#define MII_K1STSR 0x0A /* 1K Status Register (ro) */ +#define MII_AUXCTL 0x18 /* aux control register */ + + +/* Basic Mode Control register (RW) */ + +#define BMCR_RESET 0x8000 +#define BMCR_LOOPBACK 0x4000 +#define BMCR_SPEED0 0x2000 +#define BMCR_ANENABLE 0x1000 +#define BMCR_POWERDOWN 0x0800 +#define BMCR_ISOLATE 0x0400 +#define BMCR_RESTARTAN 0x0200 +#define BMCR_DUPLEX 0x0100 +#define BMCR_COLTEST 0x0080 +#define BMCR_SPEED1 0x0040 +#define BMCR_SPEED1000 (BMCR_SPEED1) +#define BMCR_SPEED100 (BMCR_SPEED0) +#define BMCR_SPEED10 0 + + +/* Basic Mode Status register (RO) */ + +#define BMSR_100BT4 0x8000 +#define BMSR_100BT_FDX 0x4000 +#define BMSR_100BT_HDX 0x2000 +#define BMSR_10BT_FDX 0x1000 +#define BMSR_10BT_HDX 0x0800 +#define BMSR_100BT2_FDX 0x0400 +#define BMSR_100BT2_HDX 0x0200 +#define BMSR_1000BT_XSR 0x0100 +#define BMSR_PRESUP 0x0040 +#define BMSR_ANCOMPLETE 0x0020 +#define BMSR_REMFAULT 0x0010 +#define BMSR_AUTONEG 0x0008 +#define BMSR_LINKSTAT 0x0004 +#define BMSR_JABDETECT 0x0002 +#define BMSR_EXTCAPAB 0x0001 + + +/* PHY Identifer registers (RO) */ + +#define PHYIDR1 0x2000 +#define PHYIDR2 0x5C60 + + +/* Autonegotiation Advertisement register (RW) */ + +#define ANAR_NP 0x8000 +#define ANAR_RF 0x2000 +#define ANAR_ASYPAUSE 0x0800 +#define ANAR_PAUSE 0x0400 +#define ANAR_T4 0x0200 +#define ANAR_TXFD 0x0100 +#define ANAR_TXHD 0x0080 +#define ANAR_10FD 0x0040 +#define ANAR_10HD 0x0020 +#define ANAR_PSB 0x001F + +#define PSB_802_3 0x0001 /* 802.3 */ + +/* Autonegotiation Link Partner Abilities register (RW) */ + +#define ANLPAR_NP 0x8000 +#define ANLPAR_ACK 0x4000 +#define ANLPAR_RF 0x2000 +#define ANLPAR_ASYPAUSE 0x0800 +#define ANLPAR_PAUSE 0x0400 +#define ANLPAR_T4 0x0200 +#define ANLPAR_TXFD 0x0100 +#define ANLPAR_TXHD 0x0080 +#define ANLPAR_10FD 0x0040 +#define ANLPAR_10HD 0x0020 +#define ANLPAR_PSB 0x001F + + +/* Autonegotiation Expansion register (RO) */ + +#define ANER_PDF 0x0010 +#define ANER_LPNPABLE 0x0008 +#define ANER_NPABLE 0x0004 +#define ANER_PAGERX 0x0002 +#define ANER_LPANABLE 0x0001 + + +#define ANNPTR_NP 0x8000 +#define ANNPTR_MP 0x2000 +#define ANNPTR_ACK2 0x1000 +#define ANNPTR_TOGTX 0x0800 +#define ANNPTR_CODE 0x0008 + +#define ANNPRR_NP 0x8000 +#define ANNPRR_MP 0x2000 +#define ANNPRR_ACK3 0x1000 +#define ANNPRR_TOGTX 0x0800 +#define ANNPRR_CODE 0x0008 + + +#define K1TCR_TESTMODE 0x0000 +#define K1TCR_MSMCE 0x1000 +#define K1TCR_MSCV 0x0800 +#define K1TCR_RPTR 0x0400 +#define K1TCR_1000BT_FDX 0x200 +#define K1TCR_1000BT_HDX 0x100 + +#define K1STSR_MSMCFLT 0x8000 +#define K1STSR_MSCFGRES 0x4000 +#define K1STSR_LRSTAT 0x2000 +#define K1STSR_RRSTAT 0x1000 +#define K1STSR_LP1KFD 0x0800 +#define K1STSR_LP1KHD 0x0400 +#define K1STSR_LPASMDIR 0x0200 + +#define K1SCR_1KX_FDX 0x8000 +#define K1SCR_1KX_HDX 0x4000 +#define K1SCR_1KT_FDX 0x2000 +#define K1SCR_1KT_HDX 0x1000 + +#endif /* _MII_H_ */ diff --git a/cfe/cfe/net/net_api.c b/cfe/cfe/net/net_api.c new file mode 100755 index 0000000..c9f119e --- /dev/null +++ b/cfe/cfe/net/net_api.c @@ -0,0 +1,1095 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Top-level API to network File: net_api.c + * + * This routine contains the highest-level API to the network + * routines. The global handle to the network state is right here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "bsp_config.h" + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "cfe_timer.h" + +#include "net_ip.h" +#include "net_ip_internal.h" +#include "net_api.h" + +#include "env_subr.h" + +#if CFG_TCP +#include "net_tcp.h" +#endif + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +/* + * Net context. All the soft context structures of all the + * layers of the network stack are bundled here. There's only one + * of these in the system when the network is active. + */ + +typedef struct net_ctx_s { + /* Global info */ + int64_t timer; + + /* device name */ + char *devname; + + /* Run-time info for IP interface */ + ip_info_t *ipinfo; + + /* Info for Ethernet interface */ + ether_info_t *ethinfo; + + /* Info specific to UDP */ + udp_info_t *udpinfo; + + /* Info specific to ICMP */ + icmp_info_t *icmpinfo; + +#if CFG_TCP + /* Info specific to TCP */ + tcp_info_t *tcpinfo; +#endif +} net_ctx_t; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +net_ctx_t *netctx = NULL; +// static net_ctx_t *netctx = NULL; +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +/* ********************************************************************* + * UDP INTERFACE + ********************************************************************* */ + +/* ********************************************************************* + * udp_alloc() + * + * Allocate an ebuf with fields reserved for the UDP layer. + * + * Input parameters: + * nothing + * + * Return value: + * pointer to ebuf, or NULL if no EBUFs are available + ********************************************************************* */ + +ebuf_t *udp_alloc(void) +{ + if (!netctx) return NULL; + return _udp_alloc(netctx->udpinfo); +} + +/* ********************************************************************* + * udp_free(buf) + * + * Return an ebuf to the pool. The ebuf was presumably allocated + * via udp_alloc() first. + * + * Input parameters: + * buf - ebuf to return to the pool + * + * Return value: + * nothing + ********************************************************************* */ +void udp_free(ebuf_t *buf) +{ + if (!netctx) return; + _udp_free(netctx->udpinfo,buf); +} + +/* ********************************************************************* + * udp_socket(port) + * + * Open a UDP socket. Once open, datagrams sent on the socket will + * go to the specified port number. You can change the port later + * using the "udp_connect" function. + * + * Input parameters: + * port - port number + * + * Return value: + * UDP port handle, or -1 if no ports are available. + ********************************************************************* */ + +int udp_socket(uint16_t port) +{ + if (!netctx) return -1; + + return _udp_socket(netctx->udpinfo,port); +} + +/* ********************************************************************* + * udp_close(sock) + * + * Close a udp socket. You pass this handle returned from a previous + * call to udp_open. + * + * Input parameters: + * handle - UDP port handle, from udp_open() + * + * Return value: + * nothing + ********************************************************************* */ + +void udp_close(int portnum) +{ + if (!netctx) return; + + _udp_close(netctx->udpinfo,portnum); +} + + +/* ********************************************************************* + * udp_send(s,buf,dest) + * + * Send a datagram to the specified destination address. The + * source and destination UDP port numbers are taken from the + * values passed to earlier calls to udp_open, udp_bind, and + * udp_connect. + * + * Input parameters: + * s - socket handle, from udp_open + * buf - ebuf to send (allocated via udp_alloc) + * dest - pointer to 4-byte destination IP address + * + * Return value: + * 0 if ok + * <0 if an error occured. + ********************************************************************* */ + +int udp_send(int s,ebuf_t *buf,uint8_t *dest) +{ + if (!netctx) return -1; + + return _udp_send(netctx->udpinfo,s,buf,dest); +} + +/* ********************************************************************* + * udp_bind(s,port) + * + * Re-"bind" the specified udp socket to a new source port. + * This changes the source port number that will be transmitted + * in subsequent calls to udp_send() + * + * Input parameters: + * s - socket handle + * port - new port number + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int udp_bind(int s,uint16_t port) +{ + if (!netctx) return -1; + + return _udp_bind(netctx->udpinfo,s,port); +} + + +/* ********************************************************************* + * udp_connect(s,port) + * + * Set the port number to be used in the destination port field + * for subsequent calls to udp_send(). + * + * Input parameters: + * s - udp socket handle + * port - new destination port number + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int udp_connect(int s,uint16_t port) +{ + if (!netctx) return -1; + + return _udp_connect(netctx->udpinfo,s,port); +} + +/* ********************************************************************* + * udp_recv(s) + * + * Return the next packet from the receive queue for this port. + * If no packets are available, NULL is returned. + * + * Input parameters: + * s - udp port handle + * + * Return value: + * ebuf (if a packet is available) + * NULL (no packet available) + ********************************************************************* */ + +ebuf_t *udp_recv(int s) +{ + if (!netctx) return NULL; + + return _udp_recv(netctx->udpinfo,s); +} + + +/* ********************************************************************* + * udp_recv_with_timeout(s,seconds) + * + * Return the next packet from the receive queue for this socket, + * waiting for one to arrive if there are none available. + * + * Input parameters: + * s - udp socket handle + * seconds - number of seconds to wait + * + * Return value: + * ebuf (if a packet is available) + * NULL (no packet available after timeout) + ********************************************************************* */ + +ebuf_t *udp_recv_with_timeout(int s,int seconds) +{ + ebuf_t *buf = NULL; + int64_t timer; + + if (!netctx) return NULL; + + TIMER_SET(timer,seconds*CFE_HZ); + + while (!TIMER_EXPIRED(timer)) { + POLL(); + buf = _udp_recv(netctx->udpinfo,s); + if (buf) break; + } + + return buf; +} + + + +#if CFG_TCP +/* ********************************************************************* + * TCP INTERFACE + ********************************************************************* */ + + +/* ********************************************************************* + * tcp_socket() + * + * Create a new TCP port. + * + * Input parameters: + * nothing. + * + * Return value: + * TCP port handle, or <0 if no ports are available. + ********************************************************************* */ + +int tcp_socket(void) +{ + if (!netctx) return -1; + + return _tcp_socket(netctx->tcpinfo); +} + +/* ********************************************************************* + * tcp_connect(handle,dest,port) + * + * Connect to a remote TCP destination. + * + * Input parameters: + * handle - returned from tcp_create + * dest - destination IP address + * port - destination port number + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int tcp_connect(int s,uint8_t *dest,uint16_t port) +{ + int res; + unsigned int flags; + unsigned int connflag; + + if (!netctx) return -1; + + /* + * Get socket's blocking status + * If nonblocking, just call the tcp stack + * and return what it returns. + */ + + res = _tcp_getflags(netctx->tcpinfo,s,&flags); + if (res < 0) return res; + + if (flags & TCPFLG_NBIO) { + return _tcp_connect(netctx->tcpinfo,s,dest,port); + } + + /* + * Otherwise, call connect and poll till the status + * changes. We want to see a transition to the + * CONNECTED state, so we loop while we see "CONNECTING" + * and return a status based on what it changes to. + */ + + res = _tcp_connect(netctx->tcpinfo,s,dest,port); + if (res < 0) return res; + connflag = TCPSTATUS_NOTCONN; + + for (;;) { + POLL(); + + res = _tcp_status(netctx->tcpinfo,s,&connflag,NULL,NULL); + if (res < 0) break; + + if (connflag == TCPSTATUS_CONNECTING) continue; + break; + } + + if (connflag != TCPSTATUS_CONNECTED) return CFE_ERR_NOTCONN; + + return res; +} + +/* ********************************************************************* + * tcp_close(s) + * + * Disconnect a connection (cleanly) + * + * Input parameters: + * s - handle from tcp_create + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +int tcp_close(int s) +{ + if (!netctx) return -1; + + return _tcp_close(netctx->tcpinfo,s); +} + + + +/* ********************************************************************* + * tcp_send(s,buf,len) + * + * Send a buffer to the other TCP, buffering as much data as + * will fit in the send buffer. + * + * Input parameters: + * s - port handle, from tcp_open + * buf - buffer pointer + * len - length of buffer to send + * + * Return value: + * >=0 if ok (number of bytes sent) + * <0 if an error occured. + ********************************************************************* */ + +int tcp_send(int s,uint8_t *buf,int len) +{ + unsigned int flags; + int res; + int total = 0; + + if (!netctx) return -1; + + /* + * Get socket's blocking status + * If nonblocking, just call the tcp stack + * and return what it returns. + */ + + res = _tcp_getflags(netctx->tcpinfo,s,&flags); + if (res < 0) return res; + + if (flags & TCPFLG_NBIO) { + return _tcp_send(netctx->tcpinfo,s,buf,len); + } + + /* + * The first time we'll check the return code for an + * error so we can pass up the failure. + */ + + res = _tcp_send(netctx->tcpinfo,s,buf,len); + if (res < 0) return res; + + buf += res; + len -= res; + total += res; + + while (len > 0) { + /* + * Give the TCP stack and devices a chance to run + */ + + POLL(); + + /* + * Try to send some more. If we get an error, get out. + * otherwise, keep going till all the data is gone. + */ + + res = _tcp_send(netctx->tcpinfo,s,buf,len); + if (res < 0) break; + buf += res; + len -= res; + total += res; + } + + /* + * If we sent nothing and have an error, return the error. + * Otherwise return the amount of data we sent. + */ + if ((total == 0) && (res < 0)) return res; + else return total; +} + +/* ********************************************************************* + * tcp_recv(s,buf,len) + * + * Receive data from the remote TCP session + * + * Input parameters: + * s - port handle, from tcp_open + * buf - buffer pointer + * len - length of buffer to send + * + * Return value: + * >=0 if ok (number of bytes received) + * <0 if an error occured. + ********************************************************************* */ + +int tcp_recv(int s,uint8_t *buf,int len) +{ + unsigned int flags; + int res; + int total = 0; + + if (!netctx) return -1; + + /* + * Get socket's blocking status + * If nonblocking, just call the tcp stack + * and return what it returns. + */ + + res = _tcp_getflags(netctx->tcpinfo,s,&flags); + if (res < 0) return res; + + if (flags & TCPFLG_NBIO) { + return _tcp_recv(netctx->tcpinfo,s,buf,len); + } + + /* + * The first time we'll check the return code for an + * error so we can pass up the failure. + */ + + res = _tcp_recv(netctx->tcpinfo,s,buf,len); + if (res < 0) return res; + + buf += res; + len -= res; + total += res; + + while (len > 0) { + /* + * Give the TCP stack and devices a chance to run + */ + + POLL(); + + /* + * Try to receive some more. If we get an error, get out. + * otherwise, keep going till all the data is gone. + */ + + res = _tcp_recv(netctx->tcpinfo,s,buf,len); + if (res < 0) break; + + if (res == 0) { + _tcp_status(netctx->tcpinfo,s,&flags,NULL,NULL); + if (flags != TCPSTATUS_CONNECTED) { + res = CFE_ERR_NOTCONN; + break; + } + } + + buf += res; + len -= res; + total += res; + } + + /* + * If we sent received and have an error, return the error. + * Otherwise return the amount of data we sent. + */ + if ((total == 0) && (res < 0)) return res; + else return total; + +} + +/* ********************************************************************* + * tcp_bind(s,port) + * + * Re-"bind" the specified tcp port handle to a new source port. + * + * Used for listening sockets. + * + * Input parameters: + * s - port handle + * port - new port number + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int tcp_bind(int s,uint16_t port) +{ + if (!netctx) return -1; + + return _tcp_bind(netctx->tcpinfo,s,port); +} + +/* ********************************************************************* + * tcp_peeraddr(s,addr,port) + * + * Return the address of the remote peer. + * + * Input parameters: + * s - port handle + * addr - points to 4-byte buffer to receive IP address + * port - points to uint16 to receive port number + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int tcp_peeraddr(int s,uint8_t *addr,uint16_t *port) +{ + if (!netctx) return -1; + + return _tcp_peeraddr(netctx->tcpinfo,s,addr,port); +} + +/* ********************************************************************* + * tcp_setflags(s,addr,flags) + * + * Set per-socket flags (nodelay, etc.) + * + * Input parameters: + * s - port handle + * flags - flags for this socket + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int tcp_setflags(int s,unsigned int flags) +{ + if (!netctx) return -1; + + return _tcp_setflags(netctx->tcpinfo,s,flags); +} + +/* ********************************************************************* + * tcp_getflags(s,addr,flags) + * + * Get per-socket flags (nodelay, etc.) + * + * Input parameters: + * s - port handle + * flags - flags for this socket + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int tcp_getflags(int s,unsigned int *flags) +{ + if (!netctx) return -1; + + return _tcp_getflags(netctx->tcpinfo,s,flags); +} + + +/* ********************************************************************* + * tcp_listen(s) + * + * Set the socket into "listen" mode. + * + * Input parameters: + * s - port handle + * port - port # to listen on + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +int tcp_listen(int s,uint16_t port) +{ + if (!netctx) return -1; + + return _tcp_listen(netctx->tcpinfo,s,port); +} + +/* ********************************************************************* + * tcp_status(s,connflag,rxready,rxeof) + * + * Return the TCP connection's status + * + * Input parameters: + * s - port handle + * connflag - points to flag to receive connected status + * rxready - returns # of bytes ready to receive + * rxeof - returns TRUE if we've been FINed. + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +int tcp_status(int s,unsigned int *connflag,int *rxready,int *rxeof) +{ + if (!netctx) return -1; + + return _tcp_status(netctx->tcpinfo,s,connflag,rxready,rxeof); +} + +/* ********************************************************************* + * tcp_debug(s,arg) + * + * Call the debug routine in the tcp stack. + * + * Input parameters: + * s - socket handle + * arg - passed to debug routine + * + * Return value: + * return value from debug routine + ********************************************************************* */ + +int tcp_debug(int s,int arg) +{ + if (!netctx) return -1; + return _tcp_debug(netctx->tcpinfo,s,arg); +} + +#endif + +/* ********************************************************************* + * ARP FUNCTIONS + ********************************************************************* */ + + +/* ********************************************************************* + * arp_add(destip,desthw) + * + * Add a permanent entry to the ARP table. This entry will + * persist until deleted or the interface is deactivated. + * This may cause a stale entry to be deleted if the table is full + * + * Input parameters: + * destip - pointer to 4-byte destination IP address + * desthw - pointer to 6-byte destination hardware address + * + * Return value: + * nothing + ********************************************************************* */ + +void arp_add(uint8_t *destip,uint8_t *desthw) +{ + if (netctx) _arp_add(netctx->ipinfo,destip,desthw); +} + +/* ********************************************************************* + * arp_lookup(destip) + * + * Look up the hardware address for an IP address. + * + * Input parameters: + * destip - pointer to 4-byte IP address + * + * Return value: + * pointer to 6-byte hardware address, or NULL if there are + * no matching entries in the table. + ********************************************************************* */ + +uint8_t *arp_lookup(uint8_t *destip) +{ + if (!netctx) return NULL; + return _arp_lookup(netctx->ipinfo,destip); +} + + +/* ********************************************************************* + * arp_enumerate(entrynum,ipaddr,hwaddr) + * + * Return an entry from the ARP table. + * + * Input parameters: + * entrynum - entry number to return, starting with zero + * ipaddr - pointer to 4 bytes to receive IP address + * hwaddr - pointer to 6 bytes to receive hardware address + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int arp_enumerate(int entrynum,uint8_t *ipaddr,uint8_t *hwaddr) +{ + if (!netctx) return -1; + return _arp_enumerate(netctx->ipinfo,entrynum,ipaddr,hwaddr); +} + +/* ********************************************************************* + * arp_delete(ipaddr) + * + * Delete an entry from the ARP table. + * + * Input parameters: + * ipaddr - pointer to 4-byte IP address + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int arp_delete(uint8_t *ipaddr) +{ + if (!netctx) return -1; + return _arp_delete(netctx->ipinfo,ipaddr); +} + +/* ********************************************************************* + * ICMP FUNCTIONS + ********************************************************************* */ + +/* ********************************************************************* + * icmp_ping(dest,seq,len) + * + * Ping a remote host, transmitting the ICMP_ECHO message and + * waiting for the corresponding ICMP_ECHO_REPLY. + * + * Input parameters: + * dest - pointer to 4-byte destination IP address + * seq - sequence number to put in to the ICMP packet + * len - length of data to place in ICMP packet + * + * Return value: + * 0 if ok (remote host responded) + * else error code + ********************************************************************* */ + +int icmp_ping(uint8_t *dest,int seq,int len) +{ + if (!netctx) return -1; + return _icmp_ping(netctx->icmpinfo,dest,seq,len); +} + +/* ********************************************************************* + * INIT/CONFIG FUNCTIONS + ********************************************************************* */ + +/* ********************************************************************* + * net_getparam(param) + * + * Return a parameter from the current IP configuration. This is + * the main call to set the IP address, netmask, gateway, + * name server, host name, etc. + * + * Input parameters: + * param - parameter number (see net_api.h) + * + * Return value: + * pointer to value of parameter, or NULL if parameter + * ID is invalid + ********************************************************************* */ + +uint8_t *net_getparam(int param) +{ + if (!netctx) return NULL; + if (param == NET_DEVNAME) return (uint8_t *) netctx->devname; + return _ip_getparam(netctx->ipinfo,param); + +} + +/* ********************************************************************* + * net_setparam(param,ptr) + * + * Set the value of an IP configuration parameter + * + * Input parameters: + * param - parameter number (see net_api.h) + * ptr - pointer to parameter's new value + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int net_setparam(int param,uint8_t *ptr) +{ + if (!netctx) return NULL; + return _ip_setparam(netctx->ipinfo,param,ptr); +} + +/* ********************************************************************* + * net_poll() + * + * Process background tasks for the network stack, maintaining + * the ARP table, receive queues, etc. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void net_poll(void *arg) +{ + if (netctx) { + eth_poll(netctx->ethinfo); + if (TIMER_EXPIRED(netctx->timer)) { + _ip_timer_tick(netctx->ipinfo); + TIMER_SET(netctx->timer,CFE_HZ); + } + } +} + +/* ********************************************************************* + * net_init(devname) + * + * Initialize the network interface. This is the main call, once + * completed you should call net_setparam to set up the network + * addresses and stuff. + * + * Input parameters: + * devname - CFE device name for network device + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int net_init(char *devname) +{ + net_ctx_t *ctx; + + if (netctx) net_uninit(); + + ctx = KMALLOC(sizeof(net_ctx_t),0); + + if (!ctx) return -1; + + ctx->devname = strdup(devname); + + ctx->ethinfo = eth_init(devname); + if (ctx->ethinfo == NULL) { + return -1; + } + + ctx->ipinfo = _ip_init(ctx->ethinfo); + if (ctx->ipinfo == NULL) { + eth_uninit(ctx->ethinfo); + return -1; + } + + ctx->udpinfo = _udp_init(ctx->ipinfo,ctx->ipinfo); + if (ctx->udpinfo == NULL) { + _ip_uninit(ctx->ipinfo); + eth_uninit(ctx->ethinfo); + return -1; + } + + ctx->icmpinfo = _icmp_init(ctx->ipinfo); + if (ctx->icmpinfo == NULL) { + _udp_uninit(ctx->udpinfo); + _ip_uninit(ctx->ipinfo); + eth_uninit(ctx->ethinfo); + return -1; + } + + cfe_bg_add(net_poll,ctx); + TIMER_SET(ctx->timer,CFE_HZ); + +#if CFG_TCP + ctx->tcpinfo = _tcp_init(ctx->ipinfo,ctx->ipinfo); + cfe_bg_add(_tcp_poll,ctx->tcpinfo); +#endif + + netctx = ctx; + + return 0; +} + + +/* ********************************************************************* + * net_uninit() + * + * Uninitialize the network, deallocating all resources allocated + * to the network and closing all open device handles + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void net_uninit(void) +{ + if (netctx) { +#if CFG_TCP + cfe_bg_remove(_tcp_poll); + _tcp_uninit(netctx->tcpinfo); +#endif + TIMER_CLEAR(netctx->timer); + _icmp_uninit(netctx->icmpinfo); + _udp_uninit(netctx->udpinfo); + _ip_uninit(netctx->ipinfo); + eth_uninit(netctx->ethinfo); + KFREE(netctx->devname); + KFREE(netctx); + netctx = NULL; + cfe_bg_remove(net_poll); + } +} + + +/* ********************************************************************* + * net_setnetvars() + * + * Set environment variables related to the network. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void net_setnetvars(void) +{ + char *x; + uint8_t *addr; + char str[60]; + + /* Clear out all the environment variables */ + env_delenv("NET_DEVICE"); + env_delenv("NET_IPADDR"); + env_delenv("NET_NETMASK"); + env_delenv("NET_GATEWAY"); + env_delenv("NET_NAMESERVER"); + env_delenv("NET_DOMAIN"); + + x = (char *) net_getparam(NET_DEVNAME); + if (!x) { + return; + } + + x = (char *) net_getparam(NET_DEVNAME); + if (x) env_setenv("NET_DEVICE",x,ENV_FLG_BUILTIN); + + x = (char *) net_getparam(NET_DOMAIN); + if (x) env_setenv("NET_DOMAIN",x,ENV_FLG_BUILTIN); + + addr = net_getparam(NET_IPADDR); + if (addr) { + xsprintf(str,"%I",addr); + env_setenv("NET_IPADDR",str,ENV_FLG_BUILTIN); + } + + addr = net_getparam(NET_NETMASK); + if (addr) { + xsprintf(str,"%I",addr); + env_setenv("NET_NETMASK",str,ENV_FLG_BUILTIN); + } + + addr = net_getparam(NET_GATEWAY); + if (addr) { + xsprintf(str,"%I",addr); + env_setenv("NET_GATEWAY",str,ENV_FLG_BUILTIN); + } + + addr = net_getparam(NET_NAMESERVER); + if (addr) { + xsprintf(str,"%I",addr); + env_setenv("NET_NAMESERVER",str,ENV_FLG_BUILTIN); + } + +} + diff --git a/cfe/cfe/net/net_api.h b/cfe/cfe/net/net_api.h new file mode 100755 index 0000000..f28b917 --- /dev/null +++ b/cfe/cfe/net/net_api.h @@ -0,0 +1,179 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * High-level network API defs File: net_api.h + * + * This module contains prototypes and constants for the + * network (TCP/IP) interface. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#ifndef IP_ADDR_LEN +#define IP_ADDR_LEN 4 +#endif + +/* ********************************************************************* + * DHCP Protocol + ********************************************************************* */ + +typedef struct dhcpreply_s { + uint8_t dr_ipaddr[IP_ADDR_LEN]; + uint8_t dr_netmask[IP_ADDR_LEN]; + uint8_t dr_gateway[IP_ADDR_LEN]; + uint8_t dr_nameserver[IP_ADDR_LEN]; + uint8_t dr_dhcpserver[IP_ADDR_LEN]; + uint8_t dr_bootserver[IP_ADDR_LEN]; + char *dr_hostname; + char *dr_domainname; + char *dr_bootfile; + char *dr_rootpath; + char *dr_swapserver; + char *dr_script; + char *dr_options; +} dhcpreply_t; + + +int dhcp_bootrequest(dhcpreply_t **reply); +void dhcp_free_reply(dhcpreply_t *reply); +void dhcp_set_envvars(dhcpreply_t *reply); + +/* ********************************************************************* + * IP Layer + ********************************************************************* */ + +void ip_uninit(void); +int ip_init(char *,uint8_t *); +ebuf_t *ip_alloc(void); +void ip_free(ebuf_t *buf); +int ip_send(ebuf_t *buf,uint8_t *destaddr,uint8_t proto); +uint16_t ip_chksum(uint16_t initchksum,uint8_t *ptr,int len); + +/* ********************************************************************* + * UDP Layer + ********************************************************************* */ + +ebuf_t *udp_alloc(void); +void udp_free(ebuf_t *buf); + +int udp_socket(uint16_t port); +int udp_bind(int portnum,uint16_t port); +int udp_connect(int portnum,uint16_t port); +void udp_close(int portnum); +int udp_send(int portnum,ebuf_t *buf,uint8_t *dest); +ebuf_t *udp_recv_with_timeout(int portnum,int seconds); +ebuf_t *udp_recv(int portnum); + +/* ********************************************************************* + * TCP Layer + ********************************************************************* */ + +#if CFG_TCP +#ifndef TCPFLG_NODELAY /* XXX should be kept in sync with net_tcp.h */ +#define TCPFLG_NODELAY 1 /* disable nagle */ +#define TCPFLG_NBIO 2 /* non-blocking I/O */ + +#define TCPSTATUS_NOTCONN 0 +#define TCPSTATUS_CONNECTING 1 +#define TCPSTATUS_CONNECTED 2 +#endif +int tcp_socket(void); +void tcp_destroy(int portnum); +int tcp_connect(int s,uint8_t *dest,uint16_t port); +int tcp_close(int s); +int tcp_send(int s,uint8_t *buf,int len); +int tcp_recv(int s,uint8_t *buf,int len); +int tcp_bind(int s,uint16_t port); +int tcp_peeraddr(int s,uint8_t *addr,uint16_t *port); +int tcp_listen(int s,uint16_t port); +int tcp_status(int s,unsigned int *connflag,int *rxready,int *rxeof); +int tcp_debug(int s,int arg); +int tcp_setflags(int s,unsigned int flags); +int tcp_getflags(int s,unsigned int *flags); +#endif + +/* ********************************************************************* + * ARP Layer + ********************************************************************* */ + +uint8_t *arp_lookup(uint8_t *destip); +void arp_add(uint8_t *destip,uint8_t *desthw); +int arp_enumerate(int entrynum,uint8_t *ipaddr,uint8_t *hwaddr); +int arp_delete(uint8_t *ipaddr); + +/* ********************************************************************* + * Network Configuration + ********************************************************************* */ + +#ifndef NET_IPADDR +#define NET_IPADDR 0 +#define NET_NETMASK 1 +#define NET_GATEWAY 2 +#define NET_NAMESERVER 3 +#define NET_HWADDR 4 +#define NET_DOMAIN 5 +#define NET_HOSTNAME 6 +#define NET_SPEED 7 +#define NET_LOOPBACK 8 +#endif +#define NET_DEVNAME 10 + +uint8_t *net_getparam(int param); +int net_setparam(int param,uint8_t *ptr); +int net_init(char *devname); +void net_uninit(void); +void net_setnetvars(void); + +/* ********************************************************************* + * DNS + ********************************************************************* */ + +int dns_lookup(char *hostname,uint8_t *ipaddr); + +/* ********************************************************************* + * ICMP + ********************************************************************* */ + +int icmp_ping(uint8_t *dest,int seq,int len); + diff --git a/cfe/cfe/net/net_arp.c b/cfe/cfe/net/net_arp.c new file mode 100755 index 0000000..1c12457 --- /dev/null +++ b/cfe/cfe/net/net_arp.c @@ -0,0 +1,865 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Address Resolution Protocol File: net_arp.c + * + * This module implements RFC826, the Address Resolution Protocol. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_ip.h" +#include "net_ip_internal.h" + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int arp_tx_query(ip_info_t *ipi,uint8_t *destaddr); +static void arp_delete(arpentry_t *ae); +static void arp_tx_waiting(arpentry_t *ae); +static arpentry_t *arp_new_entry(ip_info_t *ipi); +static arpentry_t *arp_find_entry(ip_info_t *ipi,uint8_t *ipaddr); +static int arp_rx_query(ip_info_t *ipi,uint8_t *srcaddr, + uint8_t *targethw,uint8_t *targetip); +static int arp_rx_response(ip_info_t *ipi,uint8_t *senderhw, + uint8_t *senderip); +static int arp_rx_callback(ebuf_t *buf,void *ref); + + +/* ********************************************************************* + * arp_tx_query(ipi,destaddr) + * + * Transmit an ARP QUERY message. ARP QUERY messages are sent + * to the Ethernet broadcast address. + * + * Input parameters: + * ipi - IP information + * destaddr - IP address to query + * + * Return value: + * 0 - success + * <0 - failure + ********************************************************************* */ + +static int arp_tx_query(ip_info_t *ipi,uint8_t *destaddr) +{ + ebuf_t *buf; + uint8_t hwaddr[ENET_ADDR_LEN]; + + /* + * Get a buffer. + */ + + buf = eth_alloc(ipi->eth_info,ipi->arp_port); + if (!buf) return -1; + + /* + * fill in the fields + */ + + ebuf_append_u16_be(buf,ARP_HWADDRSPACE_ETHERNET); + ebuf_append_u16_be(buf,PROTOSPACE_IP); + ebuf_append_u8(buf,ENET_ADDR_LEN); + ebuf_append_u8(buf,IP_ADDR_LEN); + ebuf_append_u16_be(buf,ARP_OPCODE_REQUEST); + ebuf_append_bytes(buf,ipi->arp_hwaddr,ENET_ADDR_LEN); + ebuf_append_bytes(buf,ipi->net_info.ip_addr,IP_ADDR_LEN); + memset(hwaddr,0,ENET_ADDR_LEN); + ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); + ebuf_append_bytes(buf,destaddr,IP_ADDR_LEN); + + /* + * Transmit the packet + */ + + eth_send(buf,(uint8_t *)eth_broadcast); + eth_free(buf); + + return 0; +} + + +/* ********************************************************************* + * arp_delete(ae) + * + * Delete an ARP entry. The usual reason for calling this routine + * is to reclaim unused ARP entries, but an ARP entry may be + * manually deleted as well. + * + * Input parameters: + * ae - arp entry + * + * Return value: + * nothing + ********************************************************************* */ + +static void arp_delete(arpentry_t *ae) +{ + ebuf_t *buf; + + /* + * Free any buffers associated with the ARP entry. + */ + + while ((buf = (ebuf_t *) q_deqnext(&(ae->ae_txqueue)))) { + eth_free(buf); + } + + /* + * Reset the important fields + */ + + ae->ae_timer = 0; + ae->ae_usage = 0; + ae->ae_retries = 0; + ae->ae_state = ae_unused; +} + + +/* ********************************************************************* + * _arp_add(ipi,destip,desthw) + * + * Add a new ARP entry to the ARP table [internal routine]. If + * there is no room in the table, some other entry is kicked + * out. + * + * Input parameters: + * ipi - IP information + * destip - target IP address + * desthw - target hardware address + * + * Return value: + * nothing + ********************************************************************* */ + +void _arp_add(ip_info_t *ipi,uint8_t *destip,uint8_t *desthw) +{ + arpentry_t *ae; + + ae = arp_find_entry(ipi,desthw); + if (!ae) { + ae = arp_new_entry(ipi); + } + + memcpy(ae->ae_ipaddr,destip,IP_ADDR_LEN); + memcpy(ae->ae_ethaddr,desthw,ENET_ADDR_LEN); + + ae->ae_retries = 0; + ae->ae_timer = 0; /* keep forever */ + ae->ae_permanent = TRUE; + ae->ae_state = ae_established; + + arp_tx_waiting(ae); +} + + +/* ********************************************************************* + * _arp_lookup(ipi,destip) + * + * Look up an ARP entry [internal routine]. Given an IP address, + * return the hardware address to send the packets to, or + * NULL if no ARP entry exists. + * + * Input parameters: + * ipi - IP information + * destip - destination IP address + * + * Return value: + * pointer to Ethernet hardware address, or NULL if not found + ********************************************************************* */ + +uint8_t *_arp_lookup(ip_info_t *ipi,uint8_t *destip) +{ + arpentry_t *ae; + + ae = arp_find_entry(ipi,destip); + if (ae == NULL) return NULL; + + return ae->ae_ethaddr; +} + +/* ********************************************************************* + * _arp_lookup_and_send(ipi,buf,dest) + * + * Transmit a packet [internal routine]. This routine is called + * by the IP layer when it wants to send a packet. We look + * through the ARP table to find a suitable destination host and + * transmit the packet. If there is no ARP entry, an ARP request + * is transmitted and the packet is saved on a queue for when + * the address is resolved. + * + * Input parameters: + * ipi - IP information + * buf - ebuf to transmit + * dest - destination IP address + * + * Return value: + * 0 if ok + * <0 if error + ********************************************************************* */ + +int _arp_lookup_and_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *dest) +{ + arpentry_t *ae; + + ae = arp_find_entry(ipi,dest); + + if (ae == NULL) { + /* + * No ARP entry yet, create one and send the query + */ + ae = arp_new_entry(ipi); + memcpy(ae->ae_ipaddr,dest,IP_ADDR_LEN); + q_enqueue(&(ae->ae_txqueue),(queue_t *) buf); + ae->ae_retries = ARP_QUERY_RETRIES; + ae->ae_timer = ARP_QUERY_TIMER; + ae->ae_state = ae_arping; + arp_tx_query(ipi,ae->ae_ipaddr); + } + else { + /* + * have an ARP entry. If established, just send the + * packet now. Otherwise, queue on arp queue if there's room. + */ + if (ae->ae_state == ae_established) { + ae->ae_usage++; + if (!ae->ae_permanent) { + ae->ae_timer = ARP_KEEP_TIMER; + } + eth_send(buf,ae->ae_ethaddr); + eth_free(buf); + } + else { + if (q_count(&(ae->ae_txqueue)) < ARP_TXWAIT_MAX) { + q_enqueue(&(ae->ae_txqueue),(queue_t *) buf); + } + else { + /* no room, silently drop */ + eth_free(buf); + } + } + } + + return 0; +} + +/* ********************************************************************* + * arp_tx_waiting(ae) + * + * Transmit all pending packets on the specified ARP entry's + * queue. Packets get queued to an ARP entry when the address + * has not completed resolution. Once resolved, this routine + * is called to flush the packets out. + * + * Input parameters: + * ae - arp entry + * + * Return value: + * nothing + ********************************************************************* */ + +static void arp_tx_waiting(arpentry_t *ae) +{ + ebuf_t *buf; + + while ((buf = (ebuf_t *) q_deqnext(&(ae->ae_txqueue)))) { + eth_send(buf,ae->ae_ethaddr); + eth_free(buf); + } +} + + +/* ********************************************************************* + * arp_new_entry(ipi) + * + * Create a new ARP entry, deleting an active entry if necessary. + * + * Input parameters: + * ipi - IP information + * + * Return value: + * arp entry pointer + ********************************************************************* */ + +static arpentry_t *arp_new_entry(ip_info_t *ipi) +{ + arpentry_t *ae; + arpentry_t *victim = NULL; + int idx; + int minusage = 0x7FFFFFFF; + + /* + * First scan the table and find an empty entry. + */ + + ae = ipi->arp_table; + for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) { + if (ae->ae_state == ae_unused) { + return ae; + } + } + + /* + * If all entries are in use, pick the one with the + * lowest usage count. This isn't very scientific, + * and perhaps should use a timer of some sort. + */ + + ae = ipi->arp_table; + for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) { + if (ae->ae_usage < minusage) { + victim = ae; + minusage = ae->ae_usage; + } + } + + /* + * In the highly unlikely event that all entries have + * overflow values in their usage counters, just take the + * first table entry. + */ + + if (victim == NULL) victim = ipi->arp_table; + + /* + * Clear out the old entry and use it. + */ + + arp_delete(victim); + + return victim; +} + +/* ********************************************************************* + * arp_find_entry(ipi,ipaddr) + * + * Find an ARP entry in the table. Given an IP address, this + * routine locates the corresponding ARP table entry. We also + * reset the expiration timer for the ARP entry, to prevent + * it from from being deleted. + * + * Input parameters: + * ipi - IP info + * ipaddr - IP address we're looking for + * + * Return value: + * arp entry pointer, or NULL if not found + ********************************************************************* */ + +static arpentry_t *arp_find_entry(ip_info_t *ipi,uint8_t *ipaddr) +{ + arpentry_t *ae; + int idx; + + ae = ipi->arp_table; + + for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) { + if (ae->ae_state != ae_unused) { + if (memcmp(ae->ae_ipaddr,ipaddr,IP_ADDR_LEN) == 0) { + if (ae->ae_state == ae_established) + ae->ae_timer = ARP_KEEP_TIMER; + return ae; + } + } + } + return NULL; +} + + +/* ********************************************************************* + * arp_rx_query(ipi,srcaddr,targethw,targetip) + * + * Process a received ARP QUERY message. When we get an ARP, + * transmit a reply to the sender. + * + * Input parameters: + * ipi - IP information + * srcaddr - source IP address + * targethw - target hardware address + * targetip - target IP address (should be our address) + * + * Input parameters: + * 0 if ok + * else <0 = error + ********************************************************************* */ + +static int arp_rx_query(ip_info_t *ipi,uint8_t *srcaddr, + uint8_t *targethw,uint8_t *targetip) +{ + ebuf_t *txbuf; + + /* + * Allocate a packet and form the reply + */ + + txbuf = eth_alloc(ipi->eth_info,ipi->arp_port); + if (!txbuf) return -1; + + ebuf_append_u16_be(txbuf,ARP_HWADDRSPACE_ETHERNET); + ebuf_append_u16_be(txbuf,PROTOSPACE_IP); + ebuf_append_u8(txbuf,ENET_ADDR_LEN); + ebuf_append_u8(txbuf,IP_ADDR_LEN); + ebuf_append_u16_be(txbuf,ARP_OPCODE_REPLY); + + ebuf_append_bytes(txbuf,ipi->arp_hwaddr,ENET_ADDR_LEN); + ebuf_append_bytes(txbuf,ipi->net_info.ip_addr,IP_ADDR_LEN); + + ebuf_append_bytes(txbuf,targethw,ENET_ADDR_LEN); + ebuf_append_bytes(txbuf,targetip,IP_ADDR_LEN); + + eth_send(txbuf,srcaddr); + eth_free(txbuf); + + return 0; +} + +/* ********************************************************************* + * arp_rx_response(ipi,senderhw,senderip) + * + * Process a received ARP RESPONSE packet. This packet contains + * the hardware address of some host we were querying. Fill + * in the rest of the entries in the ARP table and + * transmit any pending packets. + * + * Input parameters: + * ipi - IP information + * senderhw - sender's hardware address + * senderip - sender's IP address + * + * Return value: + * 0 + ********************************************************************* */ + +static int arp_rx_response(ip_info_t *ipi,uint8_t *senderhw,uint8_t *senderip) +{ + int idx; + arpentry_t *ae; + + ae = ipi->arp_table; + + for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) { + if (ae->ae_state != ae_unused) { + if (memcmp(ae->ae_ipaddr,senderip,IP_ADDR_LEN) == 0) { + memcpy(ae->ae_ethaddr,senderhw,ENET_ADDR_LEN); + ae->ae_state = ae_established; + ae->ae_timer = ARP_KEEP_TIMER; + ae->ae_retries = 0; + ae->ae_permanent = FALSE; + arp_tx_waiting(ae); + } + } + } + + return 0; +} + +/* ********************************************************************* + * arp_rx_callback(buf,ref) + * + * Callback for ARP protocol packets. This routine is called + * by the datalink layer when we receive an ARP packet. Parse + * the packet and call any packet-specific processing routines + * + * Input parameters: + * buf - ebuf that we received + * ref - reference data when we opened the port. This is + * our IP information structure + * + * Return value: + * ETH_DROP or ETH_KEEP. + ********************************************************************* */ + +static int arp_rx_callback(ebuf_t *buf,void *ref) +{ + ip_info_t *ipi = ref; + uint16_t t16; + uint8_t t8; + uint16_t opcode; + uint8_t senderip[IP_ADDR_LEN]; + uint8_t senderhw[ENET_ADDR_LEN]; + uint8_t targetip[IP_ADDR_LEN]; + uint8_t targethw[ENET_ADDR_LEN]; + + /* + * ARP packets have to be at least 28 bytes + */ + + if (ebuf_length(buf) < 28) goto drop; + + /* + * We only do the Ethernet hardware space + */ + + ebuf_get_u16_be(buf,t16); + if (t16 != ARP_HWADDRSPACE_ETHERNET) goto drop; + + /* + * We only do the IP protocol space + */ + + ebuf_get_u16_be(buf,t16); + if (t16 != PROTOSPACE_IP) goto drop; + + /* + * The IP and Ethernet address lengths had better be right. + */ + + ebuf_get_u8(buf,t8); + if (t8 != ENET_ADDR_LEN) goto drop; + + ebuf_get_u8(buf,t8); + if (t8 != IP_ADDR_LEN) goto drop; + + /* + * Get the opcode and other fields. + */ + + ebuf_get_u16_be(buf,opcode); + + ebuf_get_bytes(buf,senderhw,ENET_ADDR_LEN); + ebuf_get_bytes(buf,senderip,IP_ADDR_LEN); + ebuf_get_bytes(buf,targethw,ENET_ADDR_LEN); + ebuf_get_bytes(buf,targetip,IP_ADDR_LEN); + + /* + * If it's not for us, just drop it. + */ + + if (memcmp(targetip,ipi->net_info.ip_addr,IP_ADDR_LEN) != 0) goto drop; + + /* + * Dispatch to an appropriate routine. + */ + + switch (opcode) { + case ARP_OPCODE_REQUEST: + arp_rx_query(ipi,ebuf_srcaddr(buf),senderhw,senderip); + break; + case ARP_OPCODE_REPLY: + arp_rx_response(ipi,senderhw,senderip); + break; + } + +drop: + return ETH_DROP; +} + +/* ********************************************************************* + * _arp_timer_tick(ipi) + * + * ARP timer processing [internal routine]. This routine + * counts down timer ticks in the ARP entries, causing retransmits + * or ARP entry expirations to happen. + * + * Input parameters: + * ipi - IP information + * + * Return value: + * nothing + ********************************************************************* */ + +void _arp_timer_tick(ip_info_t *ipi) +{ + int idx; + arpentry_t *ae; + + ae = ipi->arp_table; + + /* + * Walk through the ARP table. + */ + + for (idx = 0; idx < ARP_TABLE_SIZE; idx++,ae++) { + + switch (ae->ae_state) { + case ae_unused: + /* + * Unused entry. Do nothing. + */ + break; + + case ae_arping: + /* + * Entry is arping. Count down the timer, and retransmit + * the ARP message. + */ + ae->ae_timer--; + if (ae->ae_timer <= 0) { + if (ae->ae_retries == 0) { + arp_delete(ae); + } + else { + ae->ae_retries--; + ae->ae_timer = ARP_QUERY_TIMER; + arp_tx_query(ipi,ae->ae_ipaddr); + } + } + break; + + case ae_established: + /* + * Established entry. Count down the timer and + * delete the ARP entry. If the timer is zero + * already, it's a permanent ARP entry. + */ + if (ae->ae_timer == 0) break; + ae->ae_timer--; + if (ae->ae_timer == 0) arp_delete(ae); + break; + } + } + +} + +/* ********************************************************************* + * _arp_send_gratuitous(ipi) + * + * Transmit the "gratuitous arp" (an ARP for our own IP address). + * This is done customarily when an interface is initialized. + * + * Input parameters: + * ipi - IP information + * + * Return value: + * nothing + ********************************************************************* */ + +void _arp_send_gratuitous(ip_info_t *ipi) +{ + if (!ip_addriszero(ipi->net_info.ip_addr)) { + arp_tx_query(ipi,ipi->net_info.ip_addr); + } +} + +/* ********************************************************************* + * _arp_init(ipi) + * + * Initialize the ARP layer [internal routine] + * + * Input parameters: + * ipi - IP information + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _arp_init(ip_info_t *ipi) +{ + int8_t arpproto[2]; + int idx; + arpentry_t *ae; + + /* + * Allocate space for the ARP table + */ + + ipi->arp_table = KMALLOC(ARP_TABLE_SIZE*sizeof(arpentry_t),0); + + if (ipi->arp_table == NULL) return NULL; + + /* + * Initialize the ARP table. + */ + + ae = ipi->arp_table; + for (idx = 0; idx < ARP_TABLE_SIZE; idx++) { + ae->ae_state = ae_unused; + ae->ae_timer = 0; + ae->ae_usage = 0; + ae->ae_retries = 0; + ae->ae_permanent = 0; + q_init(&(ae->ae_txqueue)); + ae++; + } + + /* + * Open the Ethernet portal for ARP packets + */ + + arpproto[0] = (PROTOSPACE_ARP >> 8) & 0xFF; + arpproto[1] = (PROTOSPACE_ARP & 0xFF); + ipi->arp_port = eth_open(ipi->eth_info,ETH_PTYPE_DIX,arpproto,arp_rx_callback,ipi); + + if (ipi->arp_port < 0) { + KFREE(ipi->arp_table); + ipi->arp_table = NULL; + return -1; + } + + /* + * Remember our hardware address + */ + + eth_gethwaddr(ipi->eth_info,ipi->arp_hwaddr); + + /* + * Send a query for ourselves if our IP address is set + */ + + _arp_send_gratuitous(ipi); + + return 0; + +} + + +/* ********************************************************************* + * _arp_uninit(ipi) + * + * Uninitialize the ARP interface. This is called when the + * network module is shut down. + * + * Input parameters: + * ipi - IP information + * + * Return value: + * nothing + ********************************************************************* */ + +void _arp_uninit(ip_info_t *ipi) +{ + int idx; + arpentry_t *ae; + + /* + * Close the Ethernet portal + */ + + eth_close(ipi->eth_info,ipi->arp_port); + + /* + * Clear out the ARP Table. + */ + + ae = ipi->arp_table; + for (idx = 0; idx < ARP_TABLE_SIZE; idx++) { + if (ae->ae_state != ae_unused) arp_delete(ae); + ae++; + } + + /* + * Free up the memory. + */ + + KFREE(ipi->arp_table); + ipi->arp_table = NULL; + ipi->arp_port = -1; +} + + +/* ********************************************************************* + * _arp_enumerate(ipi,entrynum,ipaddr,hwaddr) + * + * Enumerate the ARP table. This is used by user-interface + * routines to display the current contents of the ARP table. + * + * Input parameters: + * ipi - IP information + * entrynum - entry index + * ipaddr - buffer to copy entry's IP address to + * hwaddr - buffer to copy entry's hardware address to + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _arp_enumerate(ip_info_t *ipi,int entrynum,uint8_t *ipaddr,uint8_t *hwaddr) +{ + arpentry_t *ae; + int idx; + + ae = ipi->arp_table; + for (idx = 0; idx < ARP_TABLE_SIZE; idx++) { + if (ae->ae_state != ae_unused) { + if (entrynum == 0) { + memcpy(ipaddr,ae->ae_ipaddr,IP_ADDR_LEN); + memcpy(hwaddr,ae->ae_ethaddr,ENET_ADDR_LEN); + return 0; + } + entrynum--; + } + ae++; + } + + return -1; +} + + +/* ********************************************************************* + * _arp_delete(ipi,ipaddr) + * + * Delete an ARP entry. This routine takes an IP address, looks + * up its ARP table entry, and removes it from the table. + * + * Input parameters: + * ipi - IP information + * ipaddr - IP address whose entry to delete + * + * Return value: + * 0 if entry was deleted + * <0 if entry was not found + ********************************************************************* */ + +int _arp_delete(ip_info_t *ipi,uint8_t *ipaddr) +{ + arpentry_t *ae; + + ae = arp_find_entry(ipi,ipaddr); + + if (ae) { + arp_delete(ae); + return 0; + } + return -1; +} diff --git a/cfe/cfe/net/net_dhcp.c b/cfe/cfe/net/net_dhcp.c new file mode 100644 index 0000000..84a39e6 --- /dev/null +++ b/cfe/cfe/net/net_dhcp.c @@ -0,0 +1,869 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * DHCP Client File: net_dhcp.c + * + * This module contains a DHCP client. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "env_subr.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "cfe.h" + +#include "net_api.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + + +#define UDP_PORT_BOOTPS 67 +#define UDP_PORT_BOOTPC 68 + +#define DHCP_REQ_TIMEOUT (1*CFE_HZ) +#define DHCP_NUM_RETRIES 8 + +#define DHCP_OP_BOOTREQUEST 1 +#define DHCP_OP_BOOTREPLY 2 + +#define DHCP_HWTYPE_ETHERNET 1 + +#define DHCP_TAG_FUNCTION 53 +#define DHCP_FUNCTION_DISCOVER 1 +#define DHCP_FUNCTION_OFFER 2 +#define DHCP_FUNCTION_REQUEST 3 +#define DHCP_FUNCTION_ACK 5 + +#define DHCP_TAG_NETMASK 1 +#define DHCP_TAG_DOMAINNAME 0x0F +#define DHCP_TAG_GATEWAY 0x03 +#define DHCP_TAG_NAMESERVER 0x06 +#define DHCP_TAG_SWAPSERVER 0x10 +#define DHCP_TAG_ROOTPATH 0x11 +#define DHCP_TAG_EXTENSIONS 0x12 +#define DHCP_TAG_SERVERIDENT 54 +#define DHCP_TAG_PARAMLIST 55 +#define DHCP_TAG_CLIENTID 61 +#define DHCP_TAG_CLASSID 60 +#define DHCP_TAG_REQADDR 50 +#define DHCP_TAG_LEASE_TIME 51 +#define DHCP_TAG_SCRIPT 130 /* CFE extended option */ +#define DHCP_TAG_OPTIONS 131 /* CFE extended option */ + +#define DHCP_TAG_END 0xFF + +#define DHCP_MAGIC_NUMBER 0x63825363 + +/*#define _DEBUG_*/ + + +/* ********************************************************************* + * dhcp_set_envvars(reply) + * + * Using the supplied DHCP reply data, set environment variables + * to contain data from the reply. + * + * Input parameters: + * reply - dhcp reply + * + * Return value: + * nothing + ********************************************************************* */ + +void dhcp_set_envvars(dhcpreply_t *reply) +{ + char buffer[50]; + + env_delenv("BOOT_SERVER"); + env_delenv("BOOT_FILE"); + env_delenv("BOOT_SCRIPT"); + env_delenv("BOOT_OPTIONS"); + + if (reply->dr_bootserver[0] | reply->dr_bootserver[1] | + reply->dr_bootserver[2] | reply->dr_bootserver[3]) { + sprintf(buffer,"%I",reply->dr_bootserver); + env_setenv("BOOT_SERVER",buffer,ENV_FLG_BUILTIN); + } + + if (reply->dr_bootfile && reply->dr_bootfile[0]) { + env_setenv("BOOT_FILE",reply->dr_bootfile,ENV_FLG_BUILTIN); + } + + if (reply->dr_script && reply->dr_script[0]) { + env_setenv("BOOT_SCRIPT",reply->dr_script,ENV_FLG_BUILTIN); + } + + if (reply->dr_options && reply->dr_options[0]) { + env_setenv("BOOT_OPTIONS",reply->dr_options,ENV_FLG_BUILTIN); + } +} + +/* ********************************************************************* + * dhcp_dumptag(tag,len,buf) + * + * Dump out information from a DHCP tag + * + * Input parameters: + * tag - tag ID + * len - length of data + * buf - data + * + * Return value: + * nothing + ********************************************************************* */ + +#ifdef _DEBUG_ +static void dhcp_dumptag(uint8_t tag,uint8_t len,uint8_t *buf) +{ + unsigned int idx; + + xprintf("DHCP: "); + + switch (tag) { + case DHCP_TAG_FUNCTION: + xprintf("DHCP Function: %d\n",buf[0]); + break; + case DHCP_TAG_LEASE_TIME: + idx = (((unsigned int) buf[0]) << 24) | + (((unsigned int) buf[1]) << 16) | + (((unsigned int) buf[2]) << 8) | + (((unsigned int) buf[3]) << 0); + xprintf("Lease Time: %d seconds\n",idx); + break; + case DHCP_TAG_SERVERIDENT: + xprintf("DHCP Server ID: %d.%d.%d.%d\n", + buf[0],buf[1],buf[2],buf[3]); + break; + case DHCP_TAG_NETMASK: + xprintf("Netmask: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]); + break; + case DHCP_TAG_DOMAINNAME: + buf[len] = 0; + xprintf("Domain: %s\n",buf); + break; + case DHCP_TAG_GATEWAY: + xprintf("Gateway: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]); + break; + case DHCP_TAG_NAMESERVER: + xprintf("Nameserver: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]); + break; + case DHCP_TAG_SWAPSERVER: + buf[len] = 0; + xprintf("Swapserver: %s\n",buf); + break; + case DHCP_TAG_ROOTPATH: + buf[len] = 0; + xprintf("Rootpath: %s\n",buf); + break; + case DHCP_TAG_SCRIPT: + buf[len] = 0; + xprintf("CFE Script: %s\n",buf); + break; + case DHCP_TAG_OPTIONS: + buf[len] = 0; + xprintf("CFE Boot Options: %s\n",buf); + break; + default: + xprintf("Tag %d len %d [",tag,len); + for (idx = 0; idx < len; idx++) { + if ((buf[idx] >= 32) && (buf[idx] < 127)) xprintf("%c",buf[idx]); + } + xprintf("]\n"); + break; + + } +} +#endif + +/* ********************************************************************* + * dhcp_free_reply(reply) + * + * Free memory associated with a DHCP reply. + * + * Input parameters: + * reply - pointer to DHCP reply + * + * Return value: + * nothing + ********************************************************************* */ + +void dhcp_free_reply(dhcpreply_t *reply) +{ + if (reply->dr_hostname) KFREE(reply->dr_hostname); + if (reply->dr_domainname) KFREE(reply->dr_domainname); + if (reply->dr_bootfile) KFREE(reply->dr_bootfile); + if (reply->dr_rootpath) KFREE(reply->dr_rootpath); + if (reply->dr_swapserver) KFREE(reply->dr_swapserver); + if (reply->dr_script) KFREE(reply->dr_script); + if (reply->dr_options) KFREE(reply->dr_options); + KFREE(reply); +} + +/* ********************************************************************* + * dhcp_build_discover() + * + * Build a DHCP DISCOVER packet + * + * Input parameters: + * hwaddr - our hardware address + * idptr - pointer to int to receive the DHCP packet ID + * serveraddr - pointer to server address (REQUEST) or + * NULL (DISCOVER) + * ebufptr - receives pointer to ebuf + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int dhcp_build_discover(uint8_t *hwaddr, + uint32_t id, + ebuf_t **ebufptr) +{ + uint8_t ipaddr[IP_ADDR_LEN]; + ebuf_t *buf; + uint8_t junk[128]; + + /* + * Get a buffer and fill it in. + */ + + ipaddr[0] = 0; ipaddr[1] = 0; ipaddr[2] = 0; ipaddr[3] = 0; + memset(junk,0,sizeof(junk)); + + buf = udp_alloc(); + + if (buf == NULL) { + return CFE_ERR_NOMEM; + } + + memset(buf->eb_ptr,0,548); + + ebuf_append_u8(buf,DHCP_OP_BOOTREQUEST); + ebuf_append_u8(buf,DHCP_HWTYPE_ETHERNET); + ebuf_append_u8(buf,ENET_ADDR_LEN); + ebuf_append_u8(buf,0); /* hops */ + ebuf_append_u32_be(buf,id); + ebuf_append_u16_be(buf,0); /* sec since boot */ + ebuf_append_u16_be(buf,0); /* flags */ + + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* ciaddr */ + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* yiaddr */ + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* siaddr */ + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* giaddr */ + + ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); /* chaddr */ + ebuf_append_bytes(buf,junk,10); /* rest of chaddr */ + ebuf_append_bytes(buf,junk,64); /* sname */ + ebuf_append_bytes(buf,junk,128); /* file */ + + ebuf_append_u32_be(buf,DHCP_MAGIC_NUMBER); + + ebuf_append_u8(buf,DHCP_TAG_FUNCTION); /* function code */ + ebuf_append_u8(buf,1); + ebuf_append_u8(buf,DHCP_FUNCTION_DISCOVER); + + ebuf_append_u8(buf,DHCP_TAG_PARAMLIST); + ebuf_append_u8(buf,8); /* count of tags that follow */ + ebuf_append_u8(buf,DHCP_TAG_NETMASK); + ebuf_append_u8(buf,DHCP_TAG_DOMAINNAME); + ebuf_append_u8(buf,DHCP_TAG_GATEWAY); + ebuf_append_u8(buf,DHCP_TAG_NAMESERVER); + ebuf_append_u8(buf,DHCP_TAG_SWAPSERVER); + ebuf_append_u8(buf,DHCP_TAG_ROOTPATH); + ebuf_append_u8(buf,DHCP_TAG_SCRIPT); + ebuf_append_u8(buf,DHCP_TAG_OPTIONS); + + + ebuf_append_u8(buf,DHCP_TAG_END); /* terminator */ + + /* + * Return the packet + */ + + *ebufptr = buf; + + return 0; +} + +/* ********************************************************************* + * dhcp_build_request() + * + * Build a DHCP DISCOVER or REQUEST packet + * + * Input parameters: + * hwaddr - our hardware address + * idptr - pointer to int to receive the DHCP packet ID + * serveraddr - pointer to server address (REQUEST) or + * NULL (DISCOVER) + * ebufptr - receives pointer to ebuf + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int dhcp_build_request(uint8_t *hwaddr, + uint32_t id, + uint8_t *serveraddr, + uint8_t *reqip, + ebuf_t **ebufptr) +{ + uint8_t ipaddr[IP_ADDR_LEN]; + ebuf_t *buf; + uint8_t junk[128]; + + /* + * Get a buffer and fill it in. + */ + + ipaddr[0] = 0; ipaddr[1] = 0; ipaddr[2] = 0; ipaddr[3] = 0; + memset(junk,0,sizeof(junk)); + + buf = udp_alloc(); + + if (buf == NULL) { + return CFE_ERR_NOMEM; + } + + memset(buf->eb_ptr,0,548); + + ebuf_append_u8(buf,DHCP_OP_BOOTREQUEST); + ebuf_append_u8(buf,DHCP_HWTYPE_ETHERNET); + ebuf_append_u8(buf,ENET_ADDR_LEN); + ebuf_append_u8(buf,0); /* hops */ + ebuf_append_u32_be(buf,id); + ebuf_append_u16_be(buf,0); /* sec since boot */ + ebuf_append_u16_be(buf,0); /* flags */ + + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* ciaddr */ + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* yiaddr */ + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* siaddr */ + ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* giaddr */ + + ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); /* chaddr */ + ebuf_append_bytes(buf,junk,10); /* rest of chaddr */ + + ebuf_append_bytes(buf,junk,64); /* sname */ + + ebuf_append_bytes(buf,junk,128); /* file */ + + ebuf_append_u32_be(buf,DHCP_MAGIC_NUMBER); + + ebuf_append_u8(buf,DHCP_TAG_FUNCTION); /* function code */ + ebuf_append_u8(buf,1); + + ebuf_append_u8(buf,DHCP_FUNCTION_REQUEST); + + ebuf_append_u8(buf,DHCP_TAG_REQADDR); + ebuf_append_u8(buf,IP_ADDR_LEN); + ebuf_append_bytes(buf,reqip,IP_ADDR_LEN); + + ebuf_append_u8(buf,DHCP_TAG_SERVERIDENT); /* server ID */ + ebuf_append_u8(buf,IP_ADDR_LEN); + ebuf_append_bytes(buf,serveraddr,IP_ADDR_LEN); + + ebuf_append_u8(buf,DHCP_TAG_CLIENTID); /* client ID */ + ebuf_append_u8(buf,7); + ebuf_append_u8(buf,1); + ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); + + ebuf_append_u8(buf,DHCP_TAG_PARAMLIST); + ebuf_append_u8(buf,8); /* count of tags that follow */ + ebuf_append_u8(buf,DHCP_TAG_NETMASK); + ebuf_append_u8(buf,DHCP_TAG_DOMAINNAME); + ebuf_append_u8(buf,DHCP_TAG_GATEWAY); + ebuf_append_u8(buf,DHCP_TAG_NAMESERVER); + ebuf_append_u8(buf,DHCP_TAG_SWAPSERVER); + ebuf_append_u8(buf,DHCP_TAG_ROOTPATH); + ebuf_append_u8(buf,DHCP_TAG_SCRIPT); + ebuf_append_u8(buf,DHCP_TAG_OPTIONS); + + + ebuf_append_u8(buf,DHCP_TAG_END); /* terminator */ + + /* + * Return the packet + */ + + *ebufptr = buf; + + return 0; +} + + +/* ********************************************************************* + * dhcp_wait_reply(s,id,reply,serveraddr) + * + * Wait for a reply from the DHCP server + * + * Input parameters: + * s - socket + * id - ID of request we sent + * reply - structure to store results in + * expfcode - expected DHCP_FUNCTION tag value + * + * Return value: + * 0 if ok (reply found) + * else error + ********************************************************************* */ + +static int dhcp_wait_reply(int s,uint32_t id,dhcpreply_t *reply,int expfcode) +{ + uint32_t tmpd; + uint8_t tmpb; + int64_t timer; + int nres = 0; + uint8_t ciaddr[IP_ADDR_LEN]; + uint8_t yiaddr[IP_ADDR_LEN]; + uint8_t siaddr[IP_ADDR_LEN]; + uint8_t giaddr[IP_ADDR_LEN]; + uint8_t junk[128]; + char *hostname; + char *bootfile; + ebuf_t *buf; + int fcode = -1; + + /* + * Set a timer for the response + */ + + TIMER_SET(timer,DHCP_REQ_TIMEOUT); + + /* + * Start waiting... + */ + + while (!TIMER_EXPIRED(timer)) { + POLL(); + + buf = udp_recv(s); + if (!buf) continue; + + ebuf_get_u8(buf,tmpb); + if (tmpb != DHCP_OP_BOOTREPLY) { + goto drop; + } + + ebuf_get_u8(buf,tmpb); + if (tmpb != DHCP_HWTYPE_ETHERNET) { + goto drop; + } + + ebuf_get_u8(buf,tmpb); + if (tmpb != ENET_ADDR_LEN) { + goto drop; + } + + ebuf_skip(buf,1); /* hops */ + + ebuf_get_u32_be(buf,tmpd); /* check ID */ + if (tmpd != id) { + goto drop; + } + + ebuf_skip(buf,2); /* seconds since boot */ + ebuf_skip(buf,2); /* flags */ + + ebuf_get_bytes(buf,ciaddr,IP_ADDR_LEN); + ebuf_get_bytes(buf,yiaddr,IP_ADDR_LEN); + ebuf_get_bytes(buf,siaddr,IP_ADDR_LEN); + ebuf_get_bytes(buf,giaddr,IP_ADDR_LEN); + + ebuf_skip(buf,16); /* hardware address */ + hostname = ebuf_ptr(buf); + ebuf_skip(buf,64); + bootfile = ebuf_ptr(buf); + + ebuf_skip(buf,128); + +#ifdef _DEBUG_ + xprintf("Client IP: %d.%d.%d.%d\n",ciaddr[0],ciaddr[1],ciaddr[2],ciaddr[3]); + xprintf("Your IP: %d.%d.%d.%d\n",yiaddr[0],yiaddr[1],yiaddr[2],yiaddr[3]); + xprintf("Server IP: %d.%d.%d.%d\n",siaddr[0],siaddr[1],siaddr[2],siaddr[3]); + xprintf("Gateway IP: %d.%d.%d.%d\n",giaddr[0],giaddr[1],giaddr[2],giaddr[3]); + xprintf("hostname: %s\n",hostname); + xprintf("boot file: %s\n",bootfile); +#endif + + memcpy(reply->dr_ipaddr,yiaddr,IP_ADDR_LEN); + memcpy(reply->dr_gateway,giaddr,IP_ADDR_LEN); + memcpy(reply->dr_bootserver,siaddr,IP_ADDR_LEN); + if (*hostname) reply->dr_hostname = strdup(hostname); + if (*bootfile) reply->dr_bootfile = strdup(bootfile); + + /* + * Test for options - look for magic number + */ + + ebuf_get_u32_be(buf,tmpd); + + memcpy(reply->dr_dhcpserver,buf->eb_usrptr,IP_ADDR_LEN); + + if (tmpd == DHCP_MAGIC_NUMBER) { + uint8_t tag; + uint8_t len; + + while (buf->eb_length > 0) { + ebuf_get_u8(buf,tag); + if (tag == DHCP_TAG_END) break; + ebuf_get_u8(buf,len); + ebuf_get_bytes(buf,junk,len); + +#ifdef _DEBUG_ + dhcp_dumptag(tag,len,junk); +#endif + + switch (tag) { + case DHCP_TAG_FUNCTION: + fcode = (uint8_t) junk[0]; + break; + case DHCP_TAG_NETMASK: + memcpy(reply->dr_netmask,junk,IP_ADDR_LEN); + break; + case DHCP_TAG_GATEWAY: + memcpy(reply->dr_gateway,junk,IP_ADDR_LEN); + break; + case DHCP_TAG_NAMESERVER: + memcpy(reply->dr_nameserver,junk,IP_ADDR_LEN); + break; + case DHCP_TAG_DOMAINNAME: + junk[len] = 0; + if (len) reply->dr_domainname = strdup(junk); + break; + case DHCP_TAG_SWAPSERVER: + junk[len] = 0; + if (len) reply->dr_swapserver = strdup(junk); + break; + case DHCP_TAG_SERVERIDENT: + if (len == IP_ADDR_LEN) { + memcpy(reply->dr_dhcpserver,junk,len); + } + break; + case DHCP_TAG_ROOTPATH: + junk[len] = 0; + if (len) reply->dr_rootpath = strdup(junk); + break; + case DHCP_TAG_SCRIPT: + junk[len] = 0; + if (len) reply->dr_script = strdup(junk); + break; + case DHCP_TAG_OPTIONS: + junk[len] = 0; + if (len) reply->dr_options = strdup(junk); + break; + } + } + } + + if (fcode != expfcode) { + goto drop; + } + + udp_free(buf); + nres++; + break; + + drop: + udp_free(buf); + } + + if (nres > 0) return 0; + else return CFE_ERR_TIMEOUT; +} + + +/* ********************************************************************* + * dhcp_do_dhcpdiscover(s,hwaddr,reply) + * + * Request an IP address from the DHCP server. On success, the + * dhcpreply_t structure will be filled in + * + * Input parameters: + * s - udp socket + * hwaddr - our hardware address + * reply - pointer to reply buffer. + * + * Return value: + * 0 if a response was received + * else error code + ********************************************************************* */ + +static int dhcp_do_dhcpdiscover(int s,uint8_t *hwaddr,dhcpreply_t *reply) +{ + ebuf_t *buf; + uint32_t id; + uint8_t ipaddr[IP_ADDR_LEN]; + int res; + + /* + * Packet ID is the current time + */ + + id = (uint32_t)cfe_ticks; + + /* + * Build the DISCOVER request + */ + + res = dhcp_build_discover(hwaddr,id,&buf); + if (res != 0) return res; + + /* + * Send the packet to the IP broadcast (255.255.255.255) + */ + + ipaddr[0] = 0xFF; ipaddr[1] = 0xFF; ipaddr[2] = 0xFF; ipaddr[3] = 0xFF; + udp_send(s,buf,ipaddr); + + /* + * Wait for a reply + */ + + res = dhcp_wait_reply(s,id,reply,DHCP_FUNCTION_OFFER); + + return res; +} + + +/* ********************************************************************* + * dhcp_do_dhcprequest(s,hwaddr,reply,discover_reply) + * + * Request an IP address from the DHCP server. On success, the + * dhcpreply_t structure will be filled in + * + * Input parameters: + * s - udp socket + * hwaddr - our hardware address + * reply - pointer to reply buffer. + * discover_reply - pointer to previously received DISCOVER data + * + * Return value: + * 0 if a response was received + * else error code + ********************************************************************* */ + +static int dhcp_do_dhcprequest(int s,uint8_t *hwaddr, + dhcpreply_t *reply, + dhcpreply_t *discover_reply) +{ + ebuf_t *buf; + uint32_t id; + uint8_t ipaddr[IP_ADDR_LEN]; + int res; + + /* + * Packet ID is the current time + */ + + id = (uint32_t)cfe_ticks; + + /* + * Build the DHCP REQUEST request + */ + + res = dhcp_build_request(hwaddr, + id, + discover_reply->dr_dhcpserver, + discover_reply->dr_ipaddr, + &buf); + + if (res != 0) return res; + + /* + * Send the packet to the IP broadcast (255.255.255.255) + */ + + ipaddr[0] = 0xFF; ipaddr[1] = 0xFF; ipaddr[2] = 0xFF; ipaddr[3] = 0xFF; + udp_send(s,buf,ipaddr); + + /* + * Wait for a reply + */ + + res = dhcp_wait_reply(s,id,reply,DHCP_FUNCTION_ACK); + + return res; +} + + +/* ********************************************************************* + * dhcp_bootrequest(reply) + * + * Request an IP address from the DHCP server. On success, the + * dhcpreply_t structure will be allocated. + * + * Input parameters: + * reply - pointer to pointer to reply. + * + * Return value: + * 0 if no responses received + * >0 for some responses received + * else error code + ********************************************************************* */ + +int dhcp_bootrequest(dhcpreply_t **rep) +{ + uint8_t *hwaddr; + int s; + dhcpreply_t *discover_reply; + dhcpreply_t *request_reply; + int nres = 0; + int retries; + uint32_t id; + + id = (uint32_t) cfe_ticks; + + /* + * Start with empty reply buffers. Since we use a portion of the + * discover reply in the request, we'll keep two of them. + */ + + discover_reply = KMALLOC(sizeof(dhcpreply_t),0); + if (discover_reply == NULL) { + return CFE_ERR_NOMEM; + } + memset(discover_reply,0,sizeof(dhcpreply_t)); + + request_reply = KMALLOC(sizeof(dhcpreply_t),0); + if (request_reply == NULL) { + KFREE(discover_reply); + return CFE_ERR_NOMEM; + } + memset(request_reply,0,sizeof(dhcpreply_t)); + + + /* + * Get our hw addr + */ + + hwaddr = net_getparam(NET_HWADDR); + if (!hwaddr) { + KFREE(discover_reply); + KFREE(request_reply); + return CFE_ERR_NETDOWN; + } + + /* + * Open UDP port + */ + + s = udp_socket(UDP_PORT_BOOTPS); + if (s < 0) { + KFREE(discover_reply); + KFREE(request_reply); + return CFE_ERR_NOHANDLES; + } + + udp_bind(s,UDP_PORT_BOOTPC); + + /* + * Do the boot request. Start by sending the OFFER message + */ + + nres = CFE_ERR_TIMEOUT; + for (retries = 0; retries < DHCP_NUM_RETRIES; retries++) { + nres = dhcp_do_dhcpdiscover(s,hwaddr,discover_reply); + if (nres == 0) break; + if (nres == CFE_ERR_TIMEOUT) continue; + break; + } + + /* + * If someone sent us a response, send the REQUEST message + * to get a lease. + */ + + if (nres == 0) { + + /* + * Now, send the REQUEST message and get a response. + */ + + for (retries = 0; retries < DHCP_NUM_RETRIES; retries++) { + nres = dhcp_do_dhcprequest(s,hwaddr, + request_reply, + discover_reply); + if (nres == 0) break; + if (nres == CFE_ERR_TIMEOUT) continue; + break; + } + } + + /* + * All done with the discover reply. + */ + + dhcp_free_reply(discover_reply); + + /* + * All done with UDP + */ + + udp_close(s); + + /* + * Return the reply info. + */ + + if (nres == 0) { + *rep = request_reply; + } + else { + *rep = NULL; + dhcp_free_reply(request_reply); + } + + return nres; +} diff --git a/cfe/cfe/net/net_dns.c b/cfe/cfe/net/net_dns.c new file mode 100755 index 0000000..89b50b1 --- /dev/null +++ b/cfe/cfe/net/net_dns.c @@ -0,0 +1,354 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Domain Name System Resolver File: net_dns.c + * + * This module provides minimal support for looking up IP addresses + * from DNS name servers (RFCxxxx) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "cfe.h" + +#include "net_api.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0) + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define UDP_PORT_DNS 53 + +#define DNS_FLG_QUERY 0x0000 +#define DNS_FLG_RESPONSE 0x8000 +#define DNS_OPCODE_QUERY 0x0000 +#define DNS_FLG_AA 0x0400 +#define DNS_FLG_TC 0x0200 +#define DNS_FLG_RD 0x0100 +#define DNS_FLG_RA 0x0080 +#define DNS_RCODE_MASK 0x000F +#define DNS_RCODE_OK 0x0000 +#define DNS_RCODE_NAMEERR 0x0003 + + +#define QTYPE_HOSTADDR 1 +#define QCLASS_INTERNET 1 + +#define DNS_QUERY_TIMEOUT 1 /* seconds */ +#define DNS_RETRY_COUNT 8 + + +/* ********************************************************************* + * dns_dolookup(s,hostname,ipaddr) + * + * Look up a host name and return its IP address. + * + * Input parameters: + * s - udp socket + * server - name server to query + * hostname - host name to find + * ipaddr - buffer to place IP address + * + * Return value: + * 0 if no responses found + * >0 to indicate number of response records (usually 1) + * else error code + ********************************************************************* */ + +static int dns_dolookup(int s,uint8_t *server,char *hostname,uint8_t *ipaddr) +{ + ebuf_t *buf; + uint16_t id; + uint16_t tmp; + char *tok; + char *ptr; + int64_t timer; + int nres = 0; + uint16_t nqr,nar,nns,nxr; + uint8_t tmpb; + int expired; + + + /* + * Use the current time for our request ID + */ + + id = (uint16_t) cfe_ticks; + + /* + * Get a buffer and fill it in. + */ + + buf = udp_alloc(); + + ebuf_append_u16_be(buf,id); + ebuf_append_u16_be(buf,(DNS_FLG_QUERY | DNS_OPCODE_QUERY | DNS_FLG_RD)); + ebuf_append_u16_be(buf,1); /* one question */ + ebuf_append_u16_be(buf,0); /* no answers */ + ebuf_append_u16_be(buf,0); /* no server resource records */ + ebuf_append_u16_be(buf,0); /* no additional records */ + + /* + * Chop up the hostname into pieces, basically replacing + * the dots with length indicators. + */ + + ptr = hostname; + + while ((tok = strchr(ptr,'.'))) { + ebuf_append_u8(buf,(tok-ptr)); + ebuf_append_bytes(buf,ptr,(tok-ptr)); + ptr = tok + 1; + } + + ebuf_append_u8(buf,strlen(ptr)); + ebuf_append_bytes(buf,ptr,strlen(ptr)); + ebuf_append_u8(buf,0); + ebuf_append_u16_be(buf,QTYPE_HOSTADDR); + ebuf_append_u16_be(buf,QCLASS_INTERNET); + + /* + * Send the request to the name server + */ + + udp_send(s,buf,server); + + /* + * Set a timer for the response + */ + + TIMER_SET(timer,DNS_QUERY_TIMEOUT*CFE_HZ); + + /* + * Start waiting... + */ + + while (!(expired = TIMER_EXPIRED(timer))) { + POLL(); + + buf = udp_recv(s); + if (!buf) continue; + + /* IDs must match */ + + ebuf_get_u16_be(buf,tmp); + if (id != tmp) goto drop; + + /* It must be a response */ + + ebuf_get_u16_be(buf,tmp); + + if ((tmp & DNS_FLG_RESPONSE) == 0) goto drop; + + if ((tmp & DNS_RCODE_MASK) != DNS_RCODE_OK) { + udp_free(buf); + /* name error */ + break; + } + + ebuf_get_u16_be(buf,nqr); + ebuf_get_u16_be(buf,nar); + ebuf_get_u16_be(buf,nns); + ebuf_get_u16_be(buf,nxr); + + if (nar == 0) { + goto drop; + } + + while (nqr > 0) { + if (ebuf_length(buf) <= 0) { + goto drop; + } + for (;;) { + ebuf_get_u8(buf,tmpb); + if (tmpb == 0) break; + ebuf_skip(buf,tmpb); + if (ebuf_length(buf) <= 0) { + goto drop; + } + } + ebuf_skip(buf,2); /* skip QTYPE */ + ebuf_skip(buf,2); /* skip QCLASS */ + nqr--; /* next question record */ + } + + /* + * Loop through the answer records to find + * a HOSTADDR record. Ignore any other records + * we find. + */ + + while (nar > 0) { + uint16_t rname,rtype,rclass,dlen; + + ebuf_get_u16_be(buf,rname); /* resource name */ + + ebuf_get_u16_be(buf,rtype); /* resource type */ + + ebuf_get_u16_be(buf,rclass); /* resource class */ + + ebuf_skip(buf,4); /* time to live */ + + ebuf_get_u16_be(buf,dlen); /* length of data */ + + if (rtype != QTYPE_HOSTADDR) { + ebuf_skip(buf,dlen); + nar--; + continue; + } + if (rclass != QCLASS_INTERNET) { + ebuf_skip(buf,dlen); + nar--; + continue; + } + + if (dlen != IP_ADDR_LEN) { + ebuf_skip(buf,dlen); + nar--; + continue; + } + + ebuf_get_bytes(buf,ipaddr,IP_ADDR_LEN); + break; + } + + if (nar == 0) goto drop; + + udp_free(buf); + nres++; + break; + + drop: + udp_free(buf); + } + + if (expired) return CFE_ERR_TIMEOUT; + if (nres == 0) return CFE_ERR_HOSTUNKNOWN; + return nres; +} + + +/* ********************************************************************* + * dns_lookup(hostname,ipaddr) + * + * Look up a host name and return its IP address. + * + * Input parameters: + * hostname - host name to find + * ipaddr - buffer to place IP address + * + * Return value: + * 0 if no responses found + * >0 to indicate number of response records (usually 1) + * else error code + ********************************************************************* */ + +int dns_lookup(char *hostname,uint8_t *ipaddr) +{ + int s; + int nres = 0; + int retries; + char temphostname[100]; + uint8_t *server; + uint8_t *tok; + + /* + * If it's a valid IP address, don't look it up. + */ + + if (parseipaddr(hostname,ipaddr) == 0) return 1; + + /* + * Add default domain if no domain was specified + */ + + if (strchr(hostname,'.') == NULL) { + tok = net_getparam(NET_DOMAIN); + if (tok) { + xsprintf(temphostname,"%s.%s",hostname,tok); + hostname = temphostname; + } + } + + /* + * Figure out who the name server is + */ + + server = net_getparam(NET_NAMESERVER); + + if (!server) return CFE_ERR_NETDOWN; + if (ip_addriszero(server)) return CFE_ERR_NONAMESERVER; + + /* + * Go do the name server lookup + */ + + s = udp_socket(UDP_PORT_DNS); + if (s < 0) return CFE_ERR_NOHANDLES; + + for (retries = 0; retries < DNS_RETRY_COUNT; retries++) { + nres = dns_dolookup(s,server,hostname,ipaddr); + if (nres == CFE_ERR_TIMEOUT) continue; + if (nres >= 0) break; + } + + udp_close(s); + + return nres; + +} diff --git a/cfe/cfe/net/net_ebuf.h b/cfe/cfe/net/net_ebuf.h new file mode 100644 index 0000000..11d83c1 --- /dev/null +++ b/cfe/cfe/net/net_ebuf.h @@ -0,0 +1,165 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Network EBUF macros File: net_ebuf.h + * + * This file contains macros and function prototypes for + * messing with "ebuf" buffers. ebufs describe network + * packets. They're sort of like poor-man's mbufs :-) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + + +#define ENET_MAX_PKT 1514 +#define ENET_CRC_SIZE 4 +#define ENET_ADDR_LEN 6 +#define ENET_DIX_HEADER 14 + +/* ********************************************************************* + * Structures + ********************************************************************* */ + + +typedef struct ebuf_s { + queue_t eb_qblock; /* linkage */ + unsigned int eb_length; /* length of area at eb_ptr */ + unsigned int eb_status; /* rx/tx status */ + int eb_port; /* eth port that owns buffer */ + void *eb_device; /* underlying net device */ + int eb_usrdata; /* user-defined stuff */ + uint8_t *eb_usrptr; /* user-defined stuff */ + uint8_t *eb_ptr; /* current ptr within pkt */ + uint8_t eb_data[0x5F0]; /* data, must be > ENET_MAX_PKT */ + /* and divisible by sizeof(uint) */ +} ebuf_t; + +/* + * Macros to initialize ebufs + */ + +#define ebuf_init_rx(eb) (eb)->eb_ptr = (eb)->eb_data; \ + (eb)->eb_length = 0; \ + (eb)->eb_status = 0 + +#define ebuf_init_tx(eb) (eb)->eb_ptr = (eb)->eb_data; \ + (eb)->eb_length = 0; \ + (eb)->eb_status = 0 + +/* + * Macros to move the currens position within an ebuf + */ + +#define ebuf_prepend(eb,amt) (eb)->eb_ptr -= amt; (eb)->eb_length += (amt) +#define ebuf_adjust(eb,amt) (eb)->eb_ptr += (amt); (eb)->eb_length += (amt) +#define ebuf_seek(eb,amt) (eb)->eb_ptr += (amt) + +#define ebuf_remlen(eb) ((eb)->eb_length) +#define ebuf_length(eb) ((eb)->eb_length) +#define ebuf_ptr(eb) ((eb)->eb_ptr) +#define ebuf_setlength(eb,amt) (eb)->eb_length = (amt) + +/* + * ebuf_append_xxx macros - these macros add data to the + * end of a packet, adjusting the length + */ + +#define ebuf_append_u8(eb,b) ((eb)->eb_ptr[(eb)->eb_length++]) = (b) ; +#define ebuf_append_u16_be(eb,w) ebuf_append_u8(eb,((w) >> 8) & 0xFF) ; \ + ebuf_append_u8(eb,((w) & 0xFF)) + +#define ebuf_append_u32_be(eb,w) ebuf_append_u8(eb,((w) >> 24) & 0xFF) ; \ + ebuf_append_u8(eb,((w) >> 16) & 0xFF) ; \ + ebuf_append_u8(eb,((w) >> 8) & 0xFF) ; \ + ebuf_append_u8(eb,((w) & 0xFF)) + +#define ebuf_append_bytes(eb,b,l) memcpy(&((eb)->eb_ptr[(eb)->eb_length]),(b),(l)); \ + (eb)->eb_length += (l) + +/* + * ebuf_put_xxx macros - these macros modify data in the middle + * of a packet, typically in an area already allocated with + * ebuf_adjust. The length is not updated, but the pointer is. + */ + +#define ebuf_put_u8(eb,b) *((eb)->eb_ptr++) = (b) +#define ebuf_put_u16_be(eb,w) ebuf_put_u8(eb,((w) >> 8) & 0xFF) ; \ + ebuf_put_u8(eb,((w) & 0xFF)) + +#define ebuf_put_u32_be(eb,w) ebuf_put_u8(eb,((w) >> 24) & 0xFF) ; \ + ebuf_put_u8(eb,((w) >> 16) & 0xFF) ; \ + ebuf_put_u8(eb,((w) >> 8) & 0xFF) ; \ + ebuf_put_u8(eb,((w) & 0xFF)) + +#define ebuf_put_bytes(eb,b,l) memcpy((buf)->eb_ptr,(b),(l)) ; (buf)->eb_ptr += (l) + +#define ebuf_srcaddr(eb) &((eb)->eb_data[6]) +#define ebuf_destaddr(eb) &((eb)->eb_data[0]) + +/* return next byte from the ebuf, and advance pointer */ + +#define ebuf_skip(eb,amt) (eb)->eb_length -= (amt); (eb)->eb_ptr += (amt) + +#define ebuf_get_u8(eb,v) (eb)->eb_length--; \ + v = (*((eb)->eb_ptr++)) + +/* return next u16 from the ebuf, big-endian */ + +#define ebuf_get_u16_be(eb,v) (eb)->eb_ptr+=2; \ + (eb)->eb_length-=2; \ + v = ( ((uint16_t)*((eb)->eb_ptr-1)) | \ + (((uint16_t)*((eb)->eb_ptr-2)) << 8) ) + +/* return next u32 from the ebuf, big-endian */ + +#define ebuf_get_u32_be(eb,v) (eb)->eb_ptr+=4; \ + (eb)->eb_length-=4; \ + v = ( ((uint32_t)*((eb)->eb_ptr-1)) | \ + (((uint32_t)*((eb)->eb_ptr-2)) << 8) | \ + (((uint32_t)*((eb)->eb_ptr-3)) << 16) | \ + (((uint32_t)*((eb)->eb_ptr-4)) << 24) ) + +#define ebuf_get_bytes(eb,b,l) memcpy((b),(buf)->eb_ptr,(l)) ; (eb)->eb_ptr += (l) ; (eb)->eb_length -= (l) + + diff --git a/cfe/cfe/net/net_ether.c b/cfe/cfe/net/net_ether.c new file mode 100644 index 0000000..0dec6e8 --- /dev/null +++ b/cfe/cfe/net/net_ether.c @@ -0,0 +1,705 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Ethernet Datalink File: net_ether.c + * + * This module provides a simple datalink (LLC1) interface + * capable of demultiplexing standard DIX-style Ethernet packets. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define ETH_MAX_PORTS 4 +#define ETH_MAX_BUFFERS 8 + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef struct ether_port_s { + int ep_dev; + uint8_t ep_proto[8]; + int ep_ptype; + int ep_mtu; + int (*ep_rxcallback)(ebuf_t *buf,void *ref); + void *ep_ref; +} ether_port_t; + +struct ether_info_s { + ether_port_t *eth_ports; + queue_t eth_freelist; + uint8_t eth_hwaddr[6]; + int eth_devhandle; + ebuf_t *eth_bufpool; +}; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +const uint8_t eth_broadcast[ENET_ADDR_LEN] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; + + +/* ********************************************************************* + * eth_open(eth,ptye,pdata,cb) + * + * Open an Ethernet portal. + * + * Input parameters: + * eth - ethernet context + * ptype - protocol type (ETH_PTYPE_xxx) + * pdata - protocol data (two bytes for DIX protocols) + * cb - callback for receive packets + * + * Return value: + * portal number + * or <0 if error occured + ********************************************************************* */ + +int eth_open(ether_info_t *eth,int ptype,char *pdata, + int (*cb)(ebuf_t *buf,void *ref),void *ref) +{ + ether_port_t *p; + int portnum; + + p = eth->eth_ports; + + for (portnum = 0; portnum < ETH_MAX_PORTS; portnum++,p++) { + if (p->ep_rxcallback == NULL) break; + } + + if (portnum == ETH_MAX_PORTS) { + return CFE_ERR_NOHANDLES; /* no ports left */ + } + + switch (ptype) { + case ETH_PTYPE_DIX: + p->ep_proto[0] = pdata[0]; + p->ep_proto[1] = pdata[1]; + p->ep_mtu = ENET_MAX_PKT - ENET_DIX_HEADER; + break; + + case ETH_PTYPE_802SAP: + case ETH_PTYPE_802SNAP: + default: + /* + * we only support DIX etypes right now. If we ever want to support + * non-IP stacks (unlikely) this will need to change. + */ + return CFE_ERR_UNSUPPORTED; + } + + p->ep_ptype = ptype; + p->ep_rxcallback = cb; + p->ep_dev = eth->eth_devhandle; + p->ep_ref = ref; + + return portnum; +} + + +/* ********************************************************************* + * eth_close(eth,port) + * + * Close an Ethernet portal, freeing resources allocated to it. + * + * Input parameters: + * eth - ethernet context + * port - portal number + * + * Return value: + * nothing + ********************************************************************* */ + +void eth_close(ether_info_t *eth,int port) +{ + ether_port_t *p = &(eth->eth_ports[port]); + + p->ep_ptype = 0; + p->ep_rxcallback = NULL; + p->ep_dev = 0; + memset(&(p->ep_proto[0]),0,sizeof(p->ep_proto)); +} + + +/* ********************************************************************* + * eth_findport(eth,buf) + * + * Locate the portal associated with a particular Ethernet packet. + * Parse the packet enough to determine if it's addressed + * correctly and to a valid protocol, and then look up the + * corresponding portal. + * + * Input parameters: + * eth - ethernet context + * buf - ethernet buffer to check + * + * Return value: + * eth_port_t structure or NULL if packet should be dropped + ********************************************************************* */ + +static ether_port_t *eth_findport(ether_info_t *eth,ebuf_t *buf) +{ + int idx; + ether_port_t *p; + + /* + * A few pre-flight checks: packets *from* multicast addresses + * are not allowed. + */ + + if (buf->eb_ptr[6] & 1) return NULL; + + /* + * Packets smaller than minimum size are not allowed. + */ + + if (buf->eb_length < 60) return NULL; + + /* + * Packets with bad status are not allowed + */ + + /* XXX if (buf->eb_status != 0) return NULL; */ + + /* + * Okay, scan the port list and find the matching portal. + */ + + for (idx = 0, p = eth->eth_ports; idx < ETH_MAX_PORTS; idx++,p++) { + if (!p->ep_rxcallback) continue; /* port not in use */ + + switch (p->ep_ptype) { + case ETH_PTYPE_DIX: + if ((p->ep_proto[0] == buf->eb_ptr[12]) && + (p->ep_proto[1] == buf->eb_ptr[13])) { + ebuf_skip(buf,ENET_DIX_HEADER); + return p; + } + break; + case ETH_PTYPE_802SAP: + case ETH_PTYPE_802SNAP: + default: + break; + } + } + + return NULL; +} + +/* ********************************************************************* + * eth_poll(eth) + * + * Poll devices and process inbound packets. If new packets arrive, + * call the appropriate callback routine. + * + * Input parameters: + * eth - ethernet context + * + * Return value: + * nothing + ********************************************************************* */ + +void eth_poll(ether_info_t *eth) +{ + ebuf_t *buf; + ether_port_t *p; + int res; + + /* XXX should this loop until all packets are processed? */ + + /* + * If no packets, just get out now + */ + + if (cfe_inpstat(eth->eth_devhandle) == 0) return; + + /* + * get a packet from the free list + */ + + buf = (ebuf_t *) q_deqnext(&(eth->eth_freelist)); + if (!buf) return; + + /* + * Receive network data into the packet buffer + */ + + ebuf_init_rx(buf); + res = cfe_read(eth->eth_devhandle,buf->eb_ptr,ENET_MAX_PKT); + + /* + * if receive error, get out now. + */ + + if (res <= 0) { + q_enqueue(&(eth->eth_freelist),(queue_t *) buf); + return; + } + + /* + * init the rest of the fields in the ebuf + */ + + buf->eb_length = res; + buf->eb_status = 0; + buf->eb_device = eth; + buf->eb_usrdata = 0; + + /* + * Look up the portal to receive the new packet + */ + + p = eth_findport(eth,buf); + + /* + * Call the callback routine if we want to keep this + * buffer. Otherwise, drop it on the floor + */ + + if (p) { + buf->eb_port = p - eth->eth_ports; + res = (*(p->ep_rxcallback))(buf,p->ep_ref); + if (res == ETH_DROP) eth_free(buf); + } + else { + eth_free(buf); + } +} + + +/* ********************************************************************* + * eth_gethwaddr(eth,hwaddr) + * + * Obtain the hardware address of the Ethernet interface. + * + * Input parameters: + * eth - ethernet context + * hwaddr - place to put hardware address - 6 bytes + * + * Return value: + * nothing + ********************************************************************* */ + +void eth_gethwaddr(ether_info_t *eth,uint8_t *hwaddr) +{ + memcpy(hwaddr,eth->eth_hwaddr,ENET_ADDR_LEN); +} + +/* ********************************************************************* + * eth_sethwaddr(eth,hwaddr) + * + * Set the hardware address of the Ethernet interface. + * + * Input parameters: + * eth - ethernet context + * hwaddr - new hardware address - 6 bytes + * + * Return value: + * nothing + ********************************************************************* */ + +void eth_sethwaddr(ether_info_t *eth,uint8_t *hwaddr) +{ + int retlen; + + memcpy(eth->eth_hwaddr,hwaddr,ENET_ADDR_LEN); + cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETHWADDR,&(eth->eth_hwaddr[0]), + sizeof(eth->eth_hwaddr),&retlen,0); + +} + + + +/* ********************************************************************* + * eth_setspeed(eth,speed) + * + * Set the speed of the Ethernet interface. + * + * Input parameters: + * eth - ethernet context + * speed - target speed (or auto for automatic) + * + * Return value: + * nothing + ********************************************************************* */ + +int eth_setspeed(ether_info_t *eth,int speed) +{ + int retlen; + + return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETSPEED, + (uint8_t *) &speed,sizeof(speed),&retlen,0); + +} + +/* ********************************************************************* + * eth_setloopback(eth,loop) + * + * Configure loopback mode options for the Ethernet + * + * Input parameters: + * eth - ethernet context + * loop - loopback mode to set + * + * Return value: + * nothing + ********************************************************************* */ + +int eth_setloopback(ether_info_t *eth,int loop) +{ + int retlen; + + return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_SETLOOPBACK, + (uint8_t *) &loop,sizeof(loop),&retlen,0); + +} + +/* ********************************************************************* + * eth_getspeed(eth,speed) + * + * Get the current setting for the Ethernet speed (note that this + * is the speed we want to achieve, not the current speed) + * + * Input parameters: + * eth - ethernet context + * speed - pointer to int to receive speed + * + * Return value: + * nothing + ********************************************************************* */ + +int eth_getspeed(ether_info_t *eth,int *speed) +{ + int retlen; + + return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_GETSPEED, + (uint8_t *) speed,sizeof(*speed),&retlen,0); + +} + +/* ********************************************************************* + * eth_getloopback(eth,loop) + * + * Read the loopback state of the Ethernet interface + * + * Input parameters: + * eth - ethernet context + * loop - pointer to int to receive loopback state + * + * Return value: + * nothing + ********************************************************************* */ + +int eth_getloopback(ether_info_t *eth,int *loop) +{ + int retlen; + + return cfe_ioctl(eth->eth_devhandle,IOCTL_ETHER_GETLOOPBACK, + (uint8_t *) loop,sizeof(*loop),&retlen,0); + +} + +/* ********************************************************************* + * eth_send(buf,dest) + * + * Transmit a packet. + * + * Input parameters: + * buf - ebuf structure describing packet + * dest - destination hardware address + * + * Return value: + * 0 - no error + * else error code + ********************************************************************* */ + +int eth_send(ebuf_t *buf,uint8_t *dest) +{ + ether_info_t *eth = buf->eb_device; + ether_port_t *p = &(eth->eth_ports[buf->eb_port]); + int res; + + switch (p->ep_ptype) { + case ETH_PTYPE_DIX: + ebuf_seek(buf,-ENET_DIX_HEADER); + ebuf_put_bytes(buf,dest,ENET_ADDR_LEN); + ebuf_put_bytes(buf,eth->eth_hwaddr,ENET_ADDR_LEN); + ebuf_put_bytes(buf,p->ep_proto,2); + /* adjust pointer and add in DIX header length */ + ebuf_prepend(buf,ENET_DIX_HEADER); + break; + case ETH_PTYPE_802SAP: + case ETH_PTYPE_802SNAP: + default: + eth_free(buf); /* should not happen */ + return CFE_ERR_UNSUPPORTED; + } + + res = cfe_write(p->ep_dev,ebuf_ptr(buf),ebuf_length(buf)); + + /* XXX - should we free buffers here? */ + + return res; +} + +/* ********************************************************************* + * eth_alloc(eth,port) + * + * Allocate an Ethernet buffer. Ethernet buffers know what + * ports they are associated with, since we need to reserve + * space for the EThernet header, which might vary in size + * for DIX, 802, etc. + * + * Input parameters: + * eth - ethernet context + * port - portal ID + * + * Return value: + * ebuf, or NULL if no ebufs left + ********************************************************************* */ + +ebuf_t *eth_alloc(ether_info_t *eth,int port) +{ + ebuf_t *buf; + ether_port_t *p = &(eth->eth_ports[port]); + + buf = (ebuf_t *) q_deqnext(&(eth->eth_freelist)); + if (buf == NULL) return NULL; + + buf->eb_status = 0; + buf->eb_port = port; + buf->eb_device = eth; + ebuf_init_tx(buf); + + switch (p->ep_ptype) { + case ETH_PTYPE_NONE: + break; + case ETH_PTYPE_DIX: + ebuf_seek(buf,ENET_DIX_HEADER); + break; + case ETH_PTYPE_802SAP: + case ETH_PTYPE_802SNAP: + default: + /* XXX Other ether types here */ + break; + } + + /* + * 'eb_ptr' points at new data, length is cleared. + * We will add the length back in at send time when the + * ethernet header is filled in. + */ + buf->eb_length = 0; + + return buf; +} + +/* ********************************************************************* + * eth_free(buf) + * + * Free an ebuf. + * + * Input parameters: + * buf - ebuf to free + * + * Return value: + * nothing + ********************************************************************* */ + +void eth_free(ebuf_t *buf) +{ + ether_info_t *eth = buf->eb_device; + + q_enqueue(&(eth->eth_freelist),(queue_t *) buf); +} + + +/* ********************************************************************* + * eth_getmtu(eth,port) + * + * Return the mtu of the specified Ethernet port. The mtu + * is the maximum number of bytes you can put in the buffer, + * excluding the Ethernet header. + * + * Input parameters: + * eth - ethernet context + * port - portal ID + * + * Return value: + * number of bytes + ********************************************************************* */ + + +int eth_getmtu(ether_info_t *eth,int port) +{ + ether_port_t *p = &(eth->eth_ports[port]); + + return p->ep_mtu; +} + + +/* ********************************************************************* + * eth_init(devname) + * + * Create an Ethernet context for a particular Ethernet device. + * + * Input parameters: + * devname - device name for underlying Ethernet driver + * + * Return value: + * ethernet context, or NULL of it could not be created. + ********************************************************************* */ + +ether_info_t *eth_init(char *devname) +{ + int idx; + ebuf_t *buf; + ether_info_t *eth; + int devhandle; + int retlen; + + /* + * Open the device driver + */ + + devhandle = cfe_open(devname); + if (devhandle < 0) return NULL; + + eth = KMALLOC(sizeof(ether_info_t),0); + if (!eth) { + cfe_close(devhandle); + return NULL; + } + + memset(eth,0,sizeof(ether_info_t)); + + /* + * Obtain hardware address + */ + + cfe_ioctl(devhandle,IOCTL_ETHER_GETHWADDR,&(eth->eth_hwaddr[0]), + sizeof(eth->eth_hwaddr),&retlen,0); + + /* + * Allocate portal table + */ + + eth->eth_ports = KMALLOC(ETH_MAX_PORTS*sizeof(ether_port_t),0); + if (!eth->eth_ports) { + cfe_close(devhandle); + KFREE(eth); + return NULL; + } + + memset(eth->eth_ports,0,ETH_MAX_PORTS*sizeof(ether_port_t)); + + /* + * Allocate buffer pool + */ + + eth->eth_bufpool = (ebuf_t *) KMALLOC(sizeof(ebuf_t)*ETH_MAX_BUFFERS,0); + if (!eth->eth_bufpool) { + cfe_close(devhandle); + KFREE(eth->eth_ports); + KFREE(eth); + return NULL; + } + + /* + * Chain buffers onto the free list + */ + + q_init(&(eth->eth_freelist)); + buf = eth->eth_bufpool; + for (idx = 0; idx < ETH_MAX_BUFFERS; idx++) { + q_enqueue(&(eth->eth_freelist),(queue_t *) buf); + buf++; + } + + /* + * Remember the device handle + */ + + eth->eth_devhandle = devhandle; + + return eth; +} + + +/* ********************************************************************* + * eth_uninit(eth) + * + * Close and free up an Ethernet context + * + * Input parameters: + * eth - ethernet context + * + * Return value: + * nothing + ********************************************************************* */ + +void eth_uninit(ether_info_t *eth) +{ + cfe_close(eth->eth_devhandle); + KFREE(eth->eth_bufpool); + KFREE(eth->eth_ports); + KFREE(eth); +} + + diff --git a/cfe/cfe/net/net_ether.h b/cfe/cfe/net/net_ether.h new file mode 100644 index 0000000..a94130b --- /dev/null +++ b/cfe/cfe/net/net_ether.h @@ -0,0 +1,89 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Ethernet protocol demux defns File: net_ether.h + * + * constants and prototypes for the Ethernet datalink + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define ETH_PTYPE_NONE 0 +#define ETH_PTYPE_DIX 1 +#define ETH_PTYPE_802SAP 2 +#define ETH_PTYPE_802SNAP 3 + +#define ETH_KEEP 1 +#define ETH_DROP 0 + +/* ********************************************************************* + * types + ********************************************************************* */ + +typedef struct ether_info_s ether_info_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int eth_open(ether_info_t *eth,int ptype,char *pdata,int (*cb)(ebuf_t *buf,void *ref),void *ref); +void eth_close(ether_info_t *eth,int port); +void eth_poll(ether_info_t *eth); +int eth_send(ebuf_t *buf,uint8_t *dest); +ebuf_t *eth_alloc(ether_info_t *eth,int port); +void eth_free(ebuf_t *buf); +ether_info_t *eth_init(char *devname); +void eth_uninit(ether_info_t *eth); +int eth_getmtu(ether_info_t *,int port); +void eth_gethwaddr(ether_info_t *,uint8_t *hwaddr); +void eth_sethwaddr(ether_info_t *,uint8_t *hwaddr); +int eth_getspeed(ether_info_t *,int *speed); +int eth_setspeed(ether_info_t *,int speed); +int eth_getloopback(ether_info_t *,int *loop); +int eth_setloopback(ether_info_t *,int loop); +extern const uint8_t eth_broadcast[ENET_ADDR_LEN]; + + + diff --git a/cfe/cfe/net/net_icmp.c b/cfe/cfe/net/net_icmp.c new file mode 100644 index 0000000..e98bc87 --- /dev/null +++ b/cfe/cfe/net/net_icmp.c @@ -0,0 +1,312 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * ICMP Protocol File: net_icmp.c + * + * This module implements portions of the ICMP protocol. Note + * that it is not a complete implementation, just enough to + * generate and respond to ICMP echo requests. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_ip.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define ICMP_CODE_ECHO 0 +#define ICMP_TYPE_ECHOREPLY 0 +#define ICMP_TYPE_ECHOREQ 8 + +#define ICMPMSG(type,code) (((type)<<8)|(code)) + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +struct icmp_info_s { + ip_info_t *icmp_ipinfo; + queue_t icmp_echoreplies; + int icmp_maxreplies; +}; + +/* ********************************************************************* + * ICMP_RX_CALLBACK(ref,buf,dst,src) + * + * This routine is called by the IP layer when we receive + * ICMP protocol messages. + * + * Input parameters: + * ref - reference data (an icmp_info_t) + * buf - the ebuf containing the buffer + * dst - destination IP address (us, usually) + * src - source IP address + * + * Return value: + * ETH_KEEP to keep packet, ETH_DROP to cause packet to be freed + ********************************************************************* */ + +static int icmp_rx_callback(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src) +{ + icmp_info_t *icmp = (icmp_info_t *)ref; + ip_info_t *ipi = icmp->icmp_ipinfo; + uint16_t imsg; + uint16_t cksum; + ebuf_t *txbuf; + uint8_t *icmphdr; + int res; + + imsg = ICMPMSG(buf->eb_ptr[0],buf->eb_ptr[1]); + + res = ETH_DROP; /* assume we're dropping the pkt */ + + switch (imsg) { + case ICMPMSG(ICMP_TYPE_ECHOREQ,ICMP_CODE_ECHO): + txbuf = _ip_alloc(ipi); + if (txbuf) { + /* Construct reply from the original packet. */ + icmphdr = txbuf->eb_ptr; + ebuf_append_bytes(txbuf,buf->eb_ptr,buf->eb_length); + icmphdr[0] = ICMP_TYPE_ECHOREPLY; + icmphdr[1] = ICMP_CODE_ECHO; + icmphdr[2] = 0; icmphdr[3] = 0; + cksum = ~ip_chksum(0,icmphdr,ebuf_length(txbuf)); + icmphdr[2] = (cksum >> 8) & 0xFF; + icmphdr[3] = (cksum & 0xFF); + if (_ip_send(ipi,txbuf,src,IPPROTO_ICMP) < 0) { + _ip_free(ipi,txbuf); + } + } + break; + + case ICMPMSG(ICMP_TYPE_ECHOREPLY,ICMP_CODE_ECHO): + if (q_count(&(icmp->icmp_echoreplies)) < icmp->icmp_maxreplies) { + /* We're keeping this packet, put it on the queue and don't + free it in the driver. */ + q_enqueue(&(icmp->icmp_echoreplies),(queue_t *) buf); + res = ETH_KEEP; + } + break; + + default: + res = ETH_DROP; + } + + return res; +} + + +/* ********************************************************************* + * _ICMP_INIT(ipi) + * + * Initialize the ICMP layer. + * + * Input parameters: + * ipi - ipinfo structure of IP layer to attach to + * + * Return value: + * icmp_info_t structure or NULL if error occurs + ********************************************************************* */ + +icmp_info_t *_icmp_init(ip_info_t *ipi) +{ + icmp_info_t *icmp; + + icmp = (icmp_info_t *) KMALLOC(sizeof(icmp_info_t),0); + if (!icmp) return NULL; + + icmp->icmp_ipinfo = ipi; + q_init(&(icmp->icmp_echoreplies)); + icmp->icmp_maxreplies = 0; + + _ip_register(ipi,IPPROTO_ICMP,icmp_rx_callback,icmp); + + return icmp; +} + +/* ********************************************************************* + * _ICMP_UNINIT(icmp) + * + * Un-initialize the ICMP layer. + * + * Input parameters: + * icmp - icmp_info_t structure + * + * Return value: + * nothing + ********************************************************************* */ + +void _icmp_uninit(icmp_info_t *icmp) +{ + _ip_deregister(icmp->icmp_ipinfo,IPPROTO_ICMP); + + KFREE(icmp); +} + + +/* ********************************************************************* + * _ICMP_PING(icmp,dest,seq,len) + * + * Transmit an ICMP echo request and wait for a reply. + * + * Input parameters: + * icmp - icmp_info_t structure + * dest - destination IP address + * seq - sequence number for ICMP packet + * len - length of data portion of ICMP packet + * + * Return value: + * <0 = error + * 0 = timeout + * >0 = reply received + ********************************************************************* */ + +int _icmp_ping(icmp_info_t *icmp,uint8_t *dest,int seq,int len) +{ + ebuf_t *buf; + int64_t timer; + uint16_t cksum; + uint8_t *icmphdr; + uint16_t id; + int idx; + int result = 0; + + /* + * Get an ebuf + */ + + buf = _ip_alloc(icmp->icmp_ipinfo); + if (buf == NULL) return -1; + + /* + * Remember where the ICMP header is going to be so we can + * calculate the checksum later. + */ + + icmphdr = buf->eb_ptr; + + id = (uint16_t) cfe_ticks; + + /* + * Construct the ICMP header and data portion. + */ + + ebuf_append_u8(buf,8); /* echo message */ + ebuf_append_u8(buf,0); /* code = 0 */ + ebuf_append_u16_be(buf,0); /* empty checksum for now */ + ebuf_append_u16_be(buf,id); /* packet ID */ + ebuf_append_u16_be(buf,((uint16_t)seq)); /* sequence # */ + + for (idx = 0; idx < len; idx++) { + ebuf_append_u8(buf,((idx+0x40)&0xFF)); /* data */ + } + + /* + * Calculate and install the checksum + */ + + cksum = ~ip_chksum(0,icmphdr,ebuf_length(buf)); + icmphdr[2] = (cksum >> 8) & 0xFF; + icmphdr[3] = (cksum & 0xFF); + + /* + * Transmit the ICMP echo + */ + + icmp->icmp_maxreplies = 1; /* allow ICMP replies */ + _ip_send(icmp->icmp_ipinfo,buf,dest,IPPROTO_ICMP); + buf = NULL; + + /* + * Wait for a reply + */ + + TIMER_SET(timer,2*CFE_HZ); + + while (!TIMER_EXPIRED(timer)) { + + POLL(); + buf = (ebuf_t *) q_deqnext(&(icmp->icmp_echoreplies)); + + /* If we get a packet, make sure it matches. */ + + if (buf) { + uint16_t rxid,rxseq; + + cksum = ip_chksum(0,buf->eb_ptr,ebuf_length(buf)); + if (cksum == 0xFFFF) { + ebuf_skip(buf,2); + ebuf_skip(buf,2); /* skip checksum */ + ebuf_get_u16_be(buf,rxid); + ebuf_get_u16_be(buf,rxseq); + + if ((id == rxid) && ((uint16_t) seq == rxseq)) { + result = 1; + break; + } + } + _ip_free(icmp->icmp_ipinfo,buf); + } + } + + /* + * Don't accept any more replies. + */ + + icmp->icmp_maxreplies = 0; /* allow ICMP replies */ + + if (buf) _ip_free(icmp->icmp_ipinfo,buf); + + return result; + +} diff --git a/cfe/cfe/net/net_ip.c b/cfe/cfe/net/net_ip.c new file mode 100755 index 0000000..86303e2 --- /dev/null +++ b/cfe/cfe/net/net_ip.c @@ -0,0 +1,722 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Internet Protocol File: net_ip.c + * + * This module implements the IP layer (RFC791) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_ip.h" +#include "net_ip_internal.h" + +#include "cfe_error.h" + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + +static int ip_rx_callback(ebuf_t *buf,void *ref); + +/* ********************************************************************* + * _ip_alloc(ipi) + * + * Allocate an ebuf and reserve space for the IP header in it. + * + * Input parameters: + * ipi - IP stack information + * + * Return value: + * ebuf - an ebuf, or NULL if there are none left + ********************************************************************* */ + +ebuf_t *_ip_alloc(ip_info_t *ipi) +{ + ebuf_t *buf; + + buf = eth_alloc(ipi->eth_info,ipi->ip_port); + + if (buf == NULL) return buf; + + ebuf_seek(buf,IPHDR_LENGTH); + ebuf_setlength(buf,0); + + return buf; +} + + +/* ********************************************************************* + * ip_chksum(initcksum,ptr,len) + * + * Do an IP checksum for the specified buffer. You can pass + * an initial checksum if you're continuing a previous checksum + * calculation, such as for UDP headers and pseudoheaders. + * + * Input parameters: + * initcksum - initial checksum (usually zero) + * ptr - pointer to buffer to checksum + * len - length of data in bytes + * + * Return value: + * checksum (16 bits) + ********************************************************************* */ + +uint16_t ip_chksum(uint16_t initcksum,uint8_t *ptr,int len) +{ + unsigned int cksum; + int idx; + int odd; + + cksum = (unsigned int) initcksum; + + odd = len & 1; + len -= odd; + + for (idx = 0; idx < len; idx += 2) { + cksum += ((unsigned long) ptr[idx] << 8) + ((unsigned long) ptr[idx+1]); + } + + if (odd) { /* buffer is odd length */ + cksum += ((unsigned long) ptr[idx] << 8); + } + + /* + * Fold in the carries + */ + + while (cksum >> 16) { + cksum = (cksum & 0xFFFF) + (cksum >> 16); + } + + return cksum; +} + + +/* ********************************************************************* + * _ip_send(ipi,buf,destaddr,proto) + * + * Send an IP datagram. We only support non-fragmented datagrams + * at this time. + * + * Input parameters: + * ipi - IP stack information + * buf - an ebuf + * destaddr - destination IP address + * proto - IP protocol number + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _ip_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *destaddr,uint8_t proto) +{ + uint16_t cksum; + uint8_t masksrc[IP_ADDR_LEN]; + uint8_t maskdest[IP_ADDR_LEN]; + int pktlen; + uint8_t *ptr; + + /* Move to the beginning of the IP hdeader */ + + ebuf_seek(buf,-IPHDR_LENGTH); + + pktlen = ebuf_length(buf) + IPHDR_LENGTH; + + ipi->ip_id++; + + /* Insert the IP header */ + + ebuf_put_u8(buf,IPHDR_VER_4 | IPHDR_LEN_20); + ebuf_put_u8(buf,IPHDR_TOS_DEFAULT); + ebuf_put_u16_be(buf,pktlen); + ebuf_put_u16_be(buf,ipi->ip_id); + ebuf_put_u16_be(buf,0); + ebuf_put_u8(buf,IPHDR_TTL_DEFAULT); + ebuf_put_u8(buf,proto); + ebuf_put_u16_be(buf,0); /* checksum */ + ebuf_put_bytes(buf,ipi->net_info.ip_addr,IP_ADDR_LEN); + ebuf_put_bytes(buf,destaddr,IP_ADDR_LEN); + + /* adjust pointer and add in the header length */ + + ebuf_prepend(buf,IPHDR_LENGTH); + + /* Checksum the header */ + + ptr = ebuf_ptr(buf); + cksum = ip_chksum(0,ptr,IPHDR_LENGTH); + cksum = ~cksum; + ptr[10] = (cksum >> 8) & 0xFF; + ptr[11] = (cksum >> 0) & 0xFF; + + /* + * If sending to the IP broadcast address, + * send to local broadcast. + */ + + if (ip_addrisbcast(destaddr)) { + eth_send(buf,(uint8_t *) eth_broadcast); + eth_free(buf); + return 0; + } + + /* + * If the mask has not been set, don't try to + * determine if we should use the gateway or not. + */ + + if (ip_addriszero(ipi->net_info.ip_netmask)) { + return _arp_lookup_and_send(ipi,buf,destaddr); + } + + /* + * Compute (dest-addr & netmask) and (my-addr & netmask) + */ + + ip_mask(masksrc,destaddr,ipi->net_info.ip_netmask); + ip_mask(maskdest,ipi->net_info.ip_addr,ipi->net_info.ip_netmask); + + /* + * if destination and my address are on the same subnet, + * send the packet directly. Otherwise, send via + * the gateway. + */ + + if (ip_compareaddr(masksrc,maskdest) == 0) { + return _arp_lookup_and_send(ipi,buf,destaddr); + } + else { + /* if no gw configured, drop packet */ + if (ip_addriszero(ipi->net_info.ip_gateway)) { + eth_free(buf); /* silently drop */ + return 0; + } + else { + return _arp_lookup_and_send(ipi,buf,ipi->net_info.ip_gateway); + } + } + +} + + +/* ********************************************************************* + * ip_rx_callback(buf,ref) + * + * Receive callback for IP packets. This routine is called + * by the Ethernet datalink. We look up a suitable protocol + * handler and pass the packet off. + * + * Input parameters: + * buf - ebuf we received + * ref - reference data from the ethernet datalink + * + * Return value: + * ETH_KEEP to keep the packet + * ETH_DROP to drop the packet + ********************************************************************* */ + +static int ip_rx_callback(ebuf_t *buf,void *ref) +{ + ip_info_t *ipi = ref; + uint8_t tmp; + int hdrlen; + uint8_t *hdr; + uint16_t origchksum; + uint16_t calcchksum; + uint16_t length; + uint16_t tmp16; + uint8_t proto; + uint8_t srcip[IP_ADDR_LEN]; + uint8_t dstip[IP_ADDR_LEN]; + ip_protodisp_t *pdisp; + int res; + int idx; + + hdr = ebuf_ptr(buf); /* save current posn */ + + ebuf_get_u8(buf,tmp); /* version and header length */ + + /* + * Check IP version + */ + + if ((tmp & 0xF0) != IPHDR_VER_4) { + goto drop; /* not IPV4 */ + } + hdrlen = (tmp & 0x0F) * 4; + + /* + * Check header size + */ + + if (hdrlen < IPHDR_LENGTH) { + goto drop; /* header < 20 bytes */ + } + + /* + * Check the checksum + */ + origchksum = ((uint16_t) hdr[10] << 8) | (uint16_t) hdr[11]; + hdr[10] = hdr[11] = 0; + calcchksum = ~ip_chksum(0,hdr,hdrlen); + if (calcchksum != origchksum) { + goto drop; + } + + /* + * Okay, now go back and check other fields. + */ + + ebuf_skip(buf,1); /* skip TOS field */ + + ebuf_get_u16_be(buf,length); + ebuf_skip(buf,2); /* skip ID field */ + + ebuf_get_u16_be(buf,tmp16); /* get Fragment Offset field */ + + /* + * If the fragment offset field is nonzero, or the + * "more fragments" bit is set, then this is a packet + * fragment. Our trivial IP implementation does not + * deal with fragments, so drop the packets. + */ + if ((tmp16 & (IPHDR_FRAGOFFSET | IPHDR_MOREFRAGMENTS)) != 0) { + goto drop; /* packet is fragmented */ + } + + ebuf_skip(buf,1); /* skip TTL */ + ebuf_get_u8(buf,proto); /* get protocol */ + ebuf_skip(buf,2); /* skip checksum */ + + ebuf_get_bytes(buf,srcip,IP_ADDR_LEN); + ebuf_get_bytes(buf,dstip,IP_ADDR_LEN); + + ebuf_skip(buf,hdrlen-IPHDR_LENGTH); /* skip rest of header */ + + ebuf_setlength(buf,length-hdrlen); /* set length to just data portion */ + + /* + * If our address is not set, let anybody in. We need this to + * properly pass up DHCP replies that get forwarde through routers. + * Otherwise, only let in matching addresses or broadcasts. + */ + + if (!ip_addriszero(ipi->net_info.ip_addr)) { + if ((ip_compareaddr(dstip,ipi->net_info.ip_addr) != 0) && + !(ip_addrisbcast(dstip))) { + goto drop; /* not for us */ + } + } + + /* + * ebuf's pointer now starts at beginning of protocol data + */ + + /* + * Find matching protocol dispatch + */ + + pdisp = ipi->ip_protocols; + res = ETH_DROP; + for (idx = 0; idx < IP_MAX_PROTOCOLS; idx++) { + if (pdisp->cb && (pdisp->protocol == proto)) { + res = (*(pdisp->cb))(pdisp->ref,buf,dstip,srcip); + break; + } + pdisp++; + } + + + return res; + +drop: + return ETH_DROP; +} + + +/* ********************************************************************* + * _ip_init(eth) + * + * Initialize the IP layer, attaching it to an underlying Ethernet + * datalink interface. + * + * Input parameters: + * eth - Ethernet datalink information + * + * Return value: + * ip_info pointer (IP stack information) or NULL if error + ********************************************************************* */ + +ip_info_t *_ip_init(ether_info_t *eth) +{ + ip_info_t *ipi; + int8_t ipproto[2]; + + /* + * Allocate IP stack info + */ + + ipi = KMALLOC(sizeof(ip_info_t),0); + if (ipi == NULL) return NULL; + + memset(ipi,0,sizeof(ip_info_t)); + + ipi->eth_info = eth; + + /* + * Initialize ARP + */ + + if (_arp_init(ipi) < 0) { + KFREE(ipi); + return NULL; + } + + /* + * Open the Ethernet portal for IP packets + */ + + ipproto[0] = (PROTOSPACE_IP >> 8) & 0xFF; ipproto[1] = PROTOSPACE_IP & 0xFF; + ipi->ip_port = eth_open(ipi->eth_info,ETH_PTYPE_DIX,ipproto,ip_rx_callback,ipi); + + if (ipi->ip_port < 0) { + _arp_uninit(ipi); + KFREE(ipi); + return NULL; + } + + return ipi; +} + + +/* ********************************************************************* + * _ip_uninit(ipi) + * + * Un-initialize the IP layer, freeing resources + * + * Input parameters: + * ipi - IP stack information + * + * Return value: + * nothing + ********************************************************************* */ + +void _ip_uninit(ip_info_t *ipi) +{ + /* + * Close the IP portal + */ + + eth_close(ipi->eth_info,ipi->ip_port); + + /* + * Turn off the ARP layer. + */ + + _arp_uninit(ipi); + + + /* + * free strings containing the domain and host names + */ + + if (ipi->net_info.ip_domain) { + KFREE(ipi->net_info.ip_domain); + } + + if (ipi->net_info.ip_hostname) { + KFREE(ipi->net_info.ip_hostname); + } + + /* + * Free the stack information + */ + + KFREE(ipi); +} + + +/* ********************************************************************* + * _ip_timer_tick(ipi) + * + * Called once per second while the IP stack is active. + * + * Input parameters: + * ipi - ip stack information + * + * Return value: + * nothing + ********************************************************************* */ + + +void _ip_timer_tick(ip_info_t *ipi) +{ + _arp_timer_tick(ipi); +} + + +/* ********************************************************************* + * _ip_free(ipi,buf) + * + * Free an ebuf allocated via _ip_alloc + * + * Input parameters: + * ipi - IP stack information + * buf - ebuf to free + * + * Return value: + * nothing + ********************************************************************* */ + +void _ip_free(ip_info_t *ipi,ebuf_t *buf) +{ + eth_free(buf); +} + +/* ********************************************************************* + * _ip_getaddr(ipi,buf) + * + * Return our IP address (is this used?) + * + * Input parameters: + * ipi - IP stack information + * buf - pointer to 4-byte buffer to receive IP address + * + * Return value: + * nothing + ********************************************************************* */ + +void _ip_getaddr(ip_info_t *ipi,uint8_t *buf) +{ + memcpy(buf,ipi->net_info.ip_addr,IP_ADDR_LEN); +} + +/* ********************************************************************* + * _ip_getparam(ipi,param) + * + * Return the value of an IP parameter (address, netmask, etc.). + * The return value may need to be coerced if it's not normally + * a uint8_t* pointer. + * + * Input parameters: + * ipi - IP stack information + * param - parameter number + * + * Return value: + * parameter value, or NULL if the parameter is invalid or + * not set. + ********************************************************************* */ + +uint8_t *_ip_getparam(ip_info_t *ipinfo,int param) +{ + uint8_t *ret = NULL; + + switch (param) { + case NET_IPADDR: + ret = ipinfo->net_info.ip_addr; + break; + case NET_NETMASK: + ret = ipinfo->net_info.ip_netmask; + break; + case NET_GATEWAY: + ret = ipinfo->net_info.ip_gateway; + break; + case NET_NAMESERVER: + ret = ipinfo->net_info.ip_nameserver; + break; + case NET_HWADDR: + ret = ipinfo->arp_hwaddr; + break; + case NET_DOMAIN: + ret = ipinfo->net_info.ip_domain; + break; + case NET_HOSTNAME: + ret = ipinfo->net_info.ip_hostname; + break; + case NET_SPEED: + return NULL; + break; + case NET_LOOPBACK: + return NULL; + break; + } + + return ret; +} + +/* ********************************************************************* + * _ip_getparam(ipi,param,value) + * + * Set the value of an IP parameter (address, netmask, etc.). + * The value may need to be coerced if it's not normally + * a uint8_t* pointer. + * + * Input parameters: + * ipi - IP stack information + * param - parameter number + * value - parameter's new value + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int _ip_setparam(ip_info_t *ipinfo,int param,uint8_t *ptr) +{ + int res = -1; + + switch (param) { + case NET_IPADDR: + memcpy(ipinfo->net_info.ip_addr,ptr,IP_ADDR_LEN); + _arp_send_gratuitous(ipinfo); + res = 0; + break; + case NET_NETMASK: + memcpy(ipinfo->net_info.ip_netmask,ptr,IP_ADDR_LEN); + res = 0; + break; + case NET_GATEWAY: + memcpy(ipinfo->net_info.ip_gateway,ptr,IP_ADDR_LEN); + res = 0; + break; + case NET_NAMESERVER: + memcpy(ipinfo->net_info.ip_nameserver,ptr,IP_ADDR_LEN); + res = 0; + break; + case NET_DOMAIN: + if (ipinfo->net_info.ip_domain) { + KFREE(ipinfo->net_info.ip_domain); + ipinfo->net_info.ip_domain = NULL; + } + if (ptr) ipinfo->net_info.ip_domain = (uint8_t*)strdup((char *) ptr); + break; + case NET_HOSTNAME: + if (ipinfo->net_info.ip_hostname) { + KFREE(ipinfo->net_info.ip_hostname); + ipinfo->net_info.ip_hostname = NULL; + } + if (ptr) ipinfo->net_info.ip_hostname = (uint8_t*)strdup((char *) ptr); + break; + case NET_HWADDR: + memcpy(ipinfo->arp_hwaddr,ptr,ENET_ADDR_LEN); + eth_sethwaddr(ipinfo->eth_info,ptr); + res = 0; + break; + case NET_SPEED: + res = eth_setspeed(ipinfo->eth_info,*(int *)ptr); + break; + case NET_LOOPBACK: + res = eth_setloopback(ipinfo->eth_info,*(int *)ptr); + break; + } + + return res; +} + +/* ********************************************************************* + * _ip_register(ipinfo,proto,cb) + * + * Register a protocol handler with the IP layer. IP client + * protocols such as UDP, ICMP, etc. call this to register their + * callbacks. + * + * Input parameters: + * ipinfo - IP stack information + * proto - IP protocol number + * cb - callback routine to register + * + * Return value: + * nothing + ********************************************************************* */ + +void _ip_register(ip_info_t *ipinfo, + int proto, + int (*cb)(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src),void *ref) +{ + int idx; + + for (idx = 0; idx < IP_MAX_PROTOCOLS; idx++) { + if (ipinfo->ip_protocols[idx].cb == NULL) break; + } + + if (idx == IP_MAX_PROTOCOLS) return; + + ipinfo->ip_protocols[idx].protocol = (uint8_t) proto; + ipinfo->ip_protocols[idx].cb = cb; + ipinfo->ip_protocols[idx].ref = ref; +} + + +/* ********************************************************************* + * _ip_deregister(ipinfo,proto) + * + * Deregister an IP protocol. + * + * Input parameters: + * ipinfo - IP stack information + * proto - protocol number + * + * Return value: + * nothing + ********************************************************************* */ + +void _ip_deregister(ip_info_t *ipinfo,int proto) +{ + int idx; + + for (idx = 0; idx < IP_MAX_PROTOCOLS; idx++) { + if (ipinfo->ip_protocols[idx].protocol == (uint8_t) proto) { + ipinfo->ip_protocols[idx].protocol = 0; + ipinfo->ip_protocols[idx].ref = 0; + ipinfo->ip_protocols[idx].cb = NULL; + } + } +} + diff --git a/cfe/cfe/net/net_ip.h b/cfe/cfe/net/net_ip.h new file mode 100755 index 0000000..7b1b4be --- /dev/null +++ b/cfe/cfe/net/net_ip.h @@ -0,0 +1,159 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IP Protocol Definitions File: net_ip.h + * + * This is the main include file for the CFE network stack. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +/* ********************************************************************* + * Global info + ********************************************************************* */ + +#ifndef IP_ADDR_LEN +#define IP_ADDR_LEN 4 +#endif + +typedef struct ip_info_s ip_info_t; + +typedef struct net_info_s { + /* Configuration info for IP interface */ + uint8_t ip_addr[IP_ADDR_LEN]; + uint8_t ip_netmask[IP_ADDR_LEN]; + uint8_t ip_gateway[IP_ADDR_LEN]; + uint8_t ip_nameserver[IP_ADDR_LEN]; + uint8_t *ip_domain; + uint8_t *ip_hostname; +} net_info_t; + +/* ********************************************************************* + * ARP Information + ********************************************************************* */ + +int _arp_lookup_and_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *dest); +void _arp_timer_tick(ip_info_t *ipi); +int _arp_init(ip_info_t *ipi); +void _arp_uninit(ip_info_t *ipi); +void _arp_add(ip_info_t *ipi,uint8_t *destip,uint8_t *desthw); +void _arp_send_gratuitous(ip_info_t *ipi); +uint8_t *_arp_lookup(ip_info_t *ipi,uint8_t *destip); +int _arp_enumerate(ip_info_t *ipi,int entrynum,uint8_t *ipaddr,uint8_t *hwaddr); +int _arp_delete(ip_info_t *ipi,uint8_t *ipaddr); + + +/* ********************************************************************* + * IP protocol + ********************************************************************* */ + + +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#define IPPROTO_ICMP 1 + +int _ip_send(ip_info_t *ipi,ebuf_t *buf,uint8_t *destaddr,uint8_t proto); +ip_info_t *_ip_init(ether_info_t *); +void _ip_timer_tick(ip_info_t *ipi); +void _ip_uninit(ip_info_t *ipi); +ebuf_t *_ip_alloc(ip_info_t *ipi); +void _ip_free(ip_info_t *ipi,ebuf_t *buf); +void _ip_getaddr(ip_info_t *ipi,uint8_t *buf); +uint8_t *_ip_getparam(ip_info_t *ipinfo,int param); +int _ip_setparam(ip_info_t *ipinfo,int param,uint8_t *ptr); +uint16_t ip_chksum(uint16_t initcksum,uint8_t *ptr,int len); +void _ip_deregister(ip_info_t *ipinfo,int proto); +void _ip_register(ip_info_t *ipinfo, + int proto, + int (*cb)(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src),void *ref); + + +#define ip_mask(dest,a,b) (dest)[0] = (a)[0] & (b)[0] ; \ + (dest)[1] = (a)[1] & (b)[1] ; \ + (dest)[2] = (a)[2] & (b)[2] ; \ + (dest)[3] = (a)[3] & (b)[3] + +#define ip_compareaddr(a,b) memcmp(a,b,IP_ADDR_LEN) + +#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0) +#define ip_addrisbcast(a) ((a[0] == 0xFF) && (a[1] == 0xFF) && (a[2] == 0xFF) && (a[3] == 0xFF)) + +#ifndef NET_IPADDR +#define NET_IPADDR 0 +#define NET_NETMASK 1 +#define NET_GATEWAY 2 +#define NET_NAMESERVER 3 +#define NET_HWADDR 4 +#define NET_DOMAIN 5 +#define NET_HOSTNAME 6 +#define NET_SPEED 7 +#define NET_LOOPBACK 8 +#endif + +/* ********************************************************************* + * UDP Protocol + ********************************************************************* */ + +typedef struct udp_info_s udp_info_t; + +int _udp_socket(udp_info_t *info,uint16_t port); +void _udp_close(udp_info_t *info,int s); +int _udp_send(udp_info_t *info,int s,ebuf_t *buf,uint8_t *dest); +udp_info_t *_udp_init(ip_info_t *ipi,void *ref); +void _udp_uninit(udp_info_t *info); +int _udp_bind(udp_info_t *info,int s,uint16_t port); +int _udp_connect(udp_info_t *info,int s,uint16_t port); +ebuf_t *_udp_recv(udp_info_t *info,int s); +ebuf_t *_udp_alloc(udp_info_t *info); +void _udp_free(udp_info_t *info,ebuf_t *buf); + +/* ********************************************************************* + * ICMP protocol + ********************************************************************* */ + +typedef struct icmp_info_s icmp_info_t; + +icmp_info_t *_icmp_init(ip_info_t *ipi); +void _icmp_uninit(icmp_info_t *icmp); + +int _icmp_ping(icmp_info_t *icmp,uint8_t *ipaddr,int seq,int len); + + diff --git a/cfe/cfe/net/net_ip_internal.h b/cfe/cfe/net/net_ip_internal.h new file mode 100644 index 0000000..94401e2 --- /dev/null +++ b/cfe/cfe/net/net_ip_internal.h @@ -0,0 +1,128 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Internal IP structures File: net_ip_internal.h + * + * This module contains non-public IP stack constants, + * structures, and function prototypes. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * ARP Protocol + ********************************************************************* */ + +#define ARP_OPCODE_REQUEST 1 +#define ARP_OPCODE_REPLY 2 + +#define ARP_HWADDRSPACE_ETHERNET 1 + +#define PROTOSPACE_IP 0x0800 +#define PROTOSPACE_ARP 0x0806 + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#define PROTOSPACE_NMRP 0x0912 +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +#define ARP_KEEP_TIMER 60 +#define ARP_QUERY_TIMER 1 +#define ARP_QUERY_RETRIES 4 +#define ARP_TXWAIT_MAX 2 +#define ARP_TABLE_SIZE 8 + +typedef enum { ae_unused, ae_arping, ae_established } arpstate_t; + +typedef struct arpentry_s { + arpstate_t ae_state; + int ae_usage; + int ae_timer; + int ae_retries; + int ae_permanent; + uint8_t ae_ipaddr[IP_ADDR_LEN]; + uint8_t ae_ethaddr[ENET_ADDR_LEN]; + queue_t ae_txqueue; +} arpentry_t; + + +/* ********************************************************************* + * IP Protocol + ********************************************************************* */ + +#define IPHDR_VER_4 0x40 +#define IPHDR_LEN_20 0x05 +#define IPHDR_LENGTH 20 +#define IPHDR_TOS_DEFAULT 0x00 +#define IPHDR_TTL_DEFAULT 100 + +#define IPHDR_RESERVED 0x8000 +#define IPHDR_DONTFRAGMENT 0x4000 +#define IPHDR_MOREFRAGMENTS 0x2000 +#define IPHDR_FRAGOFFSET 0x01FFF + +typedef struct ip_protodisp_s { + uint8_t protocol; + int (*cb)(void *ref,ebuf_t *buf,uint8_t *dst,uint8_t *src); + void *ref; +} ip_protodisp_t; + +#define IP_MAX_PROTOCOLS 4 + + +struct ip_info_s { + net_info_t net_info; + + /* Ethernet info */ + ether_info_t *eth_info; + + /* Info specific to IP */ + uint16_t ip_id; + int ip_port; + + /* IP protocol dispatch table */ + ip_protodisp_t ip_protocols[IP_MAX_PROTOCOLS]; + + /* Info specific to ARP */ + arpentry_t *arp_table; + int arp_port; + uint8_t arp_hwaddr[ENET_ADDR_LEN]; +}; + + diff --git a/cfe/cfe/net/net_nmrp.c b/cfe/cfe/net/net_nmrp.c new file mode 100755 index 0000000..696d04d --- /dev/null +++ b/cfe/cfe/net/net_nmrp.c @@ -0,0 +1,656 @@ +#include "bsp_config.h" + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "cfe_timer.h" + +#include "net_ip.h" +#include "net_ip_internal.h" +#include "net_api.h" + +#include "env_subr.h" + +#if CFG_TCP +#include "net_tcp.h" +#endif + +#include "ui_command.h" + +typedef struct net_ctx_s { + /* Global info */ + int64_t timer; + + /* device name */ + char *devname; + + /* Run-time info for IP interface */ + ip_info_t *ipinfo; + + /* Info for Ethernet interface */ + ether_info_t *ethinfo; + + /* Info specific to UDP */ + udp_info_t *udpinfo; + + /* Info specific to ICMP */ + icmp_info_t *icmpinfo; + +#if CFG_TCP + /* Info specific to TCP */ + tcp_info_t *tcpinfo; +#endif +} net_ctx_t; + + +#pragma pack(1) + +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; + +/* NMRP timeouts */ +enum _nmrp_timeouts_ { + NMRP_TIMEOUT_REQ = 1/2, /* 0.5 sec */ + NMRP_TIMEOUT_LISTEN = 3, /* 3 sec */ + NMRP_TIMEOUT_ACTIVE = 60000, /* 1 minute */ + NMRP_TIMEOUT_CLOSE = 6000, /* 6 sec */ + NMRP_TIMEOUT_ADVERTISE = 500 /* 0.5 sec */ +}; + +enum _nmrp_errors_ { + NMRP_ERR_NONE = 0, + NMRP_ERR_MSG_INVALID_LEN, + NMRP_ERR_MSG_TOO_LONG, + NMRP_ERR_MSG_TOO_MANY_OPT, + NMRP_ERR_MSG_UNKNOWN_OPT, + NMRP_ERR_MSG_INVALID_OPT, + NMRP_ERR_NO_BUF, + NMRP_ERR_GENERAL +}; + +/* NMRP codes */ +enum _nmrp_codes_ { + NMRP_CODE_ADVERTISE = 0x01, + NMRP_CODE_CONF_REQ = 0x02, + NMRP_CODE_CONF_ACK = 0x03, + NMRP_CODE_CLOSE_REQ = 0x04, + NMRP_CODE_CLOSE_ACK = 0x05, + NMRP_CODE_KEEP_ALIVE_REQ = 0x06, + NMRP_CODE_KEEP_ALIVE_ACK = 0x07, + NMRP_CODE_TFTP_UL_REQ = 0x10 +}; + +/* NMRP option types */ +enum _nmrp_option_types_ { + NMRP_OPT_MAGIC_NO = 0x0001, + NMRP_OPT_DEV_IP = 0x0002, + NMRP_OPT_FW_UP = 0x0101 +}; + +typedef enum { + NMRPC_L2_NO_ERROR = 0, + NMRPC_L2_TX_PKT_TOO_LONG, + NMRPC_L2_TX_ETHER_PREPEND_FAIL, + NMRPC_L2_TX_ERROR, + NMRPC_L2_GEN_ERR +} NMRPC_L2_RET_CODE; + +/* NMRP REQ max retries */ +enum _nmrp_req_max_retries_ { + NMRP_MAX_RETRY_CONF = 5, + NMRP_MAX_RETRY_CLOSE = 9999, + NMRP_MAX_RETRY_TFTP_UL = 4 +}; + + +enum _nmrp_state_ { + NMRP_STATE_LISTEN = 0, + NMRP_STATE_CONFIGURE, + NMRP_STATE_TRANSFER, + NMRP_STATE_CLOSE +}; + +#define NMRP_MAX_OPT_PER_MSG (6) +#define ETHER_NMRP (0x0912) + +#define NMRP_HDR_LEN (sizeof(NMRP_MSG) - sizeof(NMRP_OPT)) +#define NMRP_MIN_OPT_LEN (sizeof(NMRP_OPT) - 1) + +#define NMRP_MAGIC_NO "\x4E\x54\x47\x52" +#define NMRP_MAGIC_NO_LEN (sizeof(NMRP_MAGIC_NO) - 1) + +typedef struct { + uint8_t destMAC[6]; + uint8_t srcMAC[6]; + uint16_t etherType; +} ETHER_HDR; + +typedef struct { + uint16_t type; + uint16_t len; + uint8_t value; +} NMRP_OPT; + +typedef struct { + uint16_t reserved; + uint8_t code; + uint8_t id; + uint16_t length; + + NMRP_OPT opt; +} NMRP_MSG; + +typedef struct { + ETHER_HDR etherHdr; + NMRP_MSG nmrpMsg; +} ETHER_NMRP_PKT; + +typedef struct { + uint16_t type; + uint16_t len; + + union { + uint8_t byteVal; + uint16_t wordVal; + uint32_t dwordVal; + const uint8_t *streamVal; + } value; +} NMRP_PARSED_OPT; + +typedef struct { + uint8_t code; + uint8_t id; + uint16_t length; + + int numOptions; + NMRP_PARSED_OPT options[NMRP_MAX_OPT_PER_MSG]; +} NMRP_PARSED_MSG; + +typedef struct { + int reqCode; + const char reqName[32], respName[32]; + + int (* RespParser) (const void *pkt, int pktLen, const BYTE *serverMac, void *userData); +} NMRP_REQ_CUSTOM; + +typedef struct { + + BYTE peerMac[6]; + BYTE myMac[6]; + + DWORD peerIp; + DWORD myIp; + WORD ipId; + + WORD peerPort; + WORD myPort; +} NET_INFO; + +#pragma pack() + +#define MIN_ETHER_NMRP_LEN (sizeof(ETHER_HDR) + NMRP_HDR_LEN) + +#if 0 +#define HTONCS(constWord) ((((constWord) & 0xff00) >> 8) | (((constWord) & 0xff) << 8)) +#define NTOHCS(constWord) HTONCS(constWord) +#define HTONCL(constDword) ((((constDword) & 0xff000000) >> 24) | (((constDword) & 0xff0000) >> 8) | (((constDword) & 0xff00) << 8) | (((constDword) & 0xff) << 24)) +#define NTOHCL(constDword) HTONCL(constDword) +#endif + +#define HTONCS(constWord) constWord +#define NTOHCS(constWord) constWord +#define HTONCL(constDword) constDword +#define NTOHCL(constDword) constDword +/* +#define IS_NMRP_PKT(etherNmrpPkt, pktLen, parsedNmrpMsg, sourceMAC) \ + ((pktLen) > MIN_ETHER_NMRP_LEN && (etherNmrpPkt)->etherHdr.etherType == HTONCS(ETHER_NMRP) && \ + ((sourceMAC) == NULL || memcmp((sourceMAC), (etherNmrpPkt)->etherHdr.srcMAC, 6) == 0) && \ + NMRP_MsgParsing(&(etherNmrpPkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), (parsedNmrpMsg)) == NMRP_ERR_NONE) +*/ + +#define IS_NMRP_PKT(etherNmrpPkt, pktLen, parsedNmrpMsg, sourceMAC) \ + ((pktLen) > MIN_ETHER_NMRP_LEN && (etherNmrpPkt)->etherHdr.etherType == HTONCS(ETHER_NMRP) && \ + ((sourceMAC) == NULL || memcmp((sourceMAC), (etherNmrpPkt)->etherHdr.srcMAC, 6) == 0)) + +static int nmrp_rx_callback(ebuf_t *buf,void *ref); +int NMRP_MsgParsing(const NMRP_MSG *pkt, int pktLen, NMRP_PARSED_MSG *msg); +NMRP_PARSED_OPT *NMRP_MsgGetOpt(NMRP_PARSED_MSG *msg, uint16_t optType); +//int NMRPRequest( const BYTE *serverMac, const BYTE *clientMac, NMRP_REQ_CUSTOM *custom, void *userData); +static int NMRPConfiguring( const BYTE *serverMac, const BYTE *clientMac, DWORD *ipAddr, DWORD *ipSubnetMask, int *fwUpgrade); +static int NMRPConfAckParser(const void *pkt, int pktLen, const BYTE *serverMac, void *userData); +//int NMRPTFTPWaiting(const NET_INFO *netInfo, DWORD *peerIp, WORD *peerPort, WORD *ipId); +int NMRPTFTPWaiting(void); +int NMRPKeepAlive(void); +static int NMRPClosing(void); +static int NMRPSend(NMRP_REQ_CUSTOM *custom); + +int nmrp_server_detected; +int g_nmrp_config_acked; +int g_nmrp_close_acked; +//int g_Listening; +int g_NMRP_State; +extern net_ctx_t *netctx; + +NET_INFO g_NetInfo; +//ebuf_t *g_nmrp_txbuf = NULL; +int g_portal_number; +NMRP_PARSED_MSG g_nmrpMsg; +int g_tftp_upgrade_success; +int g_nmrp_keepalive;//jenny add for fixed NMRP server timeout issue +unsigned char g_received_packet[1600]; + +int gpio_control(int gpio, int value); +extern int32_t _getticks(void); /* return value of CP0 COUNT */ +static unsigned long seed = 1; + +void srand(unsigned long local_seed); +unsigned long rand(void); +int _start_nmrp(void); + +void srand(unsigned long local_seed) +{ + seed = local_seed; +} + +unsigned long rand(void) +{ + + long x, hi, lo, t; + + x = seed; + hi = x / 127773; + lo = x % 127773; + t = 16807 * lo - 2836 * hi; + if (t <= 0) t += 0x7fffffff; + seed = t; + return t; +} + +int _start_nmrp (void) +{ + uint8_t nmrpproto[2]; + + int ret = 0; + int ui_cmd_status; + int fwUpgrade; + int64_t timer; + DWORD ipSubnetMask; + char buf[512]; + unsigned char *pIP, *pMask; + + srand( (unsigned long)_getticks()); + + //net_init("eth0"); + nmrpproto[0] = (PROTOSPACE_NMRP >> 8) & 0xFF; + nmrpproto[1] = (PROTOSPACE_NMRP & 0xFF); + g_tftp_upgrade_success = 0; + g_nmrp_keepalive = 0;//jenny add for timeout + + g_portal_number = eth_open(netctx->ethinfo, ETH_PTYPE_DIX, (char*)nmrpproto, nmrp_rx_callback, NULL); + if(g_portal_number < 0) + { + ret = -1; + goto _clean_and_exit; + } + + eth_gethwaddr(netctx->ethinfo, g_NetInfo.myMac); +//_retry: + g_NMRP_State = NMRP_STATE_LISTEN; + nmrp_server_detected = 0; + TIMER_SET(timer, NMRP_TIMEOUT_LISTEN*CFE_HZ); + while (!TIMER_EXPIRED(timer)) + { + POLL(); + if(nmrp_server_detected) + { + xprintf ("find server.\n"); + break; + } + } + + if(!nmrp_server_detected) + { + ret = -1; + goto _clean_and_exit; + } + + g_nmrp_config_acked = 0; + + if (NMRPConfiguring( g_NetInfo.peerMac, g_NetInfo.myMac, &g_NetInfo.myIp, &ipSubnetMask, &fwUpgrade) == -1) + { + ret = -1; + goto _clean_and_exit; + } + + pIP = (unsigned char *)&g_NetInfo.myIp; + pMask = (unsigned char *)&ipSubnetMask; + + sprintf(buf, "ifconfig eth0 -addr=%u.%u.%u.%u -mask=%u.%u.%u.%u", *(pIP), *(pIP+1), *(pIP+2), *(pIP+3), + *(pMask), *(pMask+1), *(pMask+2), *(pMask+3) ); + ui_docommand(buf); + + +_retry_tftp: + + NMRPTFTPWaiting(); + //eth_close(netctx->ethinfo, g_portal_number); + //g_portal_number = 0; + //net_init("eth0"); + ui_cmd_status = ui_docommand("tftpd nmrp"); + + + sprintf(buf, "ifconfig eth0 -addr=%u.%u.%u.%u -mask=%u.%u.%u.%u", *(pIP), *(pIP+1), *(pIP+2), *(pIP+3), + *(pMask), *(pMask+1), *(pMask+2), *(pMask+3) ); + + ui_docommand(buf); + + //net_init("eth0"); + g_portal_number = eth_open(netctx->ethinfo, ETH_PTYPE_DIX, (char*)nmrpproto, nmrp_rx_callback, NULL); + + if(ui_cmd_status != 0) + { + goto _retry_tftp; + } + + g_nmrp_close_acked = 0; + /* Foxconn modified start, zacker,04/07/2008 */ + /* ui_docommand("nvram erase"); */ + // nvram_unset("restore_defaults"); + // nvram_commit(); + /* Foxconn modified end, zacker,04/07/2008 */ + + NMRPClosing(); + g_tftp_upgrade_success = 1; + // gpio_control(7, 1); //turn off power led + +_clean_and_exit: + + if(g_portal_number > 0) + eth_close(netctx->ethinfo, g_portal_number); + + return ret; +} + +extern void setPowerOnLedOn(void); +static int nmrp_rx_callback(ebuf_t *buf,void *ref) +{ + int pktLen = 0; + NMRP_PARSED_MSG nmrpMsg; + const ETHER_NMRP_PKT *pkt; + unsigned char *p; + + pkt = (const ETHER_NMRP_PKT *)buf->eb_data; + pktLen = buf->eb_length + sizeof(ETHER_HDR) - 4; + + p=(unsigned char *)pkt; + + if(g_NMRP_State == NMRP_STATE_LISTEN) + { + if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_ADVERTISE ) ) + { + if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE) + { + if(NMRP_MsgGetOpt(&nmrpMsg, NMRP_OPT_MAGIC_NO) != NULL) + { + memcpy(g_NetInfo.peerMac, buf->eb_data+6, 6); + g_NMRP_State = NMRP_STATE_CONFIGURE; + nmrp_server_detected = 1; + setPowerOnLedOn(); /* Foxconn added for U12H154, turn on TEST LED */ + } + } + } + } + else if(g_NMRP_State == NMRP_STATE_CONFIGURE) + { + if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_CONF_ACK ) ) + { + memcpy(g_received_packet, pkt, pktLen); + pkt = (const ETHER_NMRP_PKT *)g_received_packet; + if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE) + { + if(NMRPConfAckParser(pkt, pktLen, g_NetInfo.peerMac, &nmrpMsg)) + { + g_nmrpMsg = nmrpMsg; + g_nmrp_config_acked = 1; + g_NMRP_State = NMRP_STATE_TRANSFER; + } + } + } + } + else if(g_NMRP_State == NMRP_STATE_TRANSFER) + { + if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_CLOSE_ACK ) ) + { + if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE) + { + g_NMRP_State =NMRP_STATE_CLOSE; + g_nmrp_close_acked = 1; + } + } + } + + return ETH_DROP; +} + +static int NMRP_OptValParsing(NMRP_PARSED_OPT *optParsed, const uint8_t *value) +{ + int retVal = NMRP_ERR_NONE; + + switch (optParsed->type) { + case NMRP_OPT_MAGIC_NO: /* We require the lenght MUST be correct for the MAGIC-NO option */ + if (optParsed->len != (NMRP_MIN_OPT_LEN + NMRP_MAGIC_NO_LEN) || memcmp(value, NMRP_MAGIC_NO, NMRP_MAGIC_NO_LEN)) + { + retVal = NMRP_ERR_MSG_INVALID_OPT; + } + else + { + optParsed->value.streamVal = value; + } + break; + + case NMRP_OPT_DEV_IP: /* save the value of IP in the byte stream format, the actual IP is streamVal[0].streamVal[1].streamVal[2].streamVal[3]. */ + //if ( optParsed->len != (NMRP_MIN_OPT_LEN + 8) || !IsIPAddrValid(ntohl(*(DWORD *) value), ntohl(*(DWORD *) (value + 4))) ) + if ( optParsed->len != (NMRP_MIN_OPT_LEN + 8) ) + retVal = NMRP_ERR_MSG_INVALID_OPT; + else + optParsed->value.streamVal = value; + break; + + case NMRP_OPT_FW_UP: /* don't check the length of FW-UP option for future compatibility */ + break; + + default: + retVal = NMRP_ERR_MSG_UNKNOWN_OPT; + break; + } + + return retVal; +} + +int NMRP_MsgParsing(const NMRP_MSG *pkt, int pktLen, NMRP_PARSED_MSG *msg) +{ + if (pktLen < NMRP_HDR_LEN) + return NMRP_ERR_MSG_INVALID_LEN; + + msg->code = pkt->code; + msg->id = pkt->id; + + if ((msg->length = NTOHCS(pkt->length)) <= pktLen && msg->length >= NMRP_HDR_LEN) { + int retVal; + uint16_t optLen; + NMRP_OPT *opt; + NMRP_PARSED_OPT *optParsed; + + opt = (NMRP_OPT *)(((uint8_t *) pkt) + NMRP_HDR_LEN); + optParsed = msg->options; + msg->numOptions = 0; + + /* use the length indicated in the NMRP header */ + for (pktLen = msg->length - NMRP_HDR_LEN; pktLen >= NMRP_MIN_OPT_LEN; ) + { + optParsed->type = NTOHCS(opt->type); + optParsed->len = optLen = NTOHCS(opt->len); + + if (optParsed->len > pktLen) + return NMRP_ERR_MSG_INVALID_OPT; + + if ((retVal = NMRP_OptValParsing(optParsed, &opt->value)) == NMRP_ERR_NONE) + { + optParsed++; + + if (++msg->numOptions >= NMRP_MAX_OPT_PER_MSG) + return NMRP_ERR_MSG_TOO_MANY_OPT; + } + else if (retVal != NMRP_ERR_MSG_UNKNOWN_OPT) + { + return NMRP_ERR_MSG_INVALID_OPT; + } + + pktLen -= optLen; + opt = (NMRP_OPT *)(((uint8_t *) opt) + optLen); + } + } /* end if the msg->length is larger than the received packet length */ + + return pktLen == 0 ? NMRP_ERR_NONE : NMRP_ERR_MSG_INVALID_LEN; +} + +NMRP_PARSED_OPT *NMRP_MsgGetOpt(NMRP_PARSED_MSG *msg, uint16_t optType) +{ + NMRP_PARSED_OPT *opt, *optEnd; + + optEnd = &msg->options[msg->numOptions]; + + for (opt = msg->options; opt != optEnd; opt++) + if (opt->type == optType) + break; + + return msg->numOptions == 0 ? NULL : (opt == optEnd ? NULL : opt); +} + +static int NMRPClosing(void) +{ + int ret, retries=0; + static NMRP_REQ_CUSTOM reqClose = { NMRP_CODE_CLOSE_REQ, "CLOSE-REQ", "CLOSE-ACK", NULL }; + + do { + ret = NMRPSend(&reqClose); + if( !ret) + { + cfe_sleep(CFE_HZ/2); + if(g_nmrp_close_acked) + { + break; + } + } + } while(++retries <= NMRP_MAX_RETRY_CLOSE); + + return 0; +} + +int NMRPTFTPWaiting(void) +{ + static NMRP_REQ_CUSTOM reqTftpUl = { NMRP_CODE_TFTP_UL_REQ, "TFTP-UL-REQ", "TFTP-WRQ", NULL }; + + return NMRPSend(&reqTftpUl); +} + +/* Foxconn modify start by Jenny Zhao, 08/07/2008, for fixed timeout issue*/ +int NMRPKeepAlive(void) +{ + static NMRP_REQ_CUSTOM reqkeepalive = { NMRP_CODE_KEEP_ALIVE_REQ, "KEEPALIVE_REQ", "KEEPALIVE-ACK", NULL }; + + return NMRPSend(&reqkeepalive); +} +/* Foxconn modify end by Jenny Zhao, 08/07/2008*/ + +static int NMRPConfAckParser(const void *pkt, int pktLen, const BYTE *serverMac, void *userData) +{ + NMRP_PARSED_MSG *nmrpMsg = (NMRP_PARSED_MSG *) userData; + + return NMRP_MsgGetOpt(nmrpMsg, NMRP_OPT_DEV_IP) != NULL; + /* + return IS_NMRP_PKT((const ETHER_NMRP_PKT *)pkt, pktLen, nmrpMsg, serverMac) && + nmrpMsg->code == NMRP_CODE_CONF_ACK && + NMRP_MsgGetOpt(nmrpMsg, NMRP_OPT_DEV_IP) != NULL; + */ +} + + +static int NMRPConfiguring( const BYTE *serverMac, + const BYTE *clientMac, + DWORD *ipAddr, DWORD *ipSubnetMask, + int *fwUpgrade) +{ + //int ret, retries=0; + int ret; + NMRP_PARSED_OPT *devIp; + static NMRP_REQ_CUSTOM reqConf = { NMRP_CODE_CONF_REQ, "CONF-REQ", "CONF-ACK", NMRPConfAckParser }; + + do { + + ret = NMRPSend(&reqConf); + if( !ret) + { + cfe_sleep(CFE_HZ/2); + if(g_nmrp_config_acked) + { + break; + } + } + + //}while(++retries <= NMRP_MAX_RETRY_CLOSE); + } while(1); + + if(g_nmrp_config_acked) + { + devIp = NMRP_MsgGetOpt(&g_nmrpMsg, NMRP_OPT_DEV_IP); + *ipAddr = (* (DWORD *) devIp->value.streamVal); + *ipSubnetMask = (* (DWORD *) (devIp->value.streamVal + 4)); + *fwUpgrade = NMRP_MsgGetOpt(&g_nmrpMsg, NMRP_OPT_FW_UP) != NULL; + return 0; + } + return -1; +} + +static int NMRPSend(NMRP_REQ_CUSTOM *custom) +{ + ebuf_t *txbuf; + NMRP_MSG *msg; + unsigned long random_backoff; + + txbuf = eth_alloc(netctx->ethinfo, g_portal_number); + if (!txbuf) + { + return -1; + } + msg = (NMRP_MSG *)(txbuf->eb_data + 14); + msg->reserved = 0; + msg->code = custom->reqCode; + msg->id = 0; + msg->length = HTONCS(NMRP_HDR_LEN); /* header only, no option */ + txbuf->eb_length = NMRP_HDR_LEN; + + random_backoff = rand(); + random_backoff = random_backoff % 30; + xprintf("%s sent...Waiting for %s...\n", custom->reqName, custom->respName); + cfe_sleep(random_backoff); + eth_send(txbuf, (uint8_t *)g_NetInfo.peerMac); + eth_free(txbuf); + + return 0; +} + diff --git a/cfe/cfe/net/net_nmrp.h b/cfe/cfe/net/net_nmrp.h new file mode 100755 index 0000000..052ff19 --- /dev/null +++ b/cfe/cfe/net/net_nmrp.h @@ -0,0 +1 @@ +int _start_nmrp(void); diff --git a/cfe/cfe/net/net_tcp.c b/cfe/cfe/net/net_tcp.c new file mode 100755 index 0000000..377c3c8 --- /dev/null +++ b/cfe/cfe/net/net_tcp.c @@ -0,0 +1,2215 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TCP Protocol File: net_tcp.c + * + * This file contains a very simple TCP. The basic goals of this + * tcp are to be "good enough for firmware." We try to be + * correct in our protocol implementation, but not very fancy. + * In particular, we don't deal with out-of-order segments, + * we don't hesitate to copy data more then necessary, etc. + * We strive to implement important protocol features + * like slow start, nagle, etc., but even these things are + * subsetted and simplified as much as possible. + * + * Current "todo" list: + * slow start + * good testing of retransmissions, + * round-trip delay calculations + * Process received TCP options, particularly segment size + * Ignore urgent data (remove from datastream) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_ip.h" +#include "net_ip_internal.h" + +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "net_tcpbuf.h" +#include "net_tcp_internal.h" +#include "net_tcp.h" + +/* ********************************************************************* + * Config + ********************************************************************* */ + +//#define _TCP_DEBUG_ + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +struct tcp_info_s { + void *ti_ref; /* ref data for IP layer */ + ip_info_t *ti_ipinfo; /* IP layer handle */ + cfe_timer_t ti_fasttimer; /* 200ms timer */ + queue_t ti_tcblist; /* list of known TCBs */ + int ti_onqueue; /* number of TCBs on queue */ + uint32_t ti_iss; /* initial sequence number */ + tcb_t *ti_ports[TCP_MAX_PORTS]; /* table of active sockets */ +}; + +/* ********************************************************************* + * Forward Declarations + ********************************************************************* */ + +static void _tcp_protosend(tcp_info_t *ti,tcb_t *tcb); +static int _tcp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr); +static void _tcp_output(tcp_info_t *ti,tcb_t *tcb); +static void _tcp_aborttcb(tcp_info_t *ti,tcb_t *tcb); +static void _tcp_closetcb(tcp_info_t *ti,tcb_t *tcb); +static tcb_t *_tcp_find_lclport(tcp_info_t *ti,uint16_t port); +static void _tcp_freetcb(tcp_info_t *ti,tcb_t *tcb); +static void _tcp_sendctlmsg(tcp_info_t *ti,tcb_t *tcb,uint16_t flags,int timeout); + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#ifdef _TCP_DEBUG_ +#define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state); \ + printf("tcp state = " #state "\n"); +#define DEBUGMSG(x) printf x +#else +#define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state); +#define DEBUGMSG(x) +#endif + +#define _tcp_preparectlmsg(tcb,flags) (tcb)->tcb_txflags = (flags) ; \ + (tcb)->tcb_flags |= TCB_FLG_SENDMSG; + +#define _tcp_canceltimers(tcb) \ + TIMER_CLEAR((tcb)->tcb_timer_retx); \ + TIMER_CLEAR((tcb)->tcb_timer_keep); \ + TIMER_CLEAR((tcb)->tcb_timer_2msl); \ + TIMER_CLEAR((tcb)->tcb_timer_pers); + + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +#ifdef _TCP_DEBUG_ +int _tcp_dumpflags = 1; +#else +int _tcp_dumpflags = 0; +#endif + +/* ********************************************************************* + * _tcp_init(ipi,ref) + * + * Initialize the TCP module. We set up our data structures + * and register ourselves with the IP layer. + * + * Input parameters: + * ipi - IP information + * ref - will be passed back to IP as needed + * + * Return value: + * tcp_info_t structure, or NULL if problems + ********************************************************************* */ + +tcp_info_t *_tcp_init(ip_info_t *ipi,void *ref) +{ + tcp_info_t *ti; + int idx; + + ti = (tcp_info_t *) KMALLOC(sizeof(tcp_info_t),0); + if (!ti) return NULL; + + ti->ti_ref = ref; + ti->ti_ipinfo = ipi; + + /* + * Start the "fast" timer + */ + + TIMER_SET(ti->ti_fasttimer,TCP_FAST_TIMER); + + /* + * Initialize the TCB list + */ + + q_init(&(ti->ti_tcblist)); + + for (idx = 0; idx < TCP_MAX_PORTS; idx++) { + ti->ti_ports[idx] = NULL; + } + + ti->ti_onqueue = 0; + + /* + * Set up the initial sequence number + */ + + extern int32_t _getticks(void); /* return value of CP0 COUNT */ + ti->ti_iss = (uint32_t) _getticks(); /* XXX nonportable */ + + /* + * Register our protocol with IP + */ + + _ip_register(ipi,IPPROTO_TCP,_tcp_rx_callback,ti); + + return ti; +} + + +/* ********************************************************************* + * _tcp_uninit(info) + * + * De-initialize the TCP layer, unregistering from the IP layer. + * + * Input parameters: + * info - our tcp_info_t, from _tcp_init() + * + * Return value: + * nothing + ********************************************************************* */ + +void _tcp_uninit(tcp_info_t *info) +{ + tcb_t *tcb; + + /* + * Destroy all allocated TCBs, forcefully. + */ + + while (!q_isempty(&(info->ti_tcblist))) { + tcb = (tcb_t *) q_getfirst(&(info->ti_tcblist)); + /* tcp_freetcb removes tcb from the queue */ + _tcp_freetcb(info,tcb); + } + + /* + * Deregister with IP + */ + + _ip_deregister(info->ti_ipinfo,IPPROTO_TCP); + + /* + * Free up the info structure + */ + + KFREE(info); +} + + +/* ********************************************************************* + * _tcp_freetcb(ti,tcb) + * + * Called when the TIME_WAIT timer expires, we use this to + * free up the TCB for good. + * + * Input parameters: + * ti - tcp information + * tcb - tcb to free + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_freetcb(tcp_info_t *ti,tcb_t *tcb) +{ + /* + * Undo socket number + */ + + if (tcb->tcb_socknum >= 0) ti->ti_ports[tcb->tcb_socknum] = NULL; + tcb->tcb_socknum = -1; + + /* + * Remove from queue + */ + + ti->ti_onqueue--; + q_dequeue(&(tcb->tcb_qb)); + + /* + * Free buffers (could probably be done in tcb_destroy) + */ + + tmb_free(&(tcb->tcb_txbuf)); + tmb_free(&(tcb->tcb_rxbuf)); + + /* + * Free the TCB + */ + + KFREE(tcb); + +} + +/* ********************************************************************* + * _tcp_socket(info) + * + * Create a new tcp socket (a new tcb structure is allocated + * and entered into the socket table) + * + * Input parameters: + * info - tcp information + * + * Return value: + * new socket number, or <0 if an error occured + ********************************************************************* */ + +int _tcp_socket(tcp_info_t *info) +{ + int idx; + tcb_t *tcb; + + /* + * Find an empty slot. + */ + + for (idx = 0; idx < TCP_MAX_PORTS; idx++) { + if (!info->ti_ports[idx]) break; + } + + if (idx == TCP_MAX_PORTS) { + return CFE_ERR_NOHANDLES; + } + + /* + * See if we can create another TCB + */ + + if (info->ti_onqueue >= TCP_MAX_TCBS) return CFE_ERR_NOMEM; + + /* + * Allocate data structures + */ + + tcb = KMALLOC(sizeof(tcb_t),0); + if (!tcb) return CFE_ERR_NOMEM; + + memset(tcb,0,sizeof(tcb_t)); + + if (tmb_alloc(&tcb->tcb_txbuf,TCP_BUF_SIZE) < 0) goto error; + if (tmb_alloc(&tcb->tcb_rxbuf,TCP_BUF_SIZE) < 0) goto error; + + /* + * XXX Temp: our MTU is always 1400. We could/should + * XXX get this from the lower layer. + */ + + tcb->tcb_mtu = 1400; + + /* + * Default socket flags + */ + + tcb->tcb_sockflags = TCPFLG_NBIO; + + /* + * Set up initial state. Find an empty port number. + * note that the way we do this is pretty gruesome, but it will + * work for our small TCP, where the number of TCBs outstanding + * will be very small compared to the port number space. + * + * Try to look up the port number we want - if we find it, increment + * it and try again until we find an unused one. + * Stay away from ports 0..1023. + */ + + _tcp_setstate(tcb,TCPSTATE_CLOSED); + tcb->tcb_lclport = (uint16_t) (((uint16_t) cfe_ticks) + 1024); + + while (_tcp_find_lclport(info,tcb->tcb_lclport) != NULL) { + tcb->tcb_lclport++; + if (tcb->tcb_lclport == 0) tcb->tcb_lclport = 1024; + } + + /* + * Remember this socket in the table + */ + + info->ti_ports[idx] = tcb; + tcb->tcb_socknum = idx; + + info->ti_onqueue++; + q_enqueue(&(info->ti_tcblist),&(tcb->tcb_qb)); + + return idx; + +error: + tmb_free(&(tcb->tcb_txbuf)); + tmb_free(&(tcb->tcb_rxbuf)); + KFREE(tcb); + return CFE_ERR_NOMEM; +} + + +/* ********************************************************************* + * _tcp_connect(ti,s,dest,port) + * + * Connect a socket to a remote port. + * + * Input parameters: + * ti - TCP information + * s - socket number, allocated via _tcp_create + * dest - destination IP address + * port - destination port number + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_connect(tcp_info_t *ti,int s,uint8_t *dest,uint16_t port) +{ + tcb_t *tcb; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + memcpy(tcb->tcb_peeraddr,dest,IP_ADDR_LEN); + tcb->tcb_peerport = port; + + tcb->tcb_rcvnext = 0; + tcb->tcb_rcvack = 0; + + tcb->tcb_sendnext = ti->ti_iss; + tcb->tcb_sendunack = ti->ti_iss; + tcb->tcb_sendwindow = 0; + + tmb_init(&tcb->tcb_txbuf); + tmb_init(&tcb->tcb_rxbuf); + + TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER); + _tcp_setstate(tcb,TCPSTATE_SYN_SENT); + + _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN,TCP_RETX_TIMER); + + return 0; +} + + +/* ********************************************************************* + * _tcp_close(ti,s) + * + * Disconnect a TCP socket nicely. Sends a FIN packet to get + * us into the disconnect state. + * + * Input parameters: + * ti - tcp information + * s - socket number + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_close(tcp_info_t *ti,int s) +{ + tcb_t *tcb; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + +#if defined(CONFIG_MIPS_BRCM) + /* + * Flush output data. + */ + + _tcp_output(ti,tcb); +#endif + + /* + * Reclaim this socket number for future use + */ + + ti->ti_ports[s] = NULL; + tcb->tcb_socknum = -1; + + /* + * Decide what action to take based on current state + */ + + switch (tcb->tcb_state) { + case TCPSTATE_SYN_RECEIVED: + case TCPSTATE_ESTABLISHED: + /* + * Transmit the FIN/ACK and wait for a FIN/ACK. + * + * XXX probably want to wait till all unacked data is + * acked before sending the fin?? This would be sort + * of like the "linger" option + */ + _tcp_setstate(tcb,TCPSTATE_FINWAIT_1); + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER); + break; + + case TCPSTATE_CLOSED: + case TCPSTATE_LISTEN: + case TCPSTATE_SYN_SENT: + /* + * Disconnect during our attempt, or from some + * idle state that does not require sending anything. + * Go back to CLOSED. + */ + _tcp_closetcb(ti,tcb); + _tcp_freetcb(ti,tcb); + break; + + case TCPSTATE_CLOSE_WAIT: + _tcp_setstate(tcb,TCPSTATE_LAST_ACK); + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER); + break; + + case TCPSTATE_TIME_WAIT: + case TCPSTATE_FINWAIT_1: + case TCPSTATE_FINWAIT_2: + case TCPSTATE_CLOSING: + case TCPSTATE_LAST_ACK: + default: + break; + } + + return 0; +} + + + +/* ********************************************************************* + * _tcp_aborttcb(ti,tcb) + * + * Forcefully terminate a TCP connection. Sends an RST packet + * to nuke the other end. The socket is forced into the CLOSED + * state. + * + * Input parameters: + * ti - tcp information + * tcb -tcb to abort + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_aborttcb(tcp_info_t *ti,tcb_t *tcb) +{ + DEBUGMSG(("tcp_abort from state %d\n",tcb->tcb_state)); + + /* + * Decide what action to take based on current state + * If we're in SYN_SENT, RECEIVED, ESTABLISHED, FINWAIT_1, + * FINWAIT_2, CLOSING, LAST_ACK, or CLOSE_WAIT we've sent + * some traffic on this TCB, so send an RST to kill off + * the remote TCB. + */ + + if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_ABORTSTATES)) { + /* Send RST with no timeout, don't retransmit it. */ + _tcp_canceltimers(tcb); + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_RST,0); + } + + /* + * No matter what, it's now CLOSED. + */ + + _tcp_closetcb(ti,tcb); + +} + + +/* ********************************************************************* + * _tcp_closetcb(ti,tcb) + * + * Close a TCB, switching the state to "closed" and resetting + * internal variables. The TCB is *not* freed. + * + * Input parameters: + * ti - tcp information + * tcb - tcb to close + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_closetcb(tcp_info_t *ti,tcb_t *tcb) +{ + /* + * Set state to "closed" and reset timers + */ + + _tcp_setstate(tcb,TCPSTATE_CLOSED); + tcb->tcb_flags = 0; + _tcp_canceltimers(tcb); + + /* + * Reinitialize the buffers to waste the stored send data and + * clear out any receive data + */ + + tmb_init(&tcb->tcb_txbuf); + tmb_init(&tcb->tcb_rxbuf); +} + +/* ********************************************************************* + * _tcp_send(ti,s,buf,len) + * + * Queue some data to be transmitted via a TCP socket + * + * Input parameters: + * ti - TCP information + * s - socket number + * buf - buffer of data to send + * len - size of buffer to send + * + * Return value: + * number of bytes queued + * <0 if an error occured + ********************************************************************* */ + +int _tcp_send(tcp_info_t *ti,int s,uint8_t *buf,int len) +{ + tcb_t *tcb; + int retlen; + int curlen; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + /* + * State must be ESTABLISHED or CLOSE_WAIT. CLOSE_WAIT + * means we've received a fin, but we can still send in + * the outbound direction. + */ + + if (!TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_SEND_OK)) { + return CFE_ERR_NOTCONN; + } + + /* + * Copy the user data into the transmit buffer. + */ + + curlen = tmb_curlen(&(tcb->tcb_txbuf)); + retlen = tmb_copyin(&(tcb->tcb_txbuf),buf,len,TRUE); + + /* + * Cause some output on the device. + */ + + /* + * Nagle: Call _tcp_output only if there is no outstanding + * unacknowledged data. The way our transmit buffer + * works, it only holds unacknowledged data, so this + * test is easy. It isn't really 100% correct to + * do it this way, but the effect is the same; we will + * not transmit tinygrams. + */ + + if ((curlen == 0) || (tcb->tcb_sockflags & TCPFLG_NODELAY)) { + _tcp_output(ti,tcb); + } + + return retlen; +} + +/* ********************************************************************* + * _tcp_recv(ti,s,buf,len) + * + * Get buffered receive data from the TCP socket + * + * Input parameters: + * ti - tcp information + * s - socket number + * buf - pointer to receive buffer area + * len - size of receive buffer area + * + * Return value: + * number of bytes received + * <0 if an error occured + * ==0 if no data available (or tcp session is closed) + ********************************************************************* */ + +int _tcp_recv(tcp_info_t *ti,int s,uint8_t *buf,int len) +{ + tcb_t *tcb; + int retlen; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + if (!TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_RECV_OK)) { + return CFE_ERR_NOTCONN; + } + + retlen = tmb_copyout(&(tcb->tcb_rxbuf),buf,len,TRUE); + + /* + * If we've drained all of the data out of the buffer + * send an ack. This isn't ideal, but it will + * prevent us from keeping the window closed. + */ + +// if (retlen && (tmb_curlen(&(tcb->tcb_rxbuf)) == 0)) { +// _tcp_preparectlmsg(tcb,TCPFLG_ACK); +// _tcp_protosend(ti,tcb); +// tcb->tcb_flags &= ~TCB_FLG_DLYACK; +// } + + return retlen; +} + + +/* ********************************************************************* + * _tcp_bind(ti,s,port) + * + * "bind" a TCP socket to a particular port - this sets the + * outbound local (source) port number. + * + * Input parameters: + * ti - tcp information + * s - socket number + * port - port number + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_bind(tcp_info_t *ti,int s,uint16_t port) +{ + tcb_t *tcb; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + /* XXX test state - must be in 'closed' */ + + if (_tcp_find_lclport(ti,port)) return CFE_ERR_ADDRINUSE; + + tcb->tcb_lclport = port; + + return 0; +} + +/* ********************************************************************* + * _tcp_setflags(ti,s,flags) + * + * Set per-socket flags. + * + * Input parameters: + * ti - tcp information + * s - socket number + * flags - flags to set + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_setflags(tcp_info_t *ti,int s,unsigned int flags) +{ + tcb_t *tcb; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + tcb->tcb_sockflags = flags; + + return 0; +} + +/* ********************************************************************* + * _tcp_getflags(ti,s,flags) + * + * Get per-socket flags. + * + * Input parameters: + * ti - tcp information + * s - socket number + * flags - pointer to int to receive flags + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_getflags(tcp_info_t *ti,int s,unsigned int *flags) +{ + tcb_t *tcb; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + *flags = tcb->tcb_sockflags; + + return 0; +} + + +/* ********************************************************************* + * _tcp_peeraddr(ti,s,addr,port) + * + * Return the address of the computer on the other end of this + * connection. + * + * Input parameters: + * ti - tcp information + * s - socket number + * addr - receives IP address of remote + * port - port number + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_peeraddr(tcp_info_t *ti,int s,uint8_t *addr,uint16_t *port) +{ + tcb_t *tcb; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + /* + * Test for any of the states where we believe the peeraddr in the tcb + * is valid. + */ + + if (!TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_PEERADDR_OK)) { + return CFE_ERR_NOTCONN; + } + + if (addr) memcpy(addr,tcb->tcb_peeraddr,IP_ADDR_LEN); + if (port) *port = tcb->tcb_peerport; + + return 0; +} + +/* ********************************************************************* + * _tcp_listen(ti,s,port) + * + * Set a socket for listening mode, allowing inbound connections + * to occur. + * + * Input parameters: + * ti - tcp information + * s - socket nunber + * port - port number to listen for (implicit tcp_bind) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_listen(tcp_info_t *ti,int s,uint16_t port) +{ + tcb_t *tcb; + queue_t *qb; + + /* + * See if another TCB is listening to this port + */ + + for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) { + tcb = (tcb_t *) qb; + + if ((tcb->tcb_lclport == port) && + (tcb->tcb_state == TCPSTATE_LISTEN) && + (tcb->tcb_peerport == 0)) return CFE_ERR_ADDRINUSE; + + } + + /* + * Otherwise, we're good to go. + */ + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + tcb->tcb_lclport = port; + _tcp_setstate(tcb,TCPSTATE_LISTEN); + + tcb->tcb_sendnext = 0; + tcb->tcb_sendunack = 0; + tcb->tcb_sendwindow = 0; + _tcp_canceltimers(tcb); + + tcb->tcb_rcvnext = 0; + tcb->tcb_rcvack = 0; + + tmb_init(&tcb->tcb_txbuf); + tmb_init(&tcb->tcb_rxbuf); + + tcb->tcb_txflags = 0; + + return 0; +} + +/* ********************************************************************* + * _tcp_status(ti,s,connflag,rxready,rxeof) + * + * Get status information about the TCP session + * + * Input parameters: + * ti - tcp information + * s - socket nunber + * connflag - points to an int to receive connection status + * (1=connected,0=not connected) + * rxready - number of bytes in receive queue + * rxeof - returns 1 if we've been FINed. + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_status(tcp_info_t *ti,int s,unsigned int *connflag,int *rxready,int *rxeof) +{ + tcb_t *tcb; + int rxlen; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + rxlen = tmb_curlen(&(tcb->tcb_rxbuf)); + + /* + * We consider the connection "connected" if it's established + * or it's in CLOSE_WAIT (FIN received) but we have not drained + * all of the receive data. + * + * Otherwise: If it's not in one of the connection establishment states, + * it's not connected. + */ + + if (connflag) { + if ((tcb->tcb_state == TCPSTATE_ESTABLISHED) || + ((rxlen != 0) && (tcb->tcb_state == TCPSTATE_CLOSE_WAIT))) { + *connflag = TCPSTATUS_CONNECTED; + } + else if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_CONNINPROGRESS)) { + *connflag = TCPSTATUS_CONNECTING; + } + else { + *connflag = TCPSTATUS_NOTCONN; + } + } + + if (rxready) { + *rxready = rxlen; + } + + if (rxeof) { + *rxeof = 0; + if ((tcb->tcb_state == TCPSTATE_CLOSE_WAIT) || + (tcb->tcb_state == TCPSTATE_LAST_ACK)) { + *rxeof = 1; + } + } + + return 0; +} + +/* ********************************************************************* + * _tcp_debug(ti,s,arg) + * + * Perform debug functions on a socket + * + * Input parameters: + * ti - tcp information + * s - socket number + * arg - argument + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _tcp_debug(tcp_info_t *ti,int s,int arg) +{ + tcb_t *tcb; + + tcb = ti->ti_ports[s]; + if (!tcb) return CFE_ERR_INV_PARAM; + + printf("State=%d SendNext=%u SendUnack=%u ", + tcb->tcb_state,tcb->tcb_sendnext,tcb->tcb_sendunack); + printf("SendWin=%d Ack=%u Rxlen=%d\n", + tcb->tcb_sendwindow, + tcb->tcb_rcvack,tmb_curlen(&(tcb->tcb_rxbuf))); + + return 0; +} + + +#ifdef _TCP_DEBUG_ +/* ********************************************************************* + * _tcp_dumppktstate(label,flags,ack,seq,len) + * + * A debug function. + * + * Input parameters: + * label - printed before packet state + * flags - transmit flags for packet + * ack,seq,len - from the packet + * + * Return value: + * nothing + ********************************************************************* */ +static void _tcp_dumppktstate(char *label,uint16_t flags, + uint32_t ack,uint32_t seq,int len) +{ + printf("%s: ",label); + if (flags & TCPFLG_FIN) printf("FIN "); + if (flags & TCPFLG_SYN) printf("SYN "); + if (flags & TCPFLG_RST) printf("RST "); + if (flags & TCPFLG_PSH) printf("PSH "); + if (flags & TCPFLG_ACK) printf("ACK "); + if (flags & TCPFLG_URG) printf("URG "); + printf("Ack=%u Seq=%u Data=%d\n",ack,seq,len); +} +#endif + + +/* ********************************************************************* + * _tcp_output(ti,tcb) + * + * Try to perform some output on this TCB. If there is + * data to send and we can transmit it (i.e., the remote's + * receive window will allow it), segment the data from the + * buffer and transmit it, updating local state variables. + * + * Input parameters: + * ti - tcp information + * tcb - the tcb to send data on + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_output(tcp_info_t *ti,tcb_t *tcb) +{ + ebuf_t *b; + int tcplen; + int window; + uint16_t flags; + uint8_t *cksumptr; + uint8_t *tcphdr; + uint16_t cksum; + int hdrlen; + uint8_t pseudoheader[12]; + int offset; + uint32_t sendmax; + uint32_t windowmax; + uint32_t cwndmax; + + /* + * sendmax is (one plus) the highest sequence number we have + * data for. + * + * windowmax is (one plus) the highest sequence number in the + * send window. + * + * cwndmax is (one plus) the highest sequence number in the + * congestion window. + */ + + sendmax = tcb->tcb_sendunack + tmb_curlen(&(tcb->tcb_txbuf)); + windowmax = tcb->tcb_sendunack + tcb->tcb_sendwindow; + cwndmax = tcb->tcb_sendunack + 5*1400; + + /* + * We'll send up to 'sendmax', 'cwndmax', or 'windowmax' bytes, whichever + * is sooner. Set 'sendmax' to the earliest sequence number. + */ + + if (TCPSEQ_GT(sendmax,windowmax)) sendmax = windowmax; + if (TCPSEQ_GT(sendmax,cwndmax)) sendmax = cwndmax; + + /* + * The (receive) window is whatever it takes to fill the buffer. + */ + + window = tmb_remlen(&(tcb->tcb_rxbuf)); + if (window > 65000) window = 65000; + + /* + * Spit out packets until "sendnext" either catches up + * or exceeds the remote window + */ + + while (TCPSEQ_LT(tcb->tcb_sendnext,sendmax)) { + + /* + * This is the offset into the transmit buffer to start with. + * Offset 0 in the transmit buffer corresponds to "send unack" + * received acks move this pointer. + */ + + offset = tcb->tcb_sendnext - tcb->tcb_sendunack; + + /* + * Allocate a buffer and remember the pointer to where + * the header starts. + */ + + b = _ip_alloc(ti->ti_ipinfo); + if (!b) break; + + tcphdr = ebuf_ptr(b) + ebuf_length(b); + + flags = TCPFLG_ACK | TCPHDRFLG(TCP_HDR_LENGTH); + hdrlen = TCP_HDR_LENGTH; + + /* + * Fill in the fields according to the RFC. + */ + + tcb->tcb_rcvack = tcb->tcb_rcvnext; /* Update our "most recent ack" */ + + ebuf_append_u16_be(b,tcb->tcb_lclport); /* Local and remote ports */ + ebuf_append_u16_be(b,tcb->tcb_peerport); + ebuf_append_u32_be(b,tcb->tcb_sendnext); /* sequence and ack numbers */ + ebuf_append_u32_be(b,tcb->tcb_rcvack); + ebuf_append_u16_be(b,flags); /* Flags */ + ebuf_append_u16_be(b,window); /* Window size */ + cksumptr = ebuf_ptr(b) + ebuf_length(b); + ebuf_append_u16_be(b,0); /* dummy checksum for calculation */ + ebuf_append_u16_be(b,0); /* Urgent Pointer (not used) */ + + /* + * Append the data, copying pieces out of the transmit buffer + * without adjusting its pointers. + */ + + tcplen = tmb_copyout2(&(tcb->tcb_txbuf), + b->eb_ptr + b->eb_length, + offset, + tcb->tcb_mtu); + + b->eb_length += tcplen; + +#ifdef _TCP_DEBUG_ + if (_tcp_dumpflags) _tcp_dumppktstate("TX_DATA",flags, + tcb->tcb_sendnext, + tcb->tcb_rcvack,tcplen); +#endif + + /* + * Adjust the "send next" sequence number to account for what + * we're about to send. + */ + + tcb->tcb_sendnext += tcplen; + + + /* + * Build the pseudoheader, which is part of the checksum calculation + */ + + _ip_getaddr(ti->ti_ipinfo,&pseudoheader[0]); + memcpy(&pseudoheader[4],tcb->tcb_peeraddr,IP_ADDR_LEN); + pseudoheader[8] = 0; + pseudoheader[9] = IPPROTO_TCP; + pseudoheader[10] = ((tcplen+hdrlen) >> 8) & 0xFF; + pseudoheader[11] = ((tcplen+hdrlen) & 0xFF); + + /* + * Checksum the packet and insert the checksum into the header + */ + + cksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader)); + cksum = ip_chksum(cksum,tcphdr,tcplen + hdrlen); + cksum = ~cksum; + cksumptr[0] = (cksum >> 8) & 0xFF; + cksumptr[1] = (cksum & 0xFF); + + /* + * Transmit the packet. The layer below us will free it. + */ + + _ip_send(ti->ti_ipinfo,b,tcb->tcb_peeraddr,IPPROTO_TCP); + + /* + * Set the timer that we'll use to wait for an acknowledgement. + * If this timer goes off, we'll rewind "sendnext" back to + * "sendunack" and transmit stuff again. + */ + + TIMER_SET(tcb->tcb_timer_retx,TCP_RETX_TIMER); + + /* + * We just sent an ack, so cancel the delayed ack timer. + */ + + tcb->tcb_flags &= ~TCB_FLG_DLYACK; + + } + +} + +/* ********************************************************************* + * _tcp_protosend(ti,tcb) + * + * Transmit "protocol messages" on the tcb. This is used for + * sending SYN, FIN, ACK, and other control packets. + * + * Input parameters: + * ti - tcp infomration + * tcb - tcb we're interested in + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_protosend(tcp_info_t *ti,tcb_t *tcb) +{ + ebuf_t *b; + int tcplen; + int window; + uint16_t flags; + uint8_t *cksumptr; + uint8_t *tcphdr; + uint16_t cksum; + int hdrlen; + uint8_t pseudoheader[12]; + + /* + * Allocate a buffer and remember the pointer to where + * the header starts. + */ + + b = _ip_alloc(ti->ti_ipinfo); + if (!b) return; + + tcphdr = ebuf_ptr(b) + ebuf_length(b); + + /* + * We're going to send something, so we can clear the flag. + * Also clear the delay-ack flag since everything's an ack. + */ + + tcb->tcb_flags &= ~(TCB_FLG_SENDMSG | TCB_FLG_DLYACK); + + /* + * Build the TCP header + */ + + /* The flags are the current flags + the header length */ + if (tcb->tcb_txflags & TCPFLG_SYN) { + flags = tcb->tcb_txflags | (TCPHDRFLG(TCP_HDR_LENGTH + 4)); + hdrlen = TCP_HDR_LENGTH + 4; + } + else { + flags = tcb->tcb_txflags | (TCPHDRFLG(TCP_HDR_LENGTH)); + hdrlen = TCP_HDR_LENGTH; + } + + +#ifdef _TCP_DEBUG_ + if (_tcp_dumpflags) _tcp_dumppktstate("TX_CTL",flags, + tcb->tcb_sendnext, + tcb->tcb_rcvack,0); +#endif + + /* + * The (receive) window is whatever it takes to fill the buffer. + */ + + window = tmb_remlen(&(tcb->tcb_rxbuf)); + if (window > 65000) window = 65000; + + /* + * Fill in the fields according to the RFC. + */ + + tcb->tcb_rcvack = tcb->tcb_rcvnext; /* update last tx ack */ + + ebuf_append_u16_be(b,tcb->tcb_lclport); /* Local and remote ports */ + ebuf_append_u16_be(b,tcb->tcb_peerport); + ebuf_append_u32_be(b,tcb->tcb_sendnext); /* sequence and ack numbers */ + ebuf_append_u32_be(b,tcb->tcb_rcvack); + ebuf_append_u16_be(b,flags); /* Flags */ + ebuf_append_u16_be(b,window); /* Window size */ + cksumptr = ebuf_ptr(b) + ebuf_length(b); + ebuf_append_u16_be(b,0); /* dummy checksum for calculation */ + ebuf_append_u16_be(b,0); /* Urgent Pointer (not used) */ + + /* + * Append TCP options on SYN packet + */ + + if (flags & TCPFLG_SYN) { + ebuf_append_u16_be(b,TCP_MAX_SEG_OPT); + ebuf_append_u16_be(b,TCP_MAX_SEG_SIZE); + } + + tcplen = 0; /* don't transmit data here */ + + /* + * SYN and FIN packets consume a sequence number, so + * increment the "sendnext" variable. If we need to retransmit + * these segments, we'll wind "sendnext" back to "sendunack" + * + * XXX: Can you send a SYN and FIN at the same time? + */ + + if (flags & (TCPFLG_SYN | TCPFLG_FIN)) tcb->tcb_sendnext++; + + /* + * Build the pseudoheader, which is part of the checksum calculation + */ + + _ip_getaddr(ti->ti_ipinfo,&pseudoheader[0]); + memcpy(&pseudoheader[4],tcb->tcb_peeraddr,IP_ADDR_LEN); + pseudoheader[8] = 0; + pseudoheader[9] = IPPROTO_TCP; + pseudoheader[10] = ((tcplen+hdrlen) >> 8) & 0xFF; + pseudoheader[11] = ((tcplen+hdrlen) & 0xFF); + + /* + * Checksum the packet and insert the checksum into the header + */ + + cksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader)); + cksum = ip_chksum(cksum,tcphdr,tcplen + hdrlen); + cksum = ~cksum; + cksumptr[0] = (cksum >> 8) & 0xFF; + cksumptr[1] = (cksum & 0xFF); + + /* + * Transmit the packet. The layer below us will free it. + */ + + _ip_send(ti->ti_ipinfo,b,tcb->tcb_peeraddr,IPPROTO_TCP); +} + +/* ********************************************************************* + * _tcp_sendreset(ti,dstipaddr,ack,srcport,dstport) + * + * Transmit "protocol messages" on the tcb. This is used for + * sending SYN, FIN, ACK, and other control packets. + * + * Input parameters: + * ti - tcp infomration + * tcb - tcb we're interested in + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_sendreset(tcp_info_t *ti,uint8_t *dstipaddr,uint32_t ack, + uint16_t srcport,uint16_t dstport) +{ + tcb_t tcb; /* fake TCB so we can use _tcp_protosend */ + + memset(&tcb,0,sizeof(tcb)); + memcpy(tcb.tcb_peeraddr,dstipaddr,IP_ADDR_LEN); + tcb.tcb_peerport = dstport; + tcb.tcb_lclport = srcport; + tcb.tcb_txflags = TCPFLG_RST|TCPFLG_ACK; + tcb.tcb_rcvnext = ack; + + _tcp_protosend(ti,&tcb); +} + + +/* ********************************************************************* + * _tcp_sendctlmsg(ti,tcb,flags,timeout) + * + * Set up for and transmit a control message. This is usually + * called on a state transition where we need to send a control + * message like a SYN or FIN, with a timeout. We reset the + * retry counter, set the retransmit timer, and fire off the message + * right here. + * + * Input parameters: + * ti - tcp information + * tcb - the tcb for this TCP session + * flags - packet flags (TCPFLG_xxx) + * timeout - timeout value , in ticks + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_sendctlmsg(tcp_info_t *ti,tcb_t *tcb,uint16_t flags,int timeout) +{ + tcb->tcb_txflags = flags; + tcb->tcb_retrycnt = 0; + + if (timeout >= 0) { + if (timeout) { + TIMER_SET(tcb->tcb_timer_retx,timeout); + } + else { + TIMER_CLEAR(tcb->tcb_timer_retx); + } + } + + _tcp_protosend(ti,tcb); +} + + +/* ********************************************************************* + * _tcp_find_lclport(ti,port) + * + * Find the specified local port - mostly to see if it is + * already in use. + * + * Input parameters: + * ti - tcp information + * port - local port + * + * Return value: + * tcb owning this port, or NULL if none found + ********************************************************************* */ +static tcb_t *_tcp_find_lclport(tcp_info_t *ti,uint16_t port) +{ + tcb_t *tcb = NULL; + queue_t *qb; + + for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) { + tcb = (tcb_t *) qb; + + if (tcb->tcb_lclport == port) return tcb; + + } + + return NULL; + +} + +/* ********************************************************************* + * _tcp_find_tcb(ti,srcport,dstport,saddr) + * + * Locate the TCB in the active TCBs. This is used to match + * an inbound TCP packet to a TCB. + * + * Input parameters: + * ti - tcp information + * srcport,dstport - source and dest ports from TCP header + * saddr - source IP address of sending host + * + * Return value: + * tcb pointer or NULL if no TCB was found + ********************************************************************* */ + +static tcb_t *_tcp_find_tcb(tcp_info_t *ti,uint16_t srcport,uint16_t dstport,uint8_t *saddr) +{ + tcb_t *tcb = NULL; + queue_t *qb; + + for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) { + tcb = (tcb_t *) qb; + + /* Try active TCBs */ + if ((tcb->tcb_peerport != 0) && + (tcb->tcb_lclport == dstport) && + (tcb->tcb_peerport == srcport) && + (memcmp(saddr,tcb->tcb_peeraddr,IP_ADDR_LEN) == 0)) break; + } + + /* Found it on our active list. */ + if (qb != &(ti->ti_tcblist)) return tcb; + + /* no dice, try listening ports */ + for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) { + tcb = (tcb_t *) qb; + + /* Try active TCBs */ + if ((tcb->tcb_peerport == 0) && + (tcb->tcb_lclport == dstport)) break; + } + + /* Found it on our passive list. */ + if (qb != &(ti->ti_tcblist)) return tcb; + + return NULL; +} + +/* ********************************************************************* + * _tcp_procack(ti,tcb,ack,flags) + * + * Process a received acknowledgement. + * + * Input parameters: + * ti - tcp information + * tcb - tcb for this tcb session + * ack - acknum from received packet + * flags - flags from received packet + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_procack(tcp_info_t *ti,tcb_t *tcb,uint32_t ack,uint16_t flags) +{ + int ackamt; + int unacklen; + + /* This is the number of unacknowledged bytes we have */ + unacklen = tmb_curlen(&(tcb->tcb_txbuf)); + + switch (tcb->tcb_state) { + + case TCPSTATE_ESTABLISHED: + /* + * The ack is valid if it's in the range of + * unacknowledged data we're holding onto. + * + * sendunack < ack <= (sendunack+datalen) + * + * Do the first comparison as "<=" instead of just "<" + * so we can catch duplicate acks. + */ + + if (!(TCPSEQ_LEQ(tcb->tcb_sendunack,ack) && + TCPSEQ_LEQ(ack,(tcb->tcb_sendunack+unacklen)))) { + DEBUGMSG(("Ack is out of range: %u\n",ack)); + return; + } + + /* + * Compute the # of bytes spanned by this ack + */ + + ackamt = TCPSEQ_DIFF(ack,tcb->tcb_sendunack); + + /* + * If we actually acked something, adjust the tx buffer + * to remove the bytes covered by the ack, then update + * the 'next' sequence number so we'll start there next + * time. + */ + + if (ackamt > 0) { + tmb_adjust(&tcb->tcb_txbuf,ackamt); + tcb->tcb_txflags = TCPFLG_ACK; + tcb->tcb_sendunack = ack; + tcb->tcb_dup_ackcnt = 0; /* not a duplicate */ + } + else { + tcb->tcb_dup_ackcnt++; + //DEBUGMSG(("Duplicate ack received\n")); + /* + * Duplicate ack received + * XXX This is where we'd be doing stuff for + * XXX slow-start, fast retransmit, etc. + */ + } + + /* + * If we're all caught up, we can cancel the + * retransmit timer. Otherwise, try to do + * some output on the interface. This will + * reset the retransmit timer if we did anything. + */ + + if (tmb_curlen(&(tcb->tcb_txbuf)) != 0) { + tcb->tcb_flags |= TCB_FLG_OUTPUT; + } + else { + TIMER_CLEAR(tcb->tcb_timer_retx); + } + + break; + + case TCPSTATE_FINWAIT_1: + ackamt = TCPSEQ_DIFF(ack,tcb->tcb_sendunack); + if (ackamt == 1) { + tcb->tcb_sendunack = ack; + if (flags & TCPFLG_FIN) { + _tcp_setstate(tcb,TCPSTATE_TIME_WAIT); + _tcp_canceltimers(tcb); + _tcp_preparectlmsg(tcb,TCPFLG_ACK); + TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER); + } + else { + _tcp_setstate(tcb,TCPSTATE_FINWAIT_2); + } + } + break; + + } +} + +/* ********************************************************************* + * _tcp_procdata(ti,tcb,seqnum,flags,buf) + * + * Process data in a received TCP packet - we'll put the + * data into the receive ring buffer, process the seqnum + * field, and prepare to send an ack. + * + * Input parameters: + * ti - tcp information + * tcb - tcb describing TCP session + * seqnum,flags - from the header of the received TCP packet + * buf - ebuf contianing data + * + * Return value: + * nothing + ********************************************************************* */ + +static void _tcp_procdata(tcp_info_t *ti,tcb_t *tcb,uint32_t seqnum, + uint16_t flags,ebuf_t *buf) +{ + int datalen; + uint8_t *bp; + int rxwin,rwin; + uint32_t endseqnum; + uint32_t endrxwindow; + int reallen; + + /* + * Figure out how much we're going to take. This should not + * exceed our buffer size because we advertised a window + * only big enough to fill our buffer. + */ + + bp = ebuf_ptr(buf); /* pointer to TCP data */ + datalen = ebuf_remlen(buf); /* Size of TCP data */ + + /* + * If there's no data in the buffer, we can skip the data-related + * stuff and check for a possible FIN. + */ + + if (datalen != 0) { + + /* + * Figure out if the data fits within the window. We don't deal + * with out-of-order segments, so the test is relatively + * simple: The received segment must contain (or match) + * the sequence number from "rcvnext" to the end of the receive + * window. + * + * Therefore: seqnum <= rcvnext < seqnum+datalen + */ + + rxwin = tmb_remlen(&(tcb->tcb_rxbuf)); /* receive window size */ + endseqnum = (seqnum + datalen); /* seq # of end of segment */ + endrxwindow = tcb->tcb_rcvack + rxwin; /* end of receive window */ + + /* + * The segment might include data outside the receive window + * (it's not supposed to, but it can). Crop the 'endseqnum' + * value at the rx window if necessary. Keep the earlier seqnum. + */ +// +// XXX This is just plain broken - "endrxwindow" is the wrong thing to test. +// if (TCPSEQ_LT(endrxwindow,endseqnum)) { +// endseqnum = endrxwindow; +// } + + /* + * Test to see if the data is in sequence. + */ + + rwin = (TCPSEQ_LEQ(seqnum,tcb->tcb_rcvnext) && + TCPSEQ_LT(tcb->tcb_rcvnext,endseqnum)); + + if (!rwin) { + DEBUGMSG(("Dropping out-of-order packet %u %u %u\n",seqnum, + tcb->tcb_rcvnext,endseqnum)); + return; + } + + /* + * The actual amount of new data is the distance from + * the "rcvnext" pointer to the end sequence number. + * typically this will be the entire packet, but we + * handle the case of receiving a partial duplicate segment. + * Do this by shortening the data length we're going to + * copy and adjusting the buffer pointer to point past the + * duplicate data. Normally this won't do anything. + */ + + reallen = endseqnum - tcb->tcb_rcvnext; + bp += (tcb->tcb_rcvnext - seqnum); + + if (reallen != datalen) { + DEBUGMSG(("newdata(%d) does not match real length(%d)\n",reallen,datalen)); + } + + if (reallen > 0) { + + /* + * Copy the data into the receive buffer. In the + * unlikely event that it doesn't fit, update the + * length so we'll only ack what we took. + */ + + reallen = tmb_copyin(&(tcb->tcb_rxbuf),bp,reallen,TRUE); + + tcb->tcb_rcvnext += reallen; + + /* + * Set the delayed-ack flag. If it's already set, + * then we've already received some data without acking + * it, so send the ack now, to encourage us to + * ack every other segment at least. + */ + + if (tcb->tcb_flags & TCB_FLG_DLYACK) { + _tcp_preparectlmsg(tcb,TCPFLG_ACK); + } + else { + tcb->tcb_flags |= TCB_FLG_DLYACK; + } + } + } + + /* + * Handle the case of data in a FIN packet. + */ + + if (flags & TCPFLG_FIN) { + + tcb->tcb_rcvnext++; /* Consume the FIN */ + + DEBUGMSG(("FIN rcvd in %d ack %u\n",tcb->tcb_state,tcb->tcb_rcvnext)); + + switch (tcb->tcb_state) { + case TCPSTATE_ESTABLISHED: + + /* + * If a FIN is received in the ESTABLISHED state, + * go to CLOSE_WAIT. + */ + + tcb->tcb_flags &= ~TCB_FLG_DLYACK; + _tcp_setstate(tcb,TCPSTATE_CLOSE_WAIT); + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,-1); + break; + + case TCPSTATE_FINWAIT_1: + + /* + * Two choices: Either we got a FIN or a FIN ACK. + * In either case, send an ack. The difference + * is what state we end up in. + */ + + if (flags & TCPFLG_ACK) { + /* Received: FIN ACK - go directly to TIME_WAIT */ + _tcp_canceltimers(tcb); + _tcp_preparectlmsg(tcb,TCPFLG_ACK); + _tcp_setstate(tcb,TCPSTATE_TIME_WAIT); +#if defined(CONFIG_MIPS_BRCM) + TIMER_SET(tcb->tcb_timer_2msl,TCP_SEND_TIMER); +#else + TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER); +#endif + } + else { + /* Received: FIN - simultaneous close, go to CLOSING */ + _tcp_setstate(tcb,TCPSTATE_CLOSING); + _tcp_preparectlmsg(tcb,TCPFLG_ACK); + } + break; + + case TCPSTATE_FINWAIT_2: + + /* + * Received a FIN in FINWAIT_2 - just transmit + * an ack and go to TIME_WAIT. + */ + + _tcp_canceltimers(tcb); + _tcp_preparectlmsg(tcb,TCPFLG_ACK); + _tcp_setstate(tcb,TCPSTATE_TIME_WAIT); + TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER); + break; + } + } + +} + +/* ********************************************************************* + * _tcp_rx_callback(ref,buf,destaddr,srcaddr) + * + * The IP layer calls this routine when a TCP packet is received. + * We dispatch the packet to appropriate handlers from here. + * + * Input parameters: + * ref - our tcp information (held by the ip stack for us) + * buf - the ebuf that we received + * destaddr,srcaddr - destination and source IP addresses + * + * Return value: + * ETH_DROP or ETH_KEEP, depending if we keep the packet or not + ********************************************************************* */ + +static int _tcp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr) +{ + uint8_t pseudoheader[12]; + int tcplen; + uint16_t calccksum; + uint16_t origcksum; + uint8_t *tcphdr; + uint16_t srcport; + uint16_t dstport; + uint32_t seqnum; + uint32_t acknum; + uint16_t window; + uint16_t flags; + tcb_t *tcb; + tcp_info_t *ti = (tcp_info_t *) ref; + + /* + * get a pointer to the TCP header + */ + + tcplen = ebuf_length(buf); + tcphdr = ebuf_ptr(buf); + + /* + * construct the pseudoheader for the cksum calculation + */ + + memcpy(&pseudoheader[0],srcaddr,IP_ADDR_LEN); + memcpy(&pseudoheader[4],destaddr,IP_ADDR_LEN); + pseudoheader[8] = 0; + pseudoheader[9] = IPPROTO_TCP; + pseudoheader[10] = (tcplen >> 8) & 0xFF; + pseudoheader[11] = (tcplen & 0xFF); + + origcksum = ((uint16_t) tcphdr[16] << 8) | (uint16_t) tcphdr[17]; + tcphdr[16] = tcphdr[17] = 0; + + calccksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader)); + calccksum = ip_chksum(calccksum,tcphdr,tcplen); + calccksum = ~calccksum; + + if (calccksum != origcksum) { + return ETH_DROP; + } + + /* Read the other TCP header fields from the packet */ + + ebuf_get_u16_be(buf,srcport); + ebuf_get_u16_be(buf,dstport); + ebuf_get_u32_be(buf,seqnum); + ebuf_get_u32_be(buf,acknum); + ebuf_get_u16_be(buf,flags); + ebuf_get_u16_be(buf,window); + ebuf_skip(buf,4); /* skip checksum and urgent pointer */ + + /* Skip options in header */ + if (TCPHDRSIZE(flags) < TCP_HDR_LENGTH) { + return ETH_DROP; + } + ebuf_skip(buf,(TCPHDRSIZE(flags) - TCP_HDR_LENGTH)); + + /* + * Okay, start looking for a matching TCB. If no matching TCB, + * send a RST. + * XXX Extra credit: rate-limit the RSTs. + */ + + tcb = _tcp_find_tcb(ti,srcport,dstport,srcaddr); + if (!tcb) { + DEBUGMSG(("Invalid TCB from %I, srcport=%u dstport=%u\n",srcaddr,srcport,dstport)); + _tcp_sendreset(ti,srcaddr,seqnum+1,dstport,srcport); + return ETH_DROP; /* drop packet if no matching port */ + } + + /* + * Any activity on a TCB is enough to reset the keepalive timer + */ + + if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_RESETKEEPALIVE)) { + TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER); + } + + /* + * Some debugging + */ + +#ifdef _TCP_DEBUG_ + if (_tcp_dumpflags) _tcp_dumppktstate("Received",flags, + acknum,seqnum,ebuf_length(buf)); +#endif + + /* + * If someone tries to reset us, just kill off the port. + * (except: if we were in SYN_RECEIVED, go back to LISTEN) + */ + + if (flags & TCPFLG_RST) { + if (tcb->tcb_state == TCPSTATE_SYN_RECEIVED) { + _tcp_setstate(tcb,TCPSTATE_LISTEN); + } + else { + _tcp_closetcb(ti,tcb); + } + return ETH_DROP; + } + + /* + * Remember the window we got. + */ + + tcb->tcb_sendwindow = window; + + /* + * What we do here depends on the current connection state + * Most of this is just from the connection state diagram we've + * all see way too often. + */ + + switch ( tcb->tcb_state ) { + + case TCPSTATE_LISTEN: + if (flags & TCPFLG_SYN) { + tcb->tcb_rcvnext = seqnum + 1; + tcb->tcb_peerport = srcport; + memcpy(tcb->tcb_peeraddr,srcaddr,IP_ADDR_LEN); + TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER); + _tcp_setstate(tcb,TCPSTATE_SYN_RECEIVED); + _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN | TCPFLG_ACK,TCP_RETX_TIMER); + } + return ETH_DROP; /* we ignore everything else */ + break; + + case TCPSTATE_SYN_SENT: + + /* + * The only packets we pay attention to in SYN_SENT + * are packets with SYN flags. + */ + if (flags & TCPFLG_SYN) { + + /* + * Two choices: Either we got a SYN ACK (normal) + * or just a SYN (simultaneous open, rare) + */ + + if ((flags & TCPFLG_ACK) && + (acknum == (tcb->tcb_sendunack + 1))) { + /* + * If we received a SYN ACK and the acknum + * matches our SYN's seqnum + 1, we want + * to transition from SYN_SENT to ESTABLISHED. + */ + TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER); + _tcp_setstate(tcb,TCPSTATE_ESTABLISHED); + tcb->tcb_sendunack = acknum; + tcb->tcb_sendnext = tcb->tcb_sendunack; + tcb->tcb_rcvnext = seqnum + 1; + /* + * Send an ack, but don't bother with the timer. + * If the remote does not get our ack, it will + * retransmit the SYN ACK and we'll ack it from + * the "ESTABLISHED" state. + * Actually, is that really true? + */ + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,0); + } + else { + DEBUGMSG(("Simultaneous open: SYN received in SYN_SENT state\n")); + tcb->tcb_rcvnext++; /* consume the SYN */ + _tcp_setstate(tcb,TCPSTATE_SYN_RECEIVED); + _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN|TCPFLG_ACK,TCP_RETX_TIMER); + } + } + + return ETH_DROP; + break; + + case TCPSTATE_SYN_RECEIVED: + /* + * If we've received a SYN and someone sends us a SYN, + * and the sequence numbers don't match, + * send back a SYN ACK. (this doesn't sound right, + * does it? It's sort of what we do from LISTEN) + */ + + if (flags & TCPFLG_SYN) { + _tcp_sendctlmsg(ti,tcb,TCPFLG_SYN | TCPFLG_ACK,TCP_RETX_TIMER); + } + + /* + * If we got an ack and the acknum is correct, + * switch the state to 'ESTABLISHED' and cancel + * the timer. We're ready to rock. + */ + + if ((flags & TCPFLG_ACK) && + (acknum == (tcb->tcb_sendunack + 1))) { + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,0); + tcb->tcb_sendunack = acknum; + tcb->tcb_sendnext = tcb->tcb_sendunack; + TIMER_SET(tcb->tcb_timer_keep,TCP_KEEPALIVE_TIMER); + _tcp_setstate(tcb,TCPSTATE_ESTABLISHED); + } + + return ETH_DROP; + break; + + case TCPSTATE_ESTABLISHED: + case TCPSTATE_FINWAIT_1: + case TCPSTATE_FINWAIT_2: + + /* + * ESTABLISHED, FINWAIT_1, and FINWAIT_2 can all + * carry data. Process the data here. If the + * segment also contains a FIN, these routines + * will handle that. + */ + + if (flags & TCPFLG_ACK) { + _tcp_procack(ti,tcb,acknum,flags); + } + _tcp_procdata(ti,tcb,seqnum,flags,buf); + break; + + case TCPSTATE_CLOSING: + if (acknum == (tcb->tcb_sendunack + 1)) { + _tcp_setstate(tcb,TCPSTATE_TIME_WAIT); + _tcp_canceltimers(tcb); + TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER); + } + break; + + case TCPSTATE_LAST_ACK: + if (acknum == (tcb->tcb_sendunack + 1)) { + /* Ack matches, just close the TCB here. */ + _tcp_closetcb(ti,tcb); + /* and free it. */ + _tcp_freetcb(ti,tcb); + } + else { + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER); + } + break; + + case TCPSTATE_TIME_WAIT: + if (!(flags & TCPFLG_RST)) { + tcb->tcb_txflags = TCPFLG_ACK; + TIMER_SET(tcb->tcb_timer_2msl,TCP_TIMEWAIT_TIMER); + _tcp_protosend(ti,tcb); + } + break; + } + + /* + * If we're expected to transmit something, do it now. + */ + + if (tcb->tcb_flags & TCB_FLG_OUTPUT) { + _tcp_output(ti,tcb); + tcb->tcb_flags &= ~(TCB_FLG_OUTPUT | TCB_FLG_SENDMSG); + } + + if (tcb->tcb_flags & TCB_FLG_SENDMSG) { + _tcp_protosend(ti,tcb); + } + + /* We always make a copy of the data, so drop the packet. */ + return ETH_DROP; +} + +/* ********************************************************************* + * _tcp_fasttimo(ti) + * + * Handle "fast timeout" for active TCP sockets. + * + * Input parameters: + * ti - tcp_info structure + * + * Return value: + * nothing + ********************************************************************* */ +static void _tcp_fasttimo(tcp_info_t *ti) +{ + tcb_t *tcb; + queue_t *qb; + + /* + * First, reset the timer so we'll end up here + * again in another 200ms + */ + + TIMER_SET(ti->ti_fasttimer,TCP_FAST_TIMER); /* 200ms */ + + /* + * Now, walk down the list of TCBs and handle + * all the timers. + */ + + for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) { + tcb = (tcb_t *) qb; + if (tcb->tcb_flags & TCB_FLG_DLYACK) { + tcb->tcb_flags &= ~TCB_FLG_DLYACK; + _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,-1); + } + } + + /* + * While we're here, increment TCP's initial sequence number. + * BSD suggests 128000 every second, so we'll add 25600 every 200ms. + */ + + ti->ti_iss += 25600; + +} + + +/* ********************************************************************* + * _tcp_poll(arg) + * + * CFE calls this routine periodically to allow us to check + * and update timers, etc. + * + * Input parameters: + * arg - our tcp information (held by the timer module for us) + * + * Return value: + * nothing + ********************************************************************* */ + +void _tcp_poll(void *arg) +{ + tcb_t *tcb; + queue_t *qb; + tcp_info_t *ti = (tcp_info_t *) arg; + + /* + * Handle the "fast" timer. We do this every 200ms + */ + + if (TIMER_EXPIRED(ti->ti_fasttimer)) { + _tcp_fasttimo(ti); + /* timer will be reset by the _tcp_fasttimo routine */ + } + + /* + * Check the TCBs for the "slow" timers. + */ + + for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) { + tcb = (tcb_t *) qb; + + /* + * Check the retransmit timer. This is used during connection + * attempts to retransmit control messages, or also during + * regular data transfer to retransmit messages that are not + * acknowledged. + * + * XXX use the computed round-trip timer here + */ + + if (TIMER_EXPIRED(tcb->tcb_timer_retx)) { + TIMER_CLEAR(tcb->tcb_timer_retx); /* unless it is reset */ + + DEBUGMSG(("Retransmit timer expired, retrycnt=%d\n",tcb->tcb_retrycnt)); + + switch (tcb->tcb_state) { + case TCPSTATE_ESTABLISHED: + /* + * wind the send seqnum back to the last unacknowledged data, + * and send it out again. + */ + TIMER_SET(tcb->tcb_timer_retx,TCP_RETX_TIMER); + tcb->tcb_retrycnt++; + tcb->tcb_sendnext = tcb->tcb_sendunack; + _tcp_output(ti,tcb); + break; + + case TCPSTATE_SYN_SENT: + TIMER_SET(tcb->tcb_timer_retx,(TCP_RETX_TIMER << tcb->tcb_retrycnt)); + tcb->tcb_retrycnt++; + tcb->tcb_sendnext = tcb->tcb_sendunack; + _tcp_protosend(ti,tcb); + break; + + } + } + + /* + * Check the keepalive timer. This is used during connection + * attempts to time out the connection, and _can_ be used for + * keepalives during established sessions. + * + * Our TCP does not bother with keepalive messages. + */ + + if (TIMER_EXPIRED(tcb->tcb_timer_keep)) { + TIMER_CLEAR(tcb->tcb_timer_keep); /* unless it is reset */ + DEBUGMSG(("Keepalive timer expired in state %d\n",tcb->tcb_state)); + if (TCPSTATE_IN_SET(tcb->tcb_state,M_TCPSTATE_CONNINPROGRESS)) { + DEBUGMSG(("Canceling pending connection\n")); + _tcp_aborttcb(ti,tcb); + } + } + + /* + * Check the 2MSL timer. This is used in the TIME_WAIT state + * to return the tcb to the free list after the time wait + * period elapses. + */ + + if (TIMER_EXPIRED(tcb->tcb_timer_2msl)) { + TIMER_CLEAR(tcb->tcb_timer_2msl); /* will not be reset */ + DEBUGMSG(("2MSL timer expired in state %d\n",tcb->tcb_state)); + if (tcb->tcb_state == TCPSTATE_TIME_WAIT) { + DEBUGMSG(("Freeing TCB\n")); + _tcp_closetcb(ti,tcb); + _tcp_freetcb(ti,tcb); + } + } + + } + +} + + diff --git a/cfe/cfe/net/net_tcp.h b/cfe/cfe/net/net_tcp.h new file mode 100755 index 0000000..fa772e6 --- /dev/null +++ b/cfe/cfe/net/net_tcp.h @@ -0,0 +1,83 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TCP Protocol Definitions File: net_tcp.h + * + * This file contains TCP protocol-specific definitions + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * TCP Flags - keep in sync with net_api.h + ********************************************************************* */ + +#define TCPFLG_NODELAY 1 /* disable nagle */ +#define TCPFLG_NBIO 2 /* Non-blocking I/O */ + +#define TCPSTATUS_NOTCONN 0 +#define TCPSTATUS_CONNECTING 1 +#define TCPSTATUS_CONNECTED 2 + +/* ********************************************************************* + * TCP API + ********************************************************************* */ + +typedef struct tcp_info_s tcp_info_t; + +tcp_info_t *_tcp_init(ip_info_t *ipi,void *ref); +void _tcp_uninit(tcp_info_t *info); + +int _tcp_socket(tcp_info_t *info); +int _tcp_connect(tcp_info_t *ti,int s,uint8_t *dest,uint16_t port); +int _tcp_close(tcp_info_t *ti,int s); +int _tcp_send(tcp_info_t *ti,int s,uint8_t *buf,int len); +int _tcp_recv(tcp_info_t *ti,int s,uint8_t *buf,int len); +int _tcp_bind(tcp_info_t *ti,int s,uint16_t port); +int _tcp_peeraddr(tcp_info_t *ti,int s,uint8_t *addr,uint16_t *port); +int _tcp_listen(tcp_info_t *ti,int s,uint16_t port); +int _tcp_status(tcp_info_t *ti,int s,unsigned int *connflag,int *rxready,int *rxeof); +int _tcp_debug(tcp_info_t *ti,int s,int arg); +int _tcp_setflags(tcp_info_t *ti,int s,unsigned int flags); +int _tcp_getflags(tcp_info_t *ti,int s,unsigned int *flags); + +void _tcp_poll(void *arg); + + diff --git a/cfe/cfe/net/net_tcp_internal.h b/cfe/cfe/net/net_tcp_internal.h new file mode 100755 index 0000000..1e3fc6d --- /dev/null +++ b/cfe/cfe/net/net_tcp_internal.h @@ -0,0 +1,244 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TCP Protocol Internal Definitions File: net_tcp_internal.h + * + * This file contains the structures and constants needed to + * maintain TCP connections. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +/* ********************************************************************* + * TCP Constants + ********************************************************************* */ + + +#define TCP_MAX_PORTS 8 +#define TCP_MAX_TCBS 16 +#if defined(CONFIG_MIPS_BRCM) +#define TCP_BUF_SIZE (20 * 1024) +#else +#define TCP_BUF_SIZE 65536 +#endif + +#define TCP_MAX_SEG_SIZE 1400 + +#define TCP_CONNECT_TIMER (30*CFE_HZ) +#define TCP_RETX_TIMER (1*CFE_HZ) +#define TCP_TIMEWAIT_TIMER (30*CFE_HZ) +#define TCP_SEND_TIMER (CFE_HZ) + +#define TCP_FAST_TIMER (CFE_HZ/5) /* 200ms */ +#define TCP_KEEPALIVE_TIMER (CFE_HZ*60) /* one minute */ + + +/* ********************************************************************* + * TCP Protocol + ********************************************************************* */ + +#define TCPFLG_FIN 0x0001 +#define TCPFLG_SYN 0x0002 +#define TCPFLG_RST 0x0004 +#define TCPFLG_PSH 0x0008 +#define TCPFLG_ACK 0x0010 +#define TCPFLG_URG 0x0020 +#define TCPHDRSIZE(flg) (((flg) >> 12)*4) +#define TCPHDRFLG(size) (((size)/4)<<12) + +#define TCP_HDR_LENGTH 20 + +#define TCP_MAX_SEG_OPT 0x0204 + +/* ********************************************************************* + * TCP State machine + ********************************************************************* */ + +/* + * TCB states, see RFC + */ + +#define TCPSTATE_CLOSED 0 +#define TCPSTATE_LISTEN 1 +#define TCPSTATE_SYN_SENT 2 +#define TCPSTATE_SYN_RECEIVED 3 +#define TCPSTATE_ESTABLISHED 4 +#define TCPSTATE_CLOSE_WAIT 5 +#define TCPSTATE_FINWAIT_1 6 +#define TCPSTATE_FINWAIT_2 7 +#define TCPSTATE_CLOSING 8 +#define TCPSTATE_LAST_ACK 9 +#define TCPSTATE_TIME_WAIT 10 + +/* + * Masks for TCP states - we use these so we can make + * bit vectors of states for easy tests. + */ + +#define M_TCPSTATE_CLOSED (1 << TCPSTATE_CLOSED) +#define M_TCPSTATE_LISTEN (1 << TCPSTATE_LISTEN) +#define M_TCPSTATE_SYN_SENT (1 << TCPSTATE_SYN_SENT) +#define M_TCPSTATE_SYN_RECEIVED (1 << TCPSTATE_SYN_RECEIVED) +#define M_TCPSTATE_ESTABLISHED (1 << TCPSTATE_ESTABLISHED) +#define M_TCPSTATE_CLOSE_WAIT (1 << TCPSTATE_CLOSE_WAIT) +#define M_TCPSTATE_FINWAIT_1 (1 << TCPSTATE_FINWAIT_1) +#define M_TCPSTATE_FINWAIT_2 (1 << TCPSTATE_FINWAIT_2) +#define M_TCPSTATE_CLOSING (1 << TCPSTATE_CLOSING) +#define M_TCPSTATE_LAST_ACK (1 << TCPSTATE_LAST_ACK) +#define M_TCPSTATE_TIME_WAIT (1 << TCPSTATE_TIME_WAIT) +#define M_TCPSTATE_CLOSED (1 << TCPSTATE_CLOSED) + +/* + * This macro returns true if a given state is in a + * set of states (defined below) + */ + +#define TCPSTATE_IN_SET(state,set) ((1 << (state)) & (set)) + +/* + * Intresting groups of TCP states + */ + +/* ABORTSTATES - tcp_abort will send a RST if our TCB is one of these. */ +#define M_TCPSTATE_ABORTSTATES \ + M_TCPSTATE_SYN_SENT | M_TCPSTATE_SYN_RECEIVED | M_TCPSTATE_ESTABLISHED | \ + M_TCPSTATE_FINWAIT_1 | M_TCPSTATE_FINWAIT_2 | M_TCPSTATE_CLOSING | \ + M_TCPSTATE_LAST_ACK | M_TCPSTATE_CLOSE_WAIT + +/* SEND_OK - tcp_send will send data if our TCB is one of these */ +#define M_TCPSTATE_SEND_OK \ + M_TCPSTATE_ESTABLISHED | M_TCPSTATE_CLOSE_WAIT + +/* RECV_OK - tcp_recv will pass up data if our TCB is in one of these */ +#define M_TCPSTATE_RECV_OK \ + M_TCPSTATE_ESTABLISHED | M_TCPSTATE_CLOSE_WAIT + +/* PEERADDR_OK - tcp_peeraddr will return a value if TCB is in one of these */ +#define M_TCPSTATE_PEERADDR_OK \ + M_TCPSTATE_SYN_SENT | M_TCPSTATE_SYN_RECEIVED | M_TCPSTATE_ESTABLISHED | \ + M_TCPSTATE_FINWAIT_1 | M_TCPSTATE_FINWAIT_2 | M_TCPSTATE_CLOSING | \ + M_TCPSTATE_LAST_ACK | M_TCPSTATE_CLOSE_WAIT + +/* RESETKEEPALIVE - reset keepalive timer in these states */ +#define M_TCPSTATE_RESETKEEPALIVE \ + M_TCPSTATE_ESTABLISHED | M_TCPSTATE_CLOSE_WAIT | M_TCPSTATE_FINWAIT_1 | \ + M_TCPSTATE_FINWAIT_2 | M_TCPSTATE_CLOSING | M_TCPSTATE_LAST_ACK + +#define CONNINPROGRESS - connection is in progress in these states */ +#define M_TCPSTATE_CONNINPROGRESS \ + M_TCPSTATE_LISTEN | M_TCPSTATE_SYN_SENT | M_TCPSTATE_SYN_RECEIVED + + +/* + * TCP flags for the control block + */ + +#define TCB_FLG_OUTPUT 1 /* need to call tcp_output */ +#define TCB_FLG_SENDMSG 2 +#define TCB_FLG_DLYACK 4 /* delayed ack is pending */ + +/* ********************************************************************* + * TCP Control Block + ********************************************************************* */ + +typedef struct tcb_s { + queue_t tcb_qb; /* next/previous in list */ + int tcb_socknum; /* socket number, index into table */ + + int tcb_state; /* current connection state */ + + uint8_t tcb_peeraddr[IP_ADDR_LEN]; /* Peer's IP Address */ + uint16_t tcb_peerport; /* Peer's port address */ + uint16_t tcb_lclport; /* My port address */ + + uint16_t tcb_txflags; /* packet flags for next tx packet */ + + cfe_timer_t tcb_timer_2msl; /* 2MSL timer, used in TIME_WAIT */ + cfe_timer_t tcb_timer_keep; /* Timer for keepalives and connections */ + cfe_timer_t tcb_timer_retx; /* send retransmission timer */ + cfe_timer_t tcb_timer_pers; /* Persist timer */ + + int tcb_retrycnt; /* Retry counter */ + + int tcb_mtu; /* MTU if underlying link */ + unsigned int tcb_flags; /* Misc protocol flags */ + unsigned int tcb_sockflags; /* flags set by user api */ + + /* + * Buffers + */ + + tcpmodbuf_t tcb_txbuf; /* Transmit buffer */ + tcpmodbuf_t tcb_rxbuf; /* Receive buffer */ + + /* + * Send sequence variables + */ + + uint32_t tcb_sendunack; /* oldest unacknowledged seqnum */ + uint32_t tcb_sendnext; /* Next seqnum to send */ + uint32_t tcb_sendwindow; /* Last advertised send window */ + + /* + * Receive sequence variables + */ + + uint32_t tcb_rcvnext; /* next in-order receive seq num */ + uint32_t tcb_rcvack; /* last transmitted acknowledgement */ + + /* + * Window management variables + */ + int tcb_dup_ackcnt; /* Duplicate ack counter */ + +} tcb_t; + +/* ********************************************************************* + * Macros to muck with sequence numbers + ********************************************************************* */ + +#define TCPSEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define TCPSEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define TCPSEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define TCPSEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +#define TCPSEQ_DIFF(a,b) ((int)((a)-(b))) + diff --git a/cfe/cfe/net/net_tcpbuf.c b/cfe/cfe/net/net_tcpbuf.c new file mode 100644 index 0000000..08e690b --- /dev/null +++ b/cfe/cfe/net/net_tcpbuf.c @@ -0,0 +1,298 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TCP Protocol File: net_tcp.c + * + * This file contains a very simple TCP. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" + +#include "net_tcpbuf.h" + + + +/* ********************************************************************* + * tmb_init(buf) + * + * Initialize a modulo buffer's pointers to the "empty" state + * + * Input parameters: + * buf - modulo buffer structure + * + * Return value: + * nothing + ********************************************************************* */ + +void tmb_init(tcpmodbuf_t *buf) +{ + buf->tmb_addptr = 0; + buf->tmb_remptr = 0; + buf->tmb_len = 0; +} + +/* ********************************************************************* + * tmb_adjust(buf,amt) + * + * Move the "remove" pointer ahead by 'amt' without retrieving the + * data. + * + * Input parameters: + * buf - modulo buffer structure + * amt - number of bytes to move + * + * Return value: + * nothing + ********************************************************************* */ + + +void tmb_adjust(tcpmodbuf_t *buf,int amt) +{ + /* XXX should we check for moving to far? */ + buf->tmb_len -= amt; + buf->tmb_remptr = (buf->tmb_remptr + amt) % buf->tmb_bufsize; +} + +/* ********************************************************************* + * tmb_alloc(buf,size) + * + * Allocate memory for the modulo buffer. + * + * Input parameters: + * buf - modulo buffer structure + * size - size of data in modulo buffer + * + * Return value: + * 0 if ok + * -1 if error + ********************************************************************* */ + +int tmb_alloc(tcpmodbuf_t *buf,int size) +{ + buf->tmb_buf = KMALLOC(size,0); + if (!buf->tmb_buf) return -1; + buf->tmb_bufsize = size; + + tmb_init(buf); + + return 0; +} + +/* ********************************************************************* + * tmb_free(buf) + * + * Free memory associated with the modulo buffer + * + * Input parameters: + * buf - modulo buffer + * + * Return value: + * nothing + ********************************************************************* */ + +void tmb_free(tcpmodbuf_t *buf) +{ + if (buf->tmb_buf) KFREE(buf->tmb_buf); + buf->tmb_buf = NULL; +} + + +/* ********************************************************************* + * tmb_copyin(tmb,buf,len,update) + * + * Copy data into the modulo buffer at the 'add' pointer + * + * Input parameters: + * tmb - modulo buffer structure + * buf,len - buffer and length of buffer to copy in + * update - true to advance 'add' pointer (usually true for copyin) + * + * Return value: + * number of bytes actually added to the buffer + ********************************************************************* */ + +int tmb_copyin(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update) +{ + int maxlen; + int l; + int newptr; + int retlen; + + if (len == 0) return 0; + + /* Set 'maxlen' to the max # of bytes we will send now */ + maxlen = tmb->tmb_bufsize - tmb->tmb_len; + if (maxlen > len) maxlen = len; + + retlen = maxlen; /* we'll return this later. */ + + /* Copy the bytes into the buffer and deal with buffer wrap */ + l = tmb->tmb_bufsize - tmb->tmb_addptr; + if (l > maxlen) l = maxlen; + + memcpy(tmb->tmb_buf + tmb->tmb_addptr,buf,l); + maxlen -= l; + buf += l; + + if (maxlen) { + memcpy(tmb->tmb_buf,buf,maxlen); + newptr = maxlen; + } + else { + newptr = tmb->tmb_addptr + l; + } + + if (update) { + tmb->tmb_len += retlen; /* this many more in the buffer */ + tmb->tmb_addptr = newptr; + } + + return retlen; +} + +/* ********************************************************************* + * tmb_copyout(tmb,buf,len,update) + * + * Copy data out of the modulo buffer from the 'remove' pointer + * + * Input parameters: + * tmb - modulo buffer structure + * buf,len - buffer and length of buffer to copy out + * update - true to advance 'remove' pointer + * + * Return value: + * number of bytes actually removed from the buffer + ********************************************************************* */ + +int tmb_copyout(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update) +{ + int maxlen; + int l; + int newptr; + int retlen; + + /* Compute how many bytes to return */ + maxlen = tmb->tmb_len; + if (maxlen > len) maxlen = len; + + retlen = maxlen; + + l = tmb->tmb_bufsize - tmb->tmb_remptr; + if (l > maxlen) l = maxlen; + + memcpy(buf,tmb->tmb_buf + tmb->tmb_remptr,l); + buf += l; + maxlen -= l; + + if (maxlen) { + memcpy(buf,tmb->tmb_buf,maxlen); + newptr = maxlen; + } + else { + newptr = tmb->tmb_remptr + l; + } + + if (update) { + tmb->tmb_len -= retlen; + tmb->tmb_remptr = newptr; + } + + return retlen; +} + +/* ********************************************************************* + * tmb_copyout2(tmb,buf,offset,len) + * + * Copy data out of the modulo buffer from a specific offset from + * the remove pointer. This is done without updating the + * remove pointer - we use this to dig data out when segmenting + * packets for transmission. + * + * Input parameters: + * tmb - modulo buffer structure + * buf,len - buffer and length of buffer to copy out + * offset - offset from remove pointer to start + * + * Return value: + * number of bytes actually copied out of the buffer + ********************************************************************* */ + +int tmb_copyout2(tcpmodbuf_t *tmb,uint8_t *buf,int offset,int len) +{ + int maxlen; + int l; + int retlen; + int remptr; + + /* Compute how many bytes to return */ + maxlen = tmb->tmb_len - offset; + + /* if offset is beyond length, get out now. */ + if (maxlen <= 0) return 0; + + /* otherwise choose min(max_can_copy,max_to_copy) */ + if (maxlen > len) maxlen = len; + retlen = maxlen; + + /* Adjust remove pointer for offset */ + remptr = (tmb->tmb_remptr + offset) % tmb->tmb_bufsize; + + l = tmb->tmb_bufsize - remptr; + if (l > maxlen) l = maxlen; + + memcpy(buf,tmb->tmb_buf + remptr,l); + buf += l; + maxlen -= l; + + if (maxlen) { + memcpy(buf,tmb->tmb_buf,maxlen); + } + + return retlen; +} + diff --git a/cfe/cfe/net/net_tcpbuf.h b/cfe/cfe/net/net_tcpbuf.h new file mode 100644 index 0000000..0c251e3 --- /dev/null +++ b/cfe/cfe/net/net_tcpbuf.h @@ -0,0 +1,83 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TCP Protocol Definitions File: net_tcp.h + * + * This file contains TCP protocol-specific definitions + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define tmb_remlen(tmb) ((tmb)->tmb_bufsize - (tmb)->tmb_len) +#define tmb_curlen(tmb) ((tmb)->tmb_len) + + +/* ********************************************************************* + * Modulo Buffer + ********************************************************************* */ + +typedef struct tcpmodbuf_s { + uint8_t *tmb_buf; /* Buffer */ + int tmb_bufsize; /* size of buffer */ + int tmb_addptr; /* current "add" pointer */ + int tmb_remptr; /* current "remove" pointer */ + int tmb_len; /* amount of data in the buffer */ +} tcpmodbuf_t; + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +void tmb_init(tcpmodbuf_t *buf); +void tmb_adjust(tcpmodbuf_t *buf,int amt); +int tmb_alloc(tcpmodbuf_t *buf,int size); +void tmb_free(tcpmodbuf_t *buf); +int tmb_copyin(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update); +int tmb_copyout(tcpmodbuf_t *tmb,uint8_t *buf,int len,int update); +int tmb_copyout2(tcpmodbuf_t *tmb,uint8_t *buf,int offset,int len); + + + + + diff --git a/cfe/cfe/net/net_tftp.c b/cfe/cfe/net/net_tftp.c new file mode 100644 index 0000000..1c3e799 --- /dev/null +++ b/cfe/cfe/net/net_tftp.c @@ -0,0 +1,921 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TFTP Client File: net_tftp.c + * + * This module contains a TFTP client. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#include "cfe_console.h" +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "cfe.h" + +#include "cfe_loader.h" + +#include "net_api.h" + + + +/* ********************************************************************* + * TFTP protocol + ********************************************************************* */ + +#define UDP_PROTO_TFTP 69 + +#define TFTP_BLOCKSIZE 512 + +#define TFTP_OP_RRQ 1 +#define TFTP_OP_WRQ 2 +#define TFTP_OP_DATA 3 +#define TFTP_OP_ACK 4 +#define TFTP_OP_ERROR 5 + +#define TFTP_ERR_DISKFULL 3 + +#define TFTP_MAX_RETRIES 8 + +#define TFTP_RRQ_TIMEOUT 1 /* seconds */ +#define TFTP_RECV_TIMEOUT 1 /* seconds */ + +/* ********************************************************************* + * TFTP context + ********************************************************************* */ + +typedef struct tftp_fsctx_s { + int dummy; +} tftp_fsctx_t; + +typedef struct tftp_info_s { + int tftp_socket; + uint8_t tftp_data[TFTP_BLOCKSIZE]; + int tftp_blklen; + int tftp_blkoffset; + int tftp_fileoffset; + uint16_t tftp_blknum; + uint8_t tftp_ipaddr[IP_ADDR_LEN]; + int tftp_lastblock; + int tftp_error; + int tftp_filemode; + char *tftp_filename; +} tftp_info_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int tftp_fileop_init(void **fsctx,void *devicename); +static int tftp_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int tftp_fileop_read(void *ref,uint8_t *buf,int len); +static int tftp_fileop_write(void *ref,uint8_t *buf,int len); +static int tftp_fileop_seek(void *ref,int offset,int how); +static void tftp_fileop_close(void *ref); +static void tftp_fileop_uninit(void *fsctx); + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +int tftp_max_retries = TFTP_MAX_RETRIES; +int tftp_rrq_timeout = TFTP_RRQ_TIMEOUT; +int tftp_recv_timeout = TFTP_RECV_TIMEOUT; +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +/* ********************************************************************* + * TFTP fileio dispatch table + ********************************************************************* */ + +const fileio_dispatch_t tftp_fileops = { + "tftp", + LOADFLG_NOBB | FSYS_TYPE_NETWORK, + tftp_fileop_init, + tftp_fileop_open, + tftp_fileop_read, + tftp_fileop_write, + tftp_fileop_seek, + tftp_fileop_close, + tftp_fileop_uninit +}; + + +/* ********************************************************************* + * _tftp_open(info,hostname,filename,mode) + * + * Open a file on a remote host, using the TFTP protocol. + * + * Input parameters: + * info - TFTP information + * hostname - host name or IP address of remote host + * filename - name of file on remote system + * mode - file open mode, read or write + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int _tftp_open(tftp_info_t *info,char *hostname,char *filename,int mode) +{ + ebuf_t *buf = NULL; + const char *datamode = "octet"; + uint16_t type,error,block; + int res; + int retries; + + /* + * Look up the remote host's IP address + */ + + res = dns_lookup(hostname,info->tftp_ipaddr); + if (res < 0) return res; + + /* + * Open a UDP socket to the TFTP server + */ + + info->tftp_socket = udp_socket(UDP_PROTO_TFTP); + info->tftp_lastblock = 0; + info->tftp_error = 0; + info->tftp_filemode = mode; + + /* + * Try to send the RRQ packet to open the file + */ + + for (retries = 0; retries < TFTP_MAX_RETRIES; retries++) { + + buf = udp_alloc(); + if (!buf) break; + + if (info->tftp_filemode == FILE_MODE_READ) { + ebuf_append_u16_be(buf,TFTP_OP_RRQ); /* read file */ + } + else { + ebuf_append_u16_be(buf,TFTP_OP_WRQ); /* write file */ + } + ebuf_append_bytes(buf,filename,strlen(filename)+1); + ebuf_append_bytes(buf,datamode,strlen(datamode)+1); + + udp_send(info->tftp_socket,buf,info->tftp_ipaddr); + + buf = udp_recv_with_timeout(info->tftp_socket,TFTP_RRQ_TIMEOUT); + if (buf) break; + } + + /* + * If we got no response, bail now. + */ + + if (!buf) { + udp_close(info->tftp_socket); + info->tftp_socket = -1; + return CFE_ERR_TIMEOUT; + } + + /* + * Otherwise, process the response. + */ + + ebuf_get_u16_be(buf,type); + + switch (type) { + case TFTP_OP_ACK: + /* + * Acks are what we get back on a WRQ command, + * but are otherwise unexpected. + */ + if (info->tftp_filemode == FILE_MODE_WRITE) { + udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata); + info->tftp_blknum = 1; + info->tftp_blklen = 0; + udp_free(buf); + return 0; + break; + } + /* fall through */ + case TFTP_OP_RRQ: + case TFTP_OP_WRQ: + default: + /* + * we aren't expecting any of these messages + */ + udp_free(buf); + udp_close(info->tftp_socket); + info->tftp_socket = -1; + return CFE_ERR_PROTOCOLERR; + + case TFTP_OP_ERROR: + /* + * Process the error return (XXX: remove xprintf here) + */ + ebuf_get_u16_be(buf,error); + xprintf("TFTP error %d: %s\n",error,ebuf_ptr(buf)); + udp_free(buf); + udp_close(info->tftp_socket); + info->tftp_socket = -1; + return CFE_ERR_PROTOCOLERR; + + case TFTP_OP_DATA: + /* + * Yay, we've got data! Store the first block. + */ + ebuf_get_u16_be(buf,block); + udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata); + info->tftp_blknum = block; + info->tftp_blklen = ebuf_length(buf); + ebuf_get_bytes(buf,info->tftp_data,ebuf_length(buf)); + udp_free(buf); + if (info->tftp_blklen < TFTP_BLOCKSIZE) { + info->tftp_lastblock = 1; /* EOF */ + } + return 0; + break; + + } +} + + +/* ********************************************************************* + * _tftp_readmore(info) + * + * Read the next block of the file. We do this by acking the + * previous block. Once that block is acked, the TFTP server + * should send the next block to us. + * + * Input parameters: + * info - TFTP information + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int _tftp_readmore(tftp_info_t *info) +{ + ebuf_t *buf; + uint16_t cmd,block; + int retries; + + /* + * If we've already read the last block, there is no more + */ + + if (info->tftp_lastblock) return 1; + if (info->tftp_error) return CFE_ERR_TIMEOUT; + + /* + * Otherwise, ack the current block so another one will come + */ + + for (retries = 0; retries < TFTP_MAX_RETRIES; retries++) { + + buf = udp_alloc(); + if (!buf) return -1; + + /* + * Send the ack + */ + + ebuf_append_u16_be(buf,TFTP_OP_ACK); + ebuf_append_u16_be(buf,info->tftp_blknum); + udp_send(info->tftp_socket,buf,info->tftp_ipaddr); + + /* + * Wait for some response, retransmitting as necessary + */ + + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + buf = udp_recv_with_timeout(info->tftp_socket,tftp_recv_timeout); + // buf = udp_recv_with_timeout(info->tftp_socket,TFTP_RECV_TIMEOUT); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + if (buf == NULL) continue; + + /* + * Got a response, make sure it's right + */ + + ebuf_get_u16_be(buf,cmd); + if (cmd != TFTP_OP_DATA) { + udp_free(buf); + continue; + } + + ebuf_get_u16_be(buf,block); + if (block != (info->tftp_blknum+1)) { + udp_free(buf); + continue; + } + + /* + * It's the correct response. Copy the user data + */ + + info->tftp_blknum = block; + info->tftp_blklen = ebuf_length(buf); + ebuf_get_bytes(buf,info->tftp_data,ebuf_length(buf)); + udp_free(buf); + break; + } + + /* + * If the block is less than 512 bytes long, it's the EOF block. + */ + + if (retries == TFTP_MAX_RETRIES) { + info->tftp_error = 1; + return CFE_ERR_TIMEOUT; + } + + if (info->tftp_blklen < TFTP_BLOCKSIZE) { + info->tftp_lastblock = 1; /* EOF */ + } + + return 0; +} + +/* ********************************************************************* + * _tftp_writemore(info) + * + * Write the next block of the file, sending the data from our + * holding buffer. Note that the holding buffer must be full + * or else we consider this to be an EOF. + * + * Input parameters: + * info - TFTP information + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int _tftp_writemore(tftp_info_t *info) +{ + ebuf_t *buf; + uint16_t cmd,block,error; + int retries; + + /* + * If we've already written the last block, there is no more + */ + + if (info->tftp_lastblock) return 1; + if (info->tftp_error) return CFE_ERR_TIMEOUT; + + /* + * Otherwise, send a block + */ + + for (retries = 0; retries < TFTP_MAX_RETRIES; retries++) { + + buf = udp_alloc(); + if (!buf) return -1; + + /* + * Send the data + */ + + ebuf_append_u16_be(buf,TFTP_OP_DATA); + ebuf_append_u16_be(buf,info->tftp_blknum); + ebuf_append_bytes(buf,info->tftp_data,info->tftp_blklen); + udp_send(info->tftp_socket,buf,info->tftp_ipaddr); + + /* + * Wait for some response, retransmitting as necessary + */ + + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + buf = udp_recv_with_timeout(info->tftp_socket, tftp_recv_timeout); + // buf = udp_recv_with_timeout(info->tftp_socket,TFTP_RECV_TIMEOUT); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + if (buf == NULL) continue; + + /* + * Got a response, make sure it's right + */ + + ebuf_get_u16_be(buf,cmd); + + if (cmd == TFTP_OP_ERROR) { + /* + * Process the error return (XXX: remove xprintf here) + */ + ebuf_get_u16_be(buf,error); + xprintf("TFTP write error %d: %s\n",error,ebuf_ptr(buf)); + info->tftp_error = 1; + info->tftp_lastblock = 1; + udp_free(buf); + return CFE_ERR_IOERR; + } + + if (cmd != TFTP_OP_ACK) { + udp_free(buf); + continue; + } + + ebuf_get_u16_be(buf,block); + if (block != (info->tftp_blknum)) { + udp_free(buf); + continue; + } + + /* + * It's the correct response. Update the block # + */ + + info->tftp_blknum++; + if (info->tftp_blklen != TFTP_BLOCKSIZE) info->tftp_lastblock = 1; + udp_free(buf); + break; + } + + /* + * If we had some failure, mark the stream with an error + */ + + if (retries == TFTP_MAX_RETRIES) { + info->tftp_error = 1; + return CFE_ERR_TIMEOUT; + } + + return 0; +} + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +static int _tftpd_open(tftp_info_t *info,char *hostname,char *filename,int mode) +{ + ebuf_t *buf = NULL; + uint16_t type; + int res; + int retries; + char ch = 0; + + /* + * * Open a UDP socket + * */ + + info->tftp_socket = udp_socket(UDP_PROTO_TFTP); + info->tftp_lastblock = 0; + info->tftp_error = 0; + info->tftp_filemode = mode; + + /* + * * Listen for requests + * */ + + res = udp_bind(info->tftp_socket,UDP_PROTO_TFTP); + if (res < 0) return res; + + res = CFE_ERR_TIMEOUT; + + for (retries = 0; retries < tftp_max_retries; retries++) { + while (console_status()) { + console_read(&ch,1); + if (ch == 3) break; + } + + if (ch == 3) { + res = CFE_ERR_INTR; + break; + } + + buf = udp_recv_with_timeout(info->tftp_socket,tftp_recv_timeout); + if (buf == NULL) continue; + + /* + * * Process the request + * */ + + ebuf_get_u16_be(buf,type); + + switch (type) { + case TFTP_OP_RRQ: + udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata); + memcpy(info->tftp_ipaddr,buf->eb_usrptr,IP_ADDR_LEN); + info->tftp_blknum = 1; + info->tftp_blklen = 0; + res = 0; + break; + + case TFTP_OP_WRQ: + udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata); + memcpy(info->tftp_ipaddr,buf->eb_usrptr,IP_ADDR_LEN); + info->tftp_blknum = 0; + res = _tftp_readmore(info); + break; + + default: + /* + * aren't expecting any of these messages + * */ + res = CFE_ERR_PROTOCOLERR; + break; + } + + udp_free(buf); + break; + } + + if (res) { + udp_close(info->tftp_socket); + info->tftp_socket = -1; + } + + return res; +} + + +/* ********************************************************************* + * _tftp_close(info) + * + * Close a TFTP file. There are two cases for what we do + * here. If we're closing the file mid-stream, send an error + * packet to tell the host we're getting out early. Otherwise, + * just ack the final packet and the connection will close + * gracefully. + * + * Input parameters: + * info - TFTP info + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int _tftp_close(tftp_info_t *info) +{ + ebuf_t *buf; + const char *emsg = "transfer cancelled"; /* some error message */ + + if (info->tftp_socket == -1) return 0; + + if (info->tftp_filemode == FILE_MODE_READ) { + buf = udp_alloc(); + if (buf) { + /* If we're on the EOF packet, just send an ack */ + if (info->tftp_lastblock) { + ebuf_append_u16_be(buf,TFTP_OP_ACK); + ebuf_append_u16_be(buf,info->tftp_blknum); + } + else { + ebuf_append_u16_be(buf,TFTP_OP_ERROR); + ebuf_append_u16_be(buf,TFTP_ERR_DISKFULL); + ebuf_append_bytes(buf,emsg,strlen(emsg)+1); + } + udp_send(info->tftp_socket,buf,info->tftp_ipaddr); + } + } + else { + /* Just flush out the remaining write data, if any */ + _tftp_writemore(info); + } + + udp_close(info->tftp_socket); + info->tftp_socket = -1; + return 0; +} + + + +/* ********************************************************************* + * tftp_fileop_init(fsctx,device) + * + * Create a file system device context for the TFTP service + * + * Input parameters: + * fsctx - location to place context information + * device - underlying device (unused) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int tftp_fileop_init(void **fsctx,void *dev) +{ + void *ref; + + ref = KMALLOC(sizeof(tftp_fsctx_t),0); + + if (!ref) return CFE_ERR_NOMEM; + *fsctx = ref; + return 0; +} + +/* ********************************************************************* + * tftp_fileop_open(ref,fsctx,filename,mode) + * + * This is the filesystem entry point for opening a TFTP file. + * Allocate a tftp_info structure, open the TFTP file, and + * return a handle. + * + * Input parameters: + * ref - location to place reference data (the TFTP structure) + * fsctx - filesystem context + * filename - name of remote file to open + * mode - FILE_MODE_READ or FILE_MODE_WRITE + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int tftp_fileop_open(void **ref,void *fsctx,char *filename,int mode) +{ + tftp_info_t *info; + char *host; + char *file; + int res; + + if ((mode != FILE_MODE_READ) && (mode != FILE_MODE_WRITE)) { + /* must be either read or write, not both */ + return CFE_ERR_UNSUPPORTED; + } + + /* Allocate the tftp info structure */ + + info = KMALLOC(sizeof(tftp_info_t),0); + if (!info) { + return CFE_ERR_NOMEM; + } + + + info->tftp_filename = lib_strdup(filename); + if (!info->tftp_filename) { + KFREE(info); + return CFE_ERR_NOMEM; + } + + lib_chop_filename(info->tftp_filename,&host,&file); + + /* Open the file */ + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + if (!*host && !*file) { + /* TFTP server if hostname and filename are not specified */ + res = _tftpd_open(info,host,file,mode); + } else { + res = _tftp_open(info,host,file,mode); + } + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + if (res == 0) { + info->tftp_blkoffset = 0; + info->tftp_fileoffset = 0; + *ref = info; + } + else { + KFREE(info->tftp_filename); + KFREE(info); + *ref = NULL; + } + return res; +} + +/* ********************************************************************* + * tftp_fileop_read(ref,buf,len) + * + * Read some bytes from the remote TFTP file. Do this by copying + * data from the block buffer, and reading more data from the + * remote file as necessary. + * + * Input parameters: + * ref - tftp_info structure + * buf - destination buffer address (NULL to read data and + * not copy it anywhere) + * len - number of bytes to read + * + * Return value: + * number of bytes read, 0 for EOF, <0 if an error occured. + ********************************************************************* */ + +static int tftp_fileop_read(void *ref,uint8_t *buf,int len) +{ + tftp_info_t *info = (tftp_info_t *) ref; + int copied = 0; + int amtcopy; + int res; + + if (info->tftp_error) return CFE_ERR_IOERR; + if (info->tftp_filemode == FILE_MODE_WRITE) return CFE_ERR_UNSUPPORTED; + + while (len) { + + if (info->tftp_blkoffset >= info->tftp_blklen) break; + amtcopy = len; + + if (amtcopy > (info->tftp_blklen-info->tftp_blkoffset)) { + amtcopy = (info->tftp_blklen-info->tftp_blkoffset); + } + + if (buf) { + memcpy(buf,&(info->tftp_data[info->tftp_blkoffset]),amtcopy); + buf += amtcopy; + } + + info->tftp_blkoffset += amtcopy; + len -= amtcopy; + info->tftp_fileoffset += amtcopy; + copied += amtcopy; + + if (info->tftp_blkoffset >= info->tftp_blklen) { + res = _tftp_readmore(info); + if (res != 0) break; + info->tftp_blkoffset = 0; + } + } + + return copied; +} + +/* ********************************************************************* + * tftp_fileop_write(ref,buf,len) + * + * Write some bytes to the remote TFTP file. Do this by copying + * data to the block buffer, and writing data to the + * remote file as necessary. + * + * Input parameters: + * ref - tftp_info structure + * buf - source buffer address + * len - number of bytes to write + * + * Return value: + * number of bytes written, 0 for EOF, <0 if an error occured. + ********************************************************************* */ + +static int tftp_fileop_write(void *ref,uint8_t *buf,int len) +{ + tftp_info_t *info = (tftp_info_t *) ref; + int copied = 0; + int amtcopy; + int res; + + if (info->tftp_error) return CFE_ERR_IOERR; + if (info->tftp_filemode == FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + while (len) { + + amtcopy = len; + if (amtcopy > (TFTP_BLOCKSIZE - info->tftp_blklen)) { + amtcopy = (TFTP_BLOCKSIZE - info->tftp_blklen); + } + + memcpy(&(info->tftp_data[info->tftp_blklen]),buf,amtcopy); + buf += amtcopy; + + info->tftp_blklen += amtcopy; + len -= amtcopy; + info->tftp_fileoffset += amtcopy; + copied += amtcopy; + + if (info->tftp_blklen == TFTP_BLOCKSIZE) { + res = _tftp_writemore(info); + if (res != 0) { + break; + } + info->tftp_blklen = 0; + } + } + + return copied; +} + +/* ********************************************************************* + * tftp_fileop_seek(ref,offset,how) + * + * Seek within a TFTP file. Note that you can only seek *forward*, + * as TFTP doesn't really let you go backwards. (I suppose you + * could reopen the file, but thus far nobody needs to go + * backwards). You can only seek in a file in read mode. + * + * Input parameters: + * ref - our tftp information + * offset - distance to move + * how - how to move, (FILE_SEEK_*) + * + * Return value: + * new offset, or <0 if an error occured. + ********************************************************************* */ + +static int tftp_fileop_seek(void *ref,int offset,int how) +{ + tftp_info_t *info = (tftp_info_t *) ref; + int delta; + int startloc; + int res; + + if (info->tftp_filemode == FILE_MODE_WRITE) return CFE_ERR_UNSUPPORTED; + + switch (how) { + case FILE_SEEK_BEGINNING: + startloc = info->tftp_fileoffset; + break; + case FILE_SEEK_CURRENT: + startloc = 0; + break; + default: + startloc = 0; + break; + } + + delta = offset - startloc; + if (delta < 0) { + xprintf("Warning: negative seek on tftp file attempted\n"); + return CFE_ERR_UNSUPPORTED; + } + res = tftp_fileop_read(ref,NULL,delta); + if (res < 0) return res; + + return info->tftp_fileoffset; +} + + +/* ********************************************************************* + * tftp_fileop_close(ref) + * + * Close the TFTP file. + * + * Input parameters: + * ref - our TFTP info + * + * Return value: + * nothing + ********************************************************************* */ + +static void tftp_fileop_close(void *ref) +{ + tftp_info_t *info = (tftp_info_t *) ref; + + _tftp_close(info); + + KFREE(info->tftp_filename); + KFREE(info); +} + + +/* ********************************************************************* + * tftp_fileop_uninit(fsctx) + * + * Uninitialize the filesystem context, freeing allocated + * resources. + * + * Input parameters: + * fsctx - our context + * + * Return value: + * nothing + ********************************************************************* */ + +static void tftp_fileop_uninit(void *fsctx) +{ + KFREE(fsctx); +} diff --git a/cfe/cfe/net/net_udp.c b/cfe/cfe/net/net_udp.c new file mode 100644 index 0000000..968081a --- /dev/null +++ b/cfe/cfe/net/net_udp.c @@ -0,0 +1,637 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * User Datagram Protocol File: net_udp.c + * + * This module implements the User Datagram Protocol (RFCxxxx) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_ip.h" + +#include "cfe_error.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define UDP_HDR_LENGTH 8 +#define UDP_PORTBASE 1024 +#define UDP_MAX_PORTS 4 + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef struct udp_port_s udp_port_t; + +/* + * UDP port structure - describes an open UDP port. + */ + +struct udp_port_s { + uint16_t up_destport; /* destination port number */ + uint16_t up_srcport; /* source port number */ + queue_t up_rxqueue; /* queue of received packets */ + int up_maxqueue; /* max # of elements on rx queue */ + int up_inuse; /* nonzero if port is in use */ +}; + + +/* + * UDP stack information - describes the entire UDP layer. + */ + +struct udp_info_s { + uint16_t ui_portbase; + void *ui_ref; + ip_info_t *ui_ipinfo; + udp_port_t ui_ports[UDP_MAX_PORTS]; +}; + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + +static int _udp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr); + + +/* ********************************************************************* + * udp_find_port(info,port) + * + * Locate an open port. Scan the list of ports looking for one + * that is both open and has a matching source port number. + * + * Input parameters: + * info - UDP stack information + * port - source port # we're looking for + * + * Return value: + * udp_port_t pointer or NULL if no port was found + ********************************************************************* */ + +static udp_port_t *_udp_find_port(udp_info_t *info,uint16_t port) +{ + int idx; + udp_port_t *udp = info->ui_ports; + + for (idx = 0; idx < UDP_MAX_PORTS; idx++) { + if (udp->up_inuse && (udp->up_srcport == port)) { + return udp; + } + udp++; + } + + return NULL; +} + +/* ********************************************************************* + * _udp_socket(info,port) + * + * Open a UDP socket. This is an internal function used by + * the network API layer. + * + * Input parameters: + * info - UDP stack information + * port - port number to open + * + * Return value: + * port number (0 based) or an error code (<0) if an error + * occured. + ********************************************************************* */ + +int _udp_socket(udp_info_t *info,uint16_t port) +{ + extern int32_t _getticks(void); /* return value of CP0 COUNT */ + int idx; + udp_port_t *udp; + uint16_t srcport = UDP_PORTBASE + (_getticks() & 0xFFF); + + while (_udp_find_port(info,srcport)) { /* should always exit */ + srcport++; + if (srcport > (UDP_PORTBASE+4096)) srcport = UDP_PORTBASE; + } + + udp = info->ui_ports; + + for (idx = 0; idx < UDP_MAX_PORTS; idx++) { + if (!udp->up_inuse) break; + udp++; + } + + if (idx == UDP_MAX_PORTS) return CFE_ERR_NOHANDLES; + + udp->up_destport = port; + udp->up_srcport = srcport; + udp->up_maxqueue = 2; + udp->up_inuse = TRUE; + q_init(&(udp->up_rxqueue)); + + return idx; +} + + +/* ********************************************************************* + * _udp_close(info,s) + * + * Internal function to close an open UDP port. This routine is + * called by the high-level network API. + * + * Input parameters: + * info - UDP stack information + * s - an open UDP socket handle (returned from _udp_open) + * + * Return value: + * nothing + ********************************************************************* */ + +void _udp_close(udp_info_t *info,int s) +{ + udp_port_t *udp = &(info->ui_ports[s]); + ebuf_t *buf; + + while ((buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue)))) { + _ip_free(info->ui_ipinfo,buf); + } + + udp->up_srcport = 0; + udp->up_destport = 0; + udp->up_maxqueue = 0; + udp->up_inuse = FALSE; +} + +/* ********************************************************************* + * _udp_send(info,s,buf,dest) + * + * Transmit a UDP datagram. Note that we never send fragmented + * datagrams, so all datagrams must be less than the MTU. + * + * Input parameters: + * info - UDP stack information + * s - an open UDP socket handle (returned from _udp_open) + * buf - an ebuf to send + * dest - destination IP address + * + * Return value: + * 0 if packet was sent + * else error code + ********************************************************************* */ + +int _udp_send(udp_info_t *info,int s,ebuf_t *buf,uint8_t *dest) +{ + udp_port_t *udp = &(info->ui_ports[s]); + uint8_t *udphdr; + int udplen; + uint8_t pseudoheader[12]; + uint16_t cksum; + + /* + * Calculate the length of the IP datagram (includes UDP header) + */ + + udplen = ebuf_length(buf) + UDP_HDR_LENGTH; + + /* + * Build the pseudoheader, which is part of the checksum calculation + */ + + _ip_getaddr(info->ui_ipinfo,&pseudoheader[0]); + memcpy(&pseudoheader[4],dest,IP_ADDR_LEN); + pseudoheader[8] = 0; + pseudoheader[9] = IPPROTO_UDP; + pseudoheader[10] = (udplen >> 8) & 0xFF; + pseudoheader[11] = (udplen & 0xFF); + + /* + * Back up and build the actual UDP header in the packet + */ + + ebuf_seek(buf,-UDP_HDR_LENGTH); + udphdr = ebuf_ptr(buf); + + ebuf_put_u16_be(buf,udp->up_srcport); + ebuf_put_u16_be(buf,udp->up_destport); + ebuf_put_u16_be(buf,udplen); + ebuf_put_u16_be(buf,0); + + ebuf_prepend(buf,UDP_HDR_LENGTH); + + /* + * Checksum the packet and insert the checksum into the header + */ + + cksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader)); + cksum = ip_chksum(cksum,udphdr,udplen); + cksum = ~cksum; + if (cksum == 0) cksum = 0xFFFF; + udphdr[6] = (cksum >> 8) & 0xFF; + udphdr[7] = (cksum & 0xFF); + + /* + * Off it goes! + */ + + _ip_send(info->ui_ipinfo,buf,dest,IPPROTO_UDP); + + return 0; +} + +/* ********************************************************************* + * _udp_bind(info,s,port) + * + * Bind a UDP socket to a particular port number. Basically, + * all this means is we set the "source" port number. + * + * Input parameters: + * info - UDP stack information + * s - an open UDP socket (from _udp_open) + * port - port number to assign to the UDP socket + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int _udp_bind(udp_info_t *info,int s,uint16_t port) +{ + udp_port_t *udp = &(info->ui_ports[s]); + + if (_udp_find_port(info,port)) return CFE_ERR_ALREADYBOUND; + + udp->up_srcport = port; + + return 0; +} + + +/* ********************************************************************* + * _udp_connect(info,s,port) + * + * "connect" a UDP socket to a particular port number. Basically, + * this just sets the "destination" port number. It is used for + * protocols like TFTP where the destination port number changes + * after the port is open. + * + * Input parameters: + * info - UDP stack information + * s - an open UDP socket (from _udp_open) + * port - port number to assign to the UDP socket + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int _udp_connect(udp_info_t *info,int s,uint16_t port) +{ + udp_port_t *udp = &(info->ui_ports[s]); + + udp->up_destport = port; + + return 0; +} + +/* ********************************************************************* + * _udp_rx_callback(ref,buf,destaddr,srcaddr) + * + * Receive callback routine from the IP layer. When an IP + * packet of protocol type "UDP" is received, this routine gets + * called. + * + * Input parameters: + * ref - reference data (pointer to our UDP stack info) + * buf - the ebuf, currently pointing at the UDP header + * destaddr - the destination IP address (usually our IP address) + * srcaddr - the source IP address + * + * Return value: + * ETH_KEEP to keep (not deallocate) the packet + * ETH_DROP to deallocate the packet. + ********************************************************************* */ + +static int _udp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr) +{ + uint8_t pseudoheader[12]; + int udplen; + uint16_t calccksum; + uint16_t origcksum; + uint8_t *udphdr; + uint16_t srcport; + uint16_t dstport; + uint16_t udplen2; + udp_port_t *udp; + udp_info_t *info = (udp_info_t *) ref; + + + + /* + * get a pointer to the UDP header + */ + + udplen = ebuf_length(buf); + udphdr = ebuf_ptr(buf); + + /* + * see if we are checking checksums (cksum field != 0) + */ + + if ((udphdr[6] | udphdr[7]) != 0) { + + /* + * construct the pseudoheader for the cksum calculation + */ + + memcpy(&pseudoheader[0],srcaddr,IP_ADDR_LEN); + memcpy(&pseudoheader[4],destaddr,IP_ADDR_LEN); + pseudoheader[8] = 0; + pseudoheader[9] = IPPROTO_UDP; + pseudoheader[10] = (udplen >> 8) & 0xFF; + pseudoheader[11] = (udplen & 0xFF); + + origcksum = ((uint16_t) udphdr[6] << 8) | (uint16_t) udphdr[7]; + udphdr[6] = udphdr[7] = 0; + + calccksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader)); + calccksum = ip_chksum(calccksum,udphdr,udplen); + if (calccksum != 0xffff) { + calccksum = ~calccksum; + } + + if (calccksum != origcksum) { + return ETH_DROP; + } + } + + /* Read the other UDP header fields from the packet */ + + ebuf_get_u16_be(buf,srcport); + ebuf_get_u16_be(buf,dstport); + ebuf_get_u16_be(buf,udplen2); + ebuf_skip(buf,2); + + /* + * It's no good if the lengths don't match. The length + * reported by IP should be the length in the UDP header + 8 + */ + + if (udplen2 != (uint16_t) udplen) { + return ETH_DROP; + } + + /* + * Okay, start looking for a matching port + */ + + udp = _udp_find_port(info,dstport); + if (!udp) { + return ETH_DROP; /* drop packet if no matching port */ + /* XXX should send ICMP message here */ + } + + buf->eb_usrdata = (int) srcport; + buf->eb_usrptr = srcaddr; + + /* + * Drop packet if queue is full + */ + + if (q_count(&(udp->up_rxqueue)) >= udp->up_maxqueue) { + return ETH_DROP; + } + + /* + * Add to receive queue + */ + + ebuf_setlength(buf,udplen2-UDP_HDR_LENGTH); + q_enqueue(&(udp->up_rxqueue),(queue_t *) buf); + + return ETH_KEEP; +} + + +/* ********************************************************************* + * _udp_recv(info,s) + * + * Receive a packet from the specified UDP socket. + * + * Input parameters: + * info - UDP stack information + * s - an open UDP socket handle (from _udp_open) + * + * Return value: + * an ebuf, or NULL if no packets have been received. + ********************************************************************* */ + +ebuf_t *_udp_recv(udp_info_t *info,int s) +{ + ebuf_t *buf; + udp_port_t *udp = &(info->ui_ports[s]); + + buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue)); + + return buf; +} + + +/* ********************************************************************* + * _udp_init(ipi,ref) + * + * Initialize the UDP module. This routine registers our + * protocol with the IP layer. + * + * Input parameters: + * ipi - IP information (including our IP address, etc.) + * ref - reference data, stored in our UDP stack structure + * + * Return value: + * udp_info_t (allocated) or NULL if something went wrong. + ********************************************************************* */ + +udp_info_t *_udp_init(ip_info_t *ipi,void *ref) +{ + udp_info_t *info; + udp_port_t *udp; + int idx; + + /* + * Allocate some memory for our structure + */ + + info = KMALLOC(sizeof(udp_info_t),0); + + if (info == NULL) return NULL; + + memset(info,0,sizeof(udp_info_t)); + + /* + * Fill in the fields. + */ + + info->ui_ref = ref; + info->ui_ipinfo = ipi; + udp = info->ui_ports; + for (idx = 0; idx < UDP_MAX_PORTS; idx++) { + udp->up_inuse = FALSE; + q_init(&(udp->up_rxqueue)); + udp++; + } + + /* + * Register our protocol with IP + */ + + _ip_register(ipi,IPPROTO_UDP,_udp_rx_callback,info); + + return info; +} + + +/* ********************************************************************* + * _udp_uninit(info) + * + * Uninitialize the UDP module, deregistering ourselves from the + * IP layer. + * + * Input parameters: + * info - UDP stack information + * + * Return value: + * nothing + ********************************************************************* */ + +void _udp_uninit(udp_info_t *info) +{ + int idx; + udp_port_t *udp; + ebuf_t *buf; + + /* + * Unregister from IP + */ + + _ip_deregister(info->ui_ipinfo,IPPROTO_UDP); + + /* + * Free up any packets that were waiting + */ + + udp = info->ui_ports; + for (idx = 0; idx < UDP_MAX_PORTS; idx++) { + if (udp->up_inuse) { + while ((buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue)))) { + _ip_free(info->ui_ipinfo,buf); + } + } + udp++; + } + + /* + * Free the stack info + */ + + KFREE(info); +} + +/* ********************************************************************* + * _udp_alloc(info) + * + * Allocate a buffer for use with UDP. This routine obtains an + * ebuf and adjusts its header to include room for the UDP + * header. + * + * Input parameters: + * info - UDP stack information + * + * Return value: + * ebuf, or NULL if there are none left + ********************************************************************* */ + +ebuf_t *_udp_alloc(udp_info_t *info) +{ + ebuf_t *buf; + + /* + * Get an ebuf + */ + + buf = _ip_alloc(info->ui_ipinfo); + + if (!buf) return NULL; + + /* + * make room for the udp header + */ + + ebuf_seek(buf,UDP_HDR_LENGTH); + ebuf_setlength(buf,0); + + return buf; +} + +/* ********************************************************************* + * _udp_free(info,buf) + * + * Return an ebuf to the pool. + * + * Input parameters: + * info - UDP stack info + * buf - an ebuf + * + * Return value: + * nothing + ********************************************************************* */ + +void _udp_free(udp_info_t *info,ebuf_t *buf) +{ + _ip_free(info->ui_ipinfo,buf); +} diff --git a/cfe/cfe/pccons/Makefile b/cfe/cfe/pccons/Makefile new file mode 100644 index 0000000..09b8610 --- /dev/null +++ b/cfe/cfe/pccons/Makefile @@ -0,0 +1,3 @@ + +CFLAGS += -DCFG_VGACONSOLE=1 +ALLOBJS += vgainit.o vga_subr.o kbd_subr.o x86mem.o dev_pcconsole.o dev_pcconsole2.o diff --git a/cfe/cfe/pccons/README b/cfe/cfe/pccons/README new file mode 100644 index 0000000..0160ad5 --- /dev/null +++ b/cfe/cfe/pccons/README @@ -0,0 +1,19 @@ + +This directory contains "PC Console" routines, to enable the +SWARM board to use PC-style devices for its console. In +particular, it contains the code to use the X86 emulator +to initialize the VGA, and code to map scan codes to +ASCII characters for a PC keyboard. + +What is this good for, you ask? Just for fun, mostly. Many of +us have had this screwy notion that a SWARM could be used as +a Linux "workstation" if we could get VGA support and USB +keyboards implemented (oh, yeah, and there's this whole +matter of PC console support in Linux, and X, and ...). + +Like the USB host stack, this is among the least-supported +portions of CFE. If you find it useful, great! If it doesn't +work or build properly, let us know, but we may not get to fixing +it right away. + + diff --git a/cfe/cfe/pccons/dev_pcconsole.c b/cfe/cfe/pccons/dev_pcconsole.c new file mode 100644 index 0000000..fe85eca --- /dev/null +++ b/cfe/cfe/pccons/dev_pcconsole.c @@ -0,0 +1,339 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PC Console driver File: dev_pcconsole.c + * + * A console driver for a PC-style keyboard and mouse + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + + +#include "sbmips.h" +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" + +#include "lib_physio.h" + +#include "kbd_subr.h" +#include "vga_subr.h" + +#include "bsp_config.h" +#include "pcireg.h" +#include "pcivar.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define KBD_RXFULL 1 /* bit set if kb has data */ +#define KBD_TXFULL 2 /* bit set if we can send cmd */ +#define VGA_TEXTBUF_COLOR 0xB8000 /* VGA frame buffer */ + +#if defined(_P5064_) || defined(_P6064_) + #define PCI_MEM_SPACE 0x10000000 /* 128MB: s/w configurable */ + #define __ISAaddr(addr) ((physaddr_t)(PCI_MEM_SPACE+(addr))) +#else + #define __ISAaddr(addr) ((physaddr_t)0x40000000+(addr)) +#endif + +#define cpu_isamap(x,y) __ISAaddr(x) + +/* ********************************************************************* + * Forward references + ********************************************************************* */ + +static void pcconsole_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +static int pcconsole_open(cfe_devctx_t *ctx); +static int pcconsole_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int pcconsole_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int pcconsole_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int pcconsole_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int pcconsole_close(cfe_devctx_t *ctx); +static void pcconsole_poll(cfe_devctx_t *ctx,int64_t ticks); + +const static cfe_devdisp_t pcconsole_dispatch = { + pcconsole_open, + pcconsole_read, + pcconsole_inpstat, + pcconsole_write, + pcconsole_ioctl, + pcconsole_close, + pcconsole_poll, + NULL +}; + +const cfe_driver_t pcconsole = { + "PC Console", + "pcconsole", + CFE_DEV_SERIAL, + &pcconsole_dispatch, + pcconsole_probe +}; + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + + +typedef struct pcconsole_s { + vga_term_t vga; + keystate_t ks; + uint32_t kbd_status; + uint32_t kbd_data; +} pcconsole_t; + + +/* ********************************************************************* + * pcconsole_poll(ctx,ticks) + * + * Poll routine - check for new keyboard events + * + * Input parameters: + * ctx - device context + * ticks - current time + * + * Return value: + * nothing + ********************************************************************* */ + + +static void pcconsole_poll(cfe_devctx_t *ctx,int64_t ticks) +{ + pcconsole_t *softc = ctx->dev_softc; + uint8_t status; + uint8_t b; + + status = inb(softc->kbd_status); + + if (status & KBD_RXFULL) { + b = inb(softc->kbd_data); + kbd_doscan(&(softc->ks),b); + } +} + +/* ********************************************************************* + * pcconsole_waitcmdready(softc) + * + * Wait for the keyboard to be ready to accept a command + * + * Input parameters: + * softc - console structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void pcconsole_waitcmdready(pcconsole_t *softc) +{ + uint8_t status; + uint8_t data; + + for (;;) { + status = inb(softc->kbd_status); /* read status */ + if (status & KBD_RXFULL) { + data = inb(softc->kbd_data); /* get data */ + kbd_doscan(&(softc->ks),data); /* process scan codes */ + } + if (!(status & KBD_TXFULL)) break; /* stop when kbd ready */ + } +} + + +/* ********************************************************************* + * pcconsole_setleds(ks,leds) + * + * Callback from the keyboard routines for setting the LEDS + * + * Input parameters: + * ks - keyboard state + * leds - new LED state + * + * Return value: + * 0 + ********************************************************************* */ + +static int pcconsole_setleds(keystate_t *ks,int leds) +{ + pcconsole_t *softc = kbd_getref(ks); + + pcconsole_waitcmdready(softc); + outb(softc->kbd_data,KBDCMD_SETLEDS); + pcconsole_waitcmdready(softc); + outb(softc->kbd_data,(leds & 7)); + + return 0; +} + + +/* ********************************************************************* + * pcconsole_probe(drv,probe_a,probe_b,probe_ptr) + * + * Probe routine. This routine sets up the pcconsole device + * + * Input parameters: + * drv - driver structure + * probe_a + * probe_b + * probe_ptr + * + * Return value: + * nothing + ********************************************************************* */ + +static void pcconsole_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + pcconsole_t *softc; + char descr[80]; + volatile uint8_t *isamem; + + /* + * probe_a is + * probe_b is + * probe_ptr is + */ + + softc = (pcconsole_t *) KMALLOC(sizeof(pcconsole_t),0); + if (softc) { + /* + * XXX This should not be hardwired. + */ + softc->kbd_status = 0x64; + softc->kbd_data = 0x60; + kbd_init(&(softc->ks),pcconsole_setleds,softc); + + /* + * XXX this should not be hardwired + */ + isamem = (volatile uint8_t *) ((uintptr_t)cpu_isamap(0,1024*1024)); + vga_init(&(softc->vga),__ISAaddr(VGA_TEXTBUF_COLOR),outb); + + xsprintf(descr,"%s",drv->drv_description,probe_a,probe_b); + cfe_attach(drv,softc,NULL,descr); + } + +} + + +static int pcconsole_open(cfe_devctx_t *ctx) +{ + pcconsole_t *softc = ctx->dev_softc; + + outb(softc->kbd_data,KBDCMD_RESET); /* reset keyboard */ + kbd_init(&(softc->ks),pcconsole_setleds,softc); + vga_clear(&(softc->vga)); + vga_setcursor(&(softc->vga),0,0); + + return 0; +} + +static int pcconsole_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + pcconsole_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + + pcconsole_poll(ctx,0); + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + while ((blen > 0) && (kbd_inpstat(&(softc->ks)))) { + *bptr++ = (kbd_read(&(softc->ks)) & 0xFF); + blen--; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + +static int pcconsole_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + pcconsole_t *softc = ctx->dev_softc; + + pcconsole_poll(ctx,0); + + inpstat->inp_status = kbd_inpstat(&(softc->ks)) ? 1 : 0; + + return 0; +} + +static int pcconsole_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + pcconsole_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + vga_writestr(&(softc->vga),bptr,7,blen); + + buffer->buf_retlen = buffer->buf_length; + return 0; +} + +static int pcconsole_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ +/* pcconsole_t *softc = ctx->dev_softc;*/ + + return -1; +} + +static int pcconsole_close(cfe_devctx_t *ctx) +{ +/* pcconsole_t *softc = ctx->dev_softc;*/ + + return 0; +} + + diff --git a/cfe/cfe/pccons/dev_pcconsole2.c b/cfe/cfe/pccons/dev_pcconsole2.c new file mode 100644 index 0000000..e078c13 --- /dev/null +++ b/cfe/cfe/pccons/dev_pcconsole2.c @@ -0,0 +1,298 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PC Console driver File: dev_pcconsole2.c + * + * A console driver for a PC-style keyboard and mouse + * + * This version is for USB keyboards. Someday we'll consolidate + * everything. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + + +#include "sbmips.h" +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_string.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_timer.h" + +#include "lib_physio.h" + +#include "vga_subr.h" + +#include "bsp_config.h" +#include "pcireg.h" +#include "pcivar.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define KBD_RXFULL 1 /* bit set if kb has data */ +#define KBD_TXFULL 2 /* bit set if we can send cmd */ +#define VGA_TEXTBUF_COLOR 0xB8000 /* VGA frame buffer */ + +/* XXX SB1250 specific */ +#define __ISAaddr(x)(0x40000000+(x)) + +/* ********************************************************************* + * Forward references + ********************************************************************* */ + +int pcconsole_enqueue(uint8_t ch); + +static void pcconsole_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + + +static int pcconsole_open(cfe_devctx_t *ctx); +static int pcconsole_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int pcconsole_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int pcconsole_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int pcconsole_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int pcconsole_close(cfe_devctx_t *ctx); +static void pcconsole_poll(cfe_devctx_t *ctx,int64_t ticks); + +const static cfe_devdisp_t pcconsole_dispatch = { + pcconsole_open, + pcconsole_read, + pcconsole_inpstat, + pcconsole_write, + pcconsole_ioctl, + pcconsole_close, + pcconsole_poll, + NULL +}; + +const cfe_driver_t pcconsole2 = { + "PC Console (USB)", + "pcconsole", + CFE_DEV_SERIAL, + &pcconsole_dispatch, + pcconsole_probe +}; + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +#define KBD_QUEUE_LEN 32 + +typedef struct pcconsole_s { + vga_term_t vga; + int kbd_in; + int kbd_out; + uint8_t kbd_data[KBD_QUEUE_LEN]; +} pcconsole_t; + +static pcconsole_t *pcconsole_current = NULL; + +/* ********************************************************************* + * pcconsole_poll(ctx,ticks) + * + * Poll routine - check for new keyboard events + * + * Input parameters: + * ctx - device context + * ticks - current time + * + * Return value: + * nothing + ********************************************************************* */ + + +static void pcconsole_poll(cfe_devctx_t *ctx,int64_t ticks) +{ + /* No polling needed, USB will do the work for us */ +} + + + +/* ********************************************************************* + * pcconsole_probe(drv,probe_a,probe_b,probe_ptr) + * + * Probe routine. This routine sets up the pcconsole device + * + * Input parameters: + * drv - driver structure + * probe_a + * probe_b + * probe_ptr + * + * Return value: + * nothing + ********************************************************************* */ + +static void pcconsole_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + pcconsole_t *softc; + char descr[80]; + + /* + * probe_a is + * probe_b is + * probe_ptr is + */ + + softc = (pcconsole_t *) KMALLOC(sizeof(pcconsole_t),0); + if (softc) { + + memset(softc,0,sizeof(pcconsole_t)); + + /* + * XXX this should not be hardwired + */ + vga_init(&(softc->vga),__ISAaddr(VGA_TEXTBUF_COLOR),outb); + + xsprintf(descr,"%s",drv->drv_description,probe_a,probe_b); + cfe_attach(drv,softc,NULL,descr); + } + +} + + +static int pcconsole_open(cfe_devctx_t *ctx) +{ + pcconsole_t *softc = ctx->dev_softc; + + pcconsole_current = softc; + + softc->kbd_in = 0; + softc->kbd_out = 0; + + vga_clear(&(softc->vga)); + vga_setcursor(&(softc->vga),0,0); + + return 0; +} + +static int pcconsole_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + pcconsole_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + while ((blen > 0) && (softc->kbd_in != softc->kbd_out)) { + *bptr++ = softc->kbd_data[softc->kbd_out]; + softc->kbd_out++; + if (softc->kbd_out >= KBD_QUEUE_LEN) { + softc->kbd_out = 0; + } + blen--; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + +static int pcconsole_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + pcconsole_t *softc = ctx->dev_softc; + + POLL(); + + inpstat->inp_status = (softc->kbd_in != softc->kbd_out); + + return 0; +} + +static int pcconsole_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + pcconsole_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + vga_writestr(&(softc->vga),bptr,7,blen); + + buffer->buf_retlen = buffer->buf_length; + return 0; +} + +static int pcconsole_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ +/* pcconsole_t *softc = ctx->dev_softc;*/ + + return -1; +} + +static int pcconsole_close(cfe_devctx_t *ctx) +{ +/* pcconsole_t *softc = ctx->dev_softc;*/ + pcconsole_current = NULL; + + return 0; +} + +/* + * Called by USB system to queue characters. + */ +int pcconsole_enqueue(uint8_t ch) +{ + int newidx; + + if (!pcconsole_current) return -1; + + newidx = pcconsole_current->kbd_in+1; + if (newidx >= KBD_QUEUE_LEN) newidx = 0; + + if (newidx == pcconsole_current->kbd_out) return -1; + + pcconsole_current->kbd_data[pcconsole_current->kbd_in] = ch; + pcconsole_current->kbd_in = newidx; + + return 0; +} diff --git a/cfe/cfe/pccons/kbd_subr.c b/cfe/cfe/pccons/kbd_subr.c new file mode 100644 index 0000000..860db94 --- /dev/null +++ b/cfe/cfe/pccons/kbd_subr.c @@ -0,0 +1,371 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PC-style keyboard interface File: KBD_SUBR.C + * + * This module converts a stream of scancodes into ASCII + * characters. The scan codes come from a PC-style + * keyboard. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" + +#include "kbd_subr.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define FLG_SCROLL 0x0001 /* Toggles: same as bit positions for LEDs! */ +#define FLG_NUM 0x0002 +#define FLG_CAPS 0x0004 +#define FLG_SHIFT 0x0008 /* Shifts */ +#define FLG_CTRL 0x0100 +#define FLG_ALT 0x0200 +#define FLG_FKEY 0x0400 /* function keys */ +#define FLG_NKPD 0x0800 /* numeric keypad */ +#define FLG_ASCII 0x1000 /* regular ASCII character */ +#define FLG_NONE 0x2000 +#define FLG_BREAKBIT 0x80 + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +#define KC_RESPLEN 4 +typedef struct keycode_s { + int kc_type; + char kc_normal[KC_RESPLEN]; + char kc_shifted[KC_RESPLEN]; + char kc_ctrl[KC_RESPLEN]; +} keycode_t; + + +/* ********************************************************************* + * Scan code conversion table + ********************************************************************* */ + +static keycode_t scantable[] = { + { FLG_NONE, "", "", "" }, /* 0 */ + { FLG_ASCII, "\033", "\033", "\033" }, /* 1 ESC */ + { FLG_ASCII, "1", "!", "!" }, /* 2 1 */ + { FLG_ASCII, "2", "@", "\000" }, /* 3 2 */ + { FLG_ASCII, "3", "#", "#" }, /* 4 3 */ + { FLG_ASCII, "4", "$", "$" }, /* 5 4 */ + { FLG_ASCII, "5", "%", "%" }, /* 6 5 */ + { FLG_ASCII, "6", "^", "\036" }, /* 7 6 */ + { FLG_ASCII, "7", "&", "&" }, /* 8 7 */ + { FLG_ASCII, "8", "*", "\010" }, /* 9 8 */ + { FLG_ASCII, "9", "(", "(" }, /* 10 9 */ + { FLG_ASCII, "0", ")", ")" }, /* 11 0 */ + { FLG_ASCII, "-", "_", "\037" }, /* 12 - */ + { FLG_ASCII, "=", "+", "+" }, /* 13 = */ + { FLG_ASCII, "\177", "\177", "\010" }, /* 14 <- */ + { FLG_ASCII, "\t", "\177\t", "\t" }, /* 15 ->| */ + { FLG_ASCII, "q", "Q", "\021" }, /* 16 q */ + { FLG_ASCII, "w", "W", "\027" }, /* 17 w */ + { FLG_ASCII, "e", "E", "\005" }, /* 18 e */ + { FLG_ASCII, "r", "R", "\022" }, /* 19 r */ + { FLG_ASCII, "t", "T", "\024" }, /* 20 t */ + { FLG_ASCII, "y", "Y", "\031" }, /* 21 y */ + { FLG_ASCII, "u", "U", "\025" }, /* 22 u */ + { FLG_ASCII, "i", "I", "\011" }, /* 23 i */ + { FLG_ASCII, "o", "O", "\017" }, /* 24 o */ + { FLG_ASCII, "p", "P", "\020" }, /* 25 p */ + { FLG_ASCII, "[", "{", "\033" }, /* 26 [ */ + { FLG_ASCII, "]", "}", "\035" }, /* 27 ] */ + { FLG_ASCII, "\r", "\r", "\n" }, /* 28 ENT */ + { FLG_CTRL, "", "", "" }, /* 29 CTRL */ + { FLG_ASCII, "a", "A", "\001" }, /* 30 a */ + { FLG_ASCII, "s", "S", "\023" }, /* 31 s */ + { FLG_ASCII, "d", "D", "\004" }, /* 32 d */ + { FLG_ASCII, "f", "F", "\006" }, /* 33 f */ + { FLG_ASCII, "g", "G", "\007" }, /* 34 g */ + { FLG_ASCII, "h", "H", "\010" }, /* 35 h */ + { FLG_ASCII, "j", "J", "\n" }, /* 36 j */ + { FLG_ASCII, "k", "K", "\013" }, /* 37 k */ + { FLG_ASCII, "l", "L", "\014" }, /* 38 l */ + { FLG_ASCII, ";", ":", ";" }, /* 39 ; */ + { FLG_ASCII, "'", "\"", "'" }, /* 40 ' */ + { FLG_ASCII, "`", "~", "`" }, /* 41 ` */ + { FLG_SHIFT, "", "", "" }, /* 42 SHIFT */ + { FLG_ASCII, "\\", "|", "\034" }, /* 43 \ */ + { FLG_ASCII, "z", "Z", "\032" }, /* 44 z */ + { FLG_ASCII, "x", "X", "\030" }, /* 45 x */ + { FLG_ASCII, "c", "C", "\003" }, /* 46 c */ + { FLG_ASCII, "v", "V", "\026" }, /* 47 v */ + { FLG_ASCII, "b", "B", "\002" }, /* 48 b */ + { FLG_ASCII, "n", "N", "\016" }, /* 49 n */ + { FLG_ASCII, "m", "M", "\r" }, /* 50 m */ + { FLG_ASCII, ",", "<", "<" }, /* 51 , */ + { FLG_ASCII, ".", ">", ">" }, /* 52 . */ + { FLG_ASCII, "/", "?", "\037" }, /* 53 / */ + { FLG_SHIFT, "", "", "" }, /* 54 SHIFT */ + { FLG_NKPD, "*", "*", "*" }, /* 55 KP* */ + { FLG_ALT, "", "", "" }, /* 56 ALT */ + { FLG_ASCII, " ", " ", "\000" }, /* 57 SPC */ + { FLG_CAPS, "", "", "" }, /* 58 CAPS */ + { FLG_FKEY, "\033[M", "\033[Y", "\033[k" }, /* 59 f1 */ + { FLG_FKEY, "\033[N", "\033[Z", "\033[l" }, /* 60 f2 */ + { FLG_FKEY, "\033[O", "\033[a", "\033[m" }, /* 61 f3 */ + { FLG_FKEY, "\033[P", "\033[b", "\033[n" }, /* 62 f4 */ + { FLG_FKEY, "\033[Q", "\033[c", "\033[o" }, /* 63 f5 */ + { FLG_FKEY, "\033[R", "\033[d", "\033[p" }, /* 64 f6 */ + { FLG_FKEY, "\033[S", "\033[e", "\033[q" }, /* 65 f7 */ + { FLG_FKEY, "\033[T", "\033[f", "\033[r" }, /* 66 f8 */ + { FLG_FKEY, "\033[U", "\033[g", "\033[s" }, /* 67 f9 */ + { FLG_FKEY, "\033[V", "\033[h", "\033[t" }, /* 68 f10 */ + { FLG_NUM, "", "", "" }, /* 69 NUMLK */ + { FLG_SCROLL, "", "", "" }, /* 70 SCRLK */ + { FLG_NKPD, "7", "\033[H", "7" }, /* 71 KP7 */ + { FLG_NKPD, "8", "\033[A", "8" }, /* 72 KP8 */ + { FLG_NKPD, "9", "\033[I", "9" }, /* 73 KP9 */ + { FLG_NKPD, "-", "-", "-" }, /* 74 KP- */ + { FLG_NKPD, "4", "\033[D", "4" }, /* 75 KP4 */ + { FLG_NKPD, "5", "\033[E", "5" }, /* 76 KP5 */ + { FLG_NKPD, "6", "\033[C", "6" }, /* 77 KP6 */ + { FLG_NKPD, "+", "+", "+" }, /* 78 KP+ */ + { FLG_NKPD, "1", "\033[F", "1" }, /* 79 KP1 */ + { FLG_NKPD, "2", "\033[B", "2" }, /* 80 KP2 */ + { FLG_NKPD, "3", "\033[G", "3" }, /* 81 KP3 */ + { FLG_NKPD, "0", "\033[L", "0" }, /* 82 KP0 */ + { FLG_NKPD, ".", "\177", "." }, /* 83 KP. */ + { FLG_NONE, "", "", "" }, /* 84 0 */ + { FLG_NONE, "100", "", "" }, /* 85 0 */ + { FLG_NONE, "101", "", "" }, /* 86 0 */ + { FLG_FKEY, "\033[W", "\033[i", "\033[u" }, /* 87 f11 */ + { FLG_FKEY, "\033[X", "\033[j", "\033[v" }, /* 88 f12 */ + { FLG_NONE, "102", "", "" }, /* 89 0 */ + { FLG_NONE, "103", "", "" }, /* 90 0 */ + { FLG_NONE, "", "", "" }, /* 91 0 */ + { FLG_NONE, "", "", "" }, /* 92 0 */ + { FLG_NONE, "", "", "" }, /* 93 0 */ + { FLG_NONE, "", "", "" }, /* 94 0 */ + { FLG_NONE, "", "", "" }, /* 95 0 */ + { FLG_NONE, "", "", "" }, /* 96 0 */ + { FLG_NONE, "", "", "" }, /* 97 0 */ + { FLG_NONE, "", "", "" }, /* 98 0 */ + { FLG_NONE, "", "", "" }, /* 99 0 */ + { FLG_NONE, "", "", "" }, /* 100 */ + { FLG_NONE, "", "", "" }, /* 101 */ + { FLG_NONE, "", "", "" }, /* 102 */ + { FLG_NONE, "", "", "" }, /* 103 */ + { FLG_NONE, "", "", "" }, /* 104 */ + { FLG_NONE, "", "", "" }, /* 105 */ + { FLG_NONE, "", "", "" }, /* 106 */ + { FLG_NONE, "", "", "" }, /* 107 */ + { FLG_NONE, "", "", "" }, /* 108 */ + { FLG_NONE, "", "", "" }, /* 109 */ + { FLG_NONE, "", "", "" }, /* 110 */ + { FLG_NONE, "", "", "" }, /* 111 */ + { FLG_NONE, "", "", "" }, /* 112 */ + { FLG_NONE, "", "", "" }, /* 113 */ + { FLG_NONE, "", "", "" }, /* 114 */ + { FLG_NONE, "", "", "" }, /* 115 */ + { FLG_NONE, "", "", "" }, /* 116 */ + { FLG_NONE, "", "", "" }, /* 117 */ + { FLG_NONE, "", "", "" }, /* 118 */ + { FLG_NONE, "", "", "" }, /* 119 */ + { FLG_NONE, "", "", "" }, /* 120 */ + { FLG_NONE, "", "", "" }, /* 121 */ + { FLG_NONE, "", "", "" }, /* 122 */ + { FLG_NONE, "", "", "" }, /* 123 */ + { FLG_NONE, "", "", "" }, /* 124 */ + { FLG_NONE, "", "", "" }, /* 125 */ + { FLG_NONE, "", "", "" }, /* 126 */ + { FLG_NONE, "", "", "" }, /* 127 */ +}; + + +/* ********************************************************************* + * KBD_ENQUEUECHAR(ks,ch) + * + * Put a character on the queue + * + * Input parameters: + * ks - keyboard state + * ch - character to enqueue + * + * Return value: + * nothing + ********************************************************************* */ + +static void kbd_enqueuechar(keystate_t *ks,char ch) +{ + if (((ks->ks_head+1) & (KEYQUEUELEN-1)) == ks->ks_tail) { + /* queue is full */ + return; + } + ks->ks_queue[ks->ks_head] = ch; + ks->ks_head = (ks->ks_head+1) & (KEYQUEUELEN-1); +} + + +/* ********************************************************************* + * KBD_DEQUEUECHAR(ks) + * + * Remove a character from the queue + * + * Input parameters: + * ks - keystate + * + * Return value: + * 0 if no characters in queue + * else character from queue + ********************************************************************* */ +static int kbd_dequeuechar(keystate_t *ks) +{ + char ch; + + if (ks->ks_head == ks->ks_tail) return 0; + + ch = ks->ks_queue[ks->ks_tail]; + ks->ks_tail = (ks->ks_tail+1) & (KEYQUEUELEN-1); + return ch; +} + +/* ********************************************************************* + * KBD_READ(ks) + * + * User call to kbd_dequeuechar - remove a character from + * the queue. + * + * Input parameters: + * ks - keyboard state + * + * Return value: + * character from queue or 0 if no chars + ********************************************************************* */ + +int kbd_read(keystate_t *ks) +{ + return kbd_dequeuechar(ks); +} + +/* ********************************************************************* + * KBD_INPSTAT(ks) + * + * Test input status (see if a character is waiting) + * + * Input parameters: + * ks - keyboard state + * + * Return value: + * 0 if no chars waiting, 1 if characters are waiting + ********************************************************************* */ + +int kbd_inpstat(keystate_t *ks) +{ + return (ks->ks_head != ks->ks_tail); +} + + +/* ********************************************************************* + * KBD_DOSCAN(ks,scan) + * + * Process a scan code from the keyboard. + * + * Input parameters: + * ks - keyboard state + * scan - scan code from the keyboard + * + * Return value: + * nothing + ********************************************************************* */ + +void kbd_doscan(keystate_t *ks,uint8_t scan) +{ + int breakflg; + keycode_t *code = 0; + char *str; + + breakflg = (scan & FLG_BREAKBIT); + scan &= ~FLG_BREAKBIT; + code = &scantable[scan]; + + if (code->kc_type & (FLG_SHIFT|FLG_CTRL|FLG_ALT)) { + if (breakflg) ks->ks_shiftflags &= ~code->kc_type; + else ks->ks_shiftflags |= code->kc_type; + } + if (code->kc_type & (FLG_CAPS|FLG_SCROLL|FLG_NUM)) { + if (!breakflg) ks->ks_shiftflags ^= code->kc_type; + if (ks->ks_setleds) { + (*(ks->ks_setleds))(ks,ks->ks_shiftflags & (FLG_CAPS|FLG_SCROLL|FLG_NUM)); + } + } + if (code->kc_type & (FLG_ASCII | FLG_FKEY | FLG_NKPD)) { + if (ks->ks_shiftflags & (FLG_SHIFT|FLG_CAPS)) str = code->kc_shifted; + else if (ks->ks_shiftflags & FLG_CTRL) str = code->kc_ctrl; + else str = code->kc_normal; + if (!breakflg) { + while (*str) { + kbd_enqueuechar(ks,*str++); + } + } + } +} + + +/* ********************************************************************* + * KBD_INIT(ks,setleds,ref) + * + * Initialize a keyboard state object. + * + * Input parameters: + * ks - keyboard state + * setleds - routine to call when we want to set the state + * of the keyboard's LEDs + * ref - data to store in the keyboard state object + * + * Return value: + * nothing + ********************************************************************* */ + +void kbd_init(keystate_t *ks,int (*setleds)(keystate_t *,int),void *ref) +{ + memset(ks,0,sizeof(keystate_t)); + ks->ks_setleds = setleds; + ks->ks_ref = ref; +} diff --git a/cfe/cfe/pccons/kbd_subr.h b/cfe/cfe/pccons/kbd_subr.h new file mode 100644 index 0000000..f18f8db --- /dev/null +++ b/cfe/cfe/pccons/kbd_subr.h @@ -0,0 +1,82 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PC-style keyboard interface File: KBD_SUBR.C + * + * This module converts a stream of scancodes into ASCII + * characters. The scan codes come from a PC-style + * keyboard. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define KEYQUEUELEN 16 + +#define KBDCMD_RESET 0xFF +#define KBDCMD_SETLEDS 0xED + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct keystate_s { + int ks_shiftflags; + char ks_queue[KEYQUEUELEN]; + int ks_head; + int ks_tail; + int (*ks_setleds)(struct keystate_s *ks,int leds); + void *ks_ref; +} keystate_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int kbd_read(keystate_t *ks); +int kbd_inpstat(keystate_t *ks); +void kbd_init(keystate_t *ks,int (*setleds)(keystate_t *,int),void *ref); +void kbd_doscan(keystate_t *ks,uint8_t scan); +#define kbd_getref(x) ((x)->ks_ref) + + diff --git a/cfe/cfe/pccons/pcibios.h b/cfe/cfe/pccons/pcibios.h new file mode 100644 index 0000000..8da8648 --- /dev/null +++ b/cfe/cfe/pccons/pcibios.h @@ -0,0 +1,72 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PCI BIOS constants File: PCIBIOS.H + * + * This module contains constants related to the X86's PCI + * BIOS, as described in the PCI BIOS specification. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#define PCIBIOS_FN_MAJOR 0xB1 +#define PCIBIOS_FN_INSTCHK 0x01 +#define PCIBIOS_FN_FINDDEV 0x02 +#define PCIBIOS_FN_FINDCLASS 0x03 +#define PCIBIOS_FN_RDCFGBYTE 0x08 +#define PCIBIOS_FN_RDCFGWORD 0x09 +#define PCIBIOS_FN_RDCFGDWORD 0x0A + +#define PCIBIOS_FN_WRCFGBYTE 0x0B +#define PCIBIOS_FN_WRCFGWORD 0x0C +#define PCIBIOS_FN_WRCFGDWORD 0x0D +#define PCIBIOS_SUCCESSFUL 0 +#define PCIBIOS_DEVICE_NOT_FOUND 0x86 + +#define PCIBIOS_VERSION 0x0210 +#define PCIBIOS_SIGNATURE 0x20494350 + +#define PCIBIOS_ROMSIG_OFFSET 0 +#define PCIBIOS_ROMSIG1 0x55 +#define PCIBIOS_ROMSIG2 0xAA +#define PCIBIOS_ROMSIZE(x) ((unsigned int)(x)*512) + +#define PCIBIOS_ROMSIZE_OFFSET 2 +#define PCIBIOS_ROMENTRY_OFFSET 3 diff --git a/cfe/cfe/pccons/vga.h b/cfe/cfe/pccons/vga.h new file mode 100644 index 0000000..5c43664 --- /dev/null +++ b/cfe/cfe/pccons/vga.h @@ -0,0 +1,76 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * VGA definitions File: VGA.H + * + * This module contains names of the registers and bits + * commonly used on VGA adapters. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#define VGA_GFXCTL_INDEX 0x3CE +#define VGA_GFXCTL_DATA 0x3CF +#define VGA_CRTC_INDEX 0x3D4 +#define VGA_CRTC_DATA 0x3D5 +#define VGA_SEQ_INDEX 0x3C4 +#define VGA_SEQ_DATA 0x3C5 +#define VGA_INPSTATUS_R 0x3C2 +#define VGA_MISCOUTPUT_W 0x3C2 +#define VGA_MISCOUTPUT_R 0x3CC +#define VGA_ATTRIB_INDEX 0x3C0 +#define VGA_ATTRIB_DATA 0x3C1 +#define VGA_FEATURES_W 0x3DA +#define VGA_EXT_INDEX 0x3D6 +#define VGA_EXT_DATA 0x3D7 + +#define CRTC_CURSOR_HIGH 0x0E +#define CRTC_CURSOR_LOW 0x0F + +#define VGA_TEXTBUF_COLOR 0xB8000 +#define VGA_TEXTBUF_MONO 0xB0000 +#define VGA_TEXTBUF_SIZE 0x8000 + +#define VGA_ATTRIB_MONO 7 + +#define VGA_TEXTMODE_COLS 80 +#define VGA_TEXTMODE_ROWS 25 + diff --git a/cfe/cfe/pccons/vga_subr.c b/cfe/cfe/pccons/vga_subr.c new file mode 100644 index 0000000..7704054 --- /dev/null +++ b/cfe/cfe/pccons/vga_subr.c @@ -0,0 +1,285 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * VGA "teletype" routines File: VGA_SUBR.C + * + * These routines implement a simple "glass tty" interface + * to a vga monitor. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_malloc.h" + +#include "lib_physio.h" + +#include "vga_subr.h" +#include "vga.h" + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define OUTB(vga,port,val) (*((vga)->vga_outb))(port,val) + +#ifdef __MIPSEB +#define VGA_SPACE_CHAR 0x2007 /* belongs somewhere else */ +#else +#define VGA_SPACE_CHAR 0x0720 +#endif + +/* ********************************************************************* + * Data + ********************************************************************* */ + + +/* ********************************************************************* + * VGA_CLEAR(vga) + * + * Clear the VGA screen + * + * Input parameters: + * vga - VGA object + * + * Return value: + * nothing + ********************************************************************* */ + +void vga_clear(vga_term_t *vga) +{ + int idx; + + /* Clear the frame buffer */ + + for (idx = 0; idx < VGA_TEXTBUF_SIZE; idx+=2) { + phys_write16(vga->vga_buffer+idx,VGA_SPACE_CHAR); + } +} + + +/* ********************************************************************* + * VGA_SETCURSOR(vga,x,y) + * + * Set the hardware cursor position + * + * Input parameters: + * vga - VGA object + * x,y - cursor location + * + * Return value: + * nothing + ********************************************************************* */ + +void vga_setcursor(vga_term_t *vga,int x,int y) +{ + unsigned int loc = y*vga->vga_ncols + x; + + OUTB(vga,VGA_CRTC_INDEX,CRTC_CURSOR_HIGH); + OUTB(vga,VGA_CRTC_DATA,(loc >> 8) & 0xFF); + OUTB(vga,VGA_CRTC_INDEX,CRTC_CURSOR_LOW); + OUTB(vga,VGA_CRTC_DATA,(loc >> 0) & 0xFF); + + vga->vga_cursorX = x; + vga->vga_cursorY = y; +} + +/* ********************************************************************* + * VGA_SCROLL(vga) + * + * Scroll the display up one line + * + * Input parameters: + * vga - VGA object + * + * Return value: + * nothing + ********************************************************************* */ + +static void vga_scroll(vga_term_t *vga) +{ + int idx; + int count; + int rowsize; + uint32_t t; + + rowsize = vga->vga_ncols * 2; + count = (vga->vga_nrows-1) * rowsize; + + for (idx = 0; idx < count; idx+=4) { + t = phys_read32(vga->vga_buffer+idx+rowsize); + phys_write32(vga->vga_buffer+idx,t); + } + + for (idx = 0; idx < rowsize; idx += 2) { + phys_write16(vga->vga_buffer+(vga->vga_nrows-1)*rowsize+idx,VGA_SPACE_CHAR); + } + + vga_setcursor(vga,0,vga->vga_nrows-1); +} + +/* ********************************************************************* + * VGA_WRITECHAR(vga,ch,attr) + * + * Write a character to the display. This routine also + * interprets some rudimentary control characters, such + * as tab, backspace, linefeed, and carriage return. + * + * Input parameters: + * vga - VGA object + * ch - character to write + * attr - attribute byte for new character + * + * Return value: + * nothing + ********************************************************************* */ + +void vga_writechar(vga_term_t *vga,uint8_t ch,uint8_t attr) +{ + physaddr_t addr; + + switch (ch) { + case 0x07: + break; + case 0x09: + vga_writechar(vga,' ',attr); + while (vga->vga_cursorX % 8) vga_writechar(vga,' ',attr); + break; + case 0x0A: + vga->vga_cursorY++; + if (vga->vga_cursorY > (vga->vga_nrows-1)) { + vga_scroll(vga); + } + break; + case 0x08: + if (vga->vga_cursorX) { + vga->vga_cursorX--; + addr = vga->vga_buffer + (vga->vga_cursorX*2+vga->vga_cursorY*vga->vga_ncols*2); + phys_write8(addr,' '); + } + break; + case 0x0D: + vga->vga_cursorX = 0; + break; + default: + addr = vga->vga_buffer + (vga->vga_cursorX*2+vga->vga_cursorY*vga->vga_ncols*2); + phys_write8(addr,ch); + phys_write8(addr+1,attr); + vga->vga_cursorX++; + if (vga->vga_cursorX > (vga->vga_ncols-1)) { + vga->vga_cursorX = 0; + vga->vga_cursorY++; + if (vga->vga_cursorY > (vga->vga_nrows-1)) { + vga_scroll(vga); + } + } + break; + } + + vga_setcursor(vga,vga->vga_cursorX,vga->vga_cursorY); +} + +/* ********************************************************************* + * VGA_WRITESTR(vga,str,attr,len) + * + * Write a string of characters to the VGA + * + * Input parameters: + * vga - VGA object + * str - pointer to buffer + * attr - attribute byte for characters we're writing + * len - number of characters to write + * + * Return value: + * nothing + ********************************************************************* */ + +void vga_writestr(vga_term_t *vga,uint8_t *str,uint8_t attr,int len) +{ + while (len) { + vga_writechar(vga,*str,attr); + str++; + len--; + } +} + +/* ********************************************************************* + * VGA_RESET(vga) + * + * (mostly unused) - reset the VGA + * + * Input parameters: + * vga - vga object + * + * Return value: + * nothing + ********************************************************************* */ + +void vga_reset(vga_term_t *vga) +{ + vga_clear(vga); +} + +/* ********************************************************************* + * VGA_INIT(vga,buffer,outfunc) + * + * Initialize a VGA object + * + * Input parameters: + * vga - VGA object + * buffer - pointer to VGA-style frame buffer (physical addr) + * outfunc - pointer to function to write ISA I/O ports + * + * Return value: + * nothing + ********************************************************************* */ + +void vga_init(vga_term_t *vga,physaddr_t buffer,void (*outfunc)(unsigned int port,uint8_t val)) +{ + vga->vga_buffer = buffer; + vga->vga_cursorX = 0; + vga->vga_cursorY = 0; + vga->vga_nrows = VGA_TEXTMODE_ROWS; + vga->vga_ncols = VGA_TEXTMODE_COLS; + vga->vga_outb = outfunc; +} diff --git a/cfe/cfe/pccons/vga_subr.h b/cfe/cfe/pccons/vga_subr.h new file mode 100644 index 0000000..eb0e0e0 --- /dev/null +++ b/cfe/cfe/pccons/vga_subr.h @@ -0,0 +1,82 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * VGA "teletype" routines File: VGA_SUBR.H + * + * These routines implement a simple "glass tty" interface + * to a vga monitor. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct vga_term_s { + physaddr_t vga_buffer; + int vga_nrows; + int vga_ncols; + int vga_cursorX; + int vga_cursorY; + void (*vga_outb)(unsigned int isaport,uint8_t val); +} vga_term_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + + +void vga_clear(vga_term_t *vga); +void vga_setcursor(vga_term_t *vga,int x,int y); +void vga_writechar(vga_term_t *vga,uint8_t ch,uint8_t attr); +void vga_writestr(vga_term_t *vga,uint8_t *str,uint8_t attr,int len); +void vga_reset(vga_term_t *vga); +void vga_init(vga_term_t *vga,physaddr_t buffer,void (*outfunc)(unsigned int port,uint8_t val)); + + + + + + + + + + + diff --git a/cfe/cfe/pccons/vgainit.c b/cfe/cfe/pccons/vgainit.c new file mode 100644 index 0000000..7c22af2 --- /dev/null +++ b/cfe/cfe/pccons/vgainit.c @@ -0,0 +1,1164 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * VGA BIOS initialization File: VGAINIT.C + * + * This module interfaces with the X86 emulator borrowed from + * XFree86 to do VGA initialization. + * + * WARNING: This code is SB1250-specific for now. It's not + * hard to change, but then again, aren't we interested in the 1250? + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "sbmips.h" +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_malloc.h" +#include "pcireg.h" +#include "pcivar.h" +#include "cfe_console.h" +#include "vga.h" +#include "pcibios.h" +#include "lib_physio.h" +#include "vga_subr.h" +#include "x86mem.h" +#include "x86emu.h" +#include "env_subr.h" + + +/* ********************************************************************* + * Configuration + ********************************************************************* */ + +#define BYTESONLY 0 /* Always write registers as bytes */ +#define VGAINIT_NOISY 0 /* lots of debug output */ + +/* ********************************************************************* + * ISA port macros - currently SB1250-specific + ********************************************************************* */ + +#define INB(x) inb(x) +#define INW(x) inw(x) +#define INL(x) inl(x) +#define OUTB(x,y) outb(x,y) +#define OUTW(x,y) outw(x,y) +#define OUTL(x,y) outl(x,y) + +/* ********************************************************************* + * ISA memory macros - currently SB1250-specific + ********************************************************************* */ + +typedef uintptr_t vm_offset_t; + +#if defined(_P5064_) || defined(_P6064_) + #define PCI_MEM_SPACE 0x10000000 /* 128MB: s/w configurable */ + #define __ISAaddr(addr) ((physaddr_t)(PCI_MEM_SPACE+(addr))) +#else + #define __ISAaddr(addr) ((physaddr_t)0x40000000+(addr)) +#endif + +#define __ISAreadbyte(addr) phys_read8(__ISAaddr(addr)) +#define __ISAreadword(addr) phys_read16(__ISAaddr(addr)) +#define __ISAreaddword(addr) phys_read32(__ISAaddr(addr)) +#define __ISAwritebyte(addr,data) phys_write8(__ISAaddr(addr),(data)) +#define __ISAwriteword(addr,data) phys_write16(__ISAaddr(addr),(data)) +#define __ISAwritedword(addr,data) phys_write32(__ISAaddr(addr),(data)) + +/* ********************************************************************* + * Other macros + ********************************************************************* */ + +#define OFFSET(addr) (((addr) >> 0) & 0xffff) +#define SEGMENT(addr) (((addr) >> 4) & 0xf000) + +#define BSWAP_SHORT(s) ((((s) >> 8) & 0xFF) | (((s)&0xFF) << 8)) +#define BSWAP_LONG(s) ((((s) & 0xFF000000) >> 24) | \ + (((s) & 0x00FF0000) >> 8) | \ + (((s) & 0x0000FF00) << 8) | \ + (((s) & 0x000000FF) << 24)) + + +#ifdef __MIPSEB +#define CPU_TO_LE16(s) BSWAP_SHORT(s) +#define CPU_TO_LE32(s) BSWAP_LONG(s) +#define LE16_TO_CPU(s) BSWAP_SHORT(s) +#define LE32_TO_CPU(s) BSWAP_LONG(s) +#else +#define CPU_TO_LE16(s) (s) +#define CPU_TO_LE32(s) (s) +#define LE16_TO_CPU(s) (s) +#define LE32_TO_CPU(s) (s) +#endif + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int vga_biosinit(void); +int vga_probe(void); +extern void ui_restart(int); +void vgaraw_dump(char *tail); +int x86emutest(void); + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +static vga_term_t vga; +static x86mem_t x86mem; + +#define BIOSRAMLOC (0xC0000) +#define STACKSIZE 4096 +#define IRETOFFSET 12 +static uint8_t x86initcode[] = { +#if (VGA_TEXTMODE_ROWS == 60) + 0xB8,0x02,0x4F, /* mov ax,042F */ + 0xBB,0x08,0x01, /* mov bx,0108 */ /* VESA 80x60 */ +#else + 0xB8,0x03,0x00, /* mov AX,0003 */ /* 80x25 mode */ +#endif + + 0xCD,0x10, /* int 10 */ + 0xB8,0x34,0x12, /* mov ax,1234 */ + 0xBB,0x78,0x56, /* mov bx,5678 */ + 0xCC, /* int 3 */ + 0xCF}; /* IRET */ + +static uint8_t x86testcode[] = { + 0x90,0x90,0x90,0x90,0x90, /* nop, nop, nop, nop, nop */ + 0xeb,0x09, /* jmp 10 */ + 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, /* 9 nops */ + 0xb8,0x34,0x12, /* mov ax,1234 */ + 0xbb,0x78,0x56, /* mov bx,5678 */ + 0xcc, /* int 3 */ + 0xcf}; /* iret */ + +static uint32_t __ISAreadmem(x86mem_t *mem,uint32_t addr,int size) +{ + unsigned long val; + + switch (size) { + case M_BYTE: + val = __ISAreadbyte(addr); + break; + case M_WORD: + if (BYTESONLY || (addr & 0x1)) { + val = (__ISAreadbyte(addr) | (__ISAreadbyte(addr + 1) << 8)); + } + else { + val = __ISAreadword(addr); + val = LE16_TO_CPU(val); + } + break; + case M_DWORD: + if (BYTESONLY || (addr & 0x3)) { + val = (__ISAreadbyte(addr) | + (__ISAreadbyte(addr + 1) << 8) | + (__ISAreadbyte(addr + 2) << 16) | + (__ISAreadbyte(addr + 3) << 24)); + } + else { + val = __ISAreaddword(addr); + val = LE32_TO_CPU(val); + } + break; + default: + val = 0; + } + + return val; +} + + + +static void __ISAwritemem(x86mem_t *mem,uint32_t addr,uint32_t data,int size) +{ + switch (size) { + case M_BYTE: + __ISAwritebyte(addr, data); + break; + + case M_WORD: + if (BYTESONLY || (addr & 0x1)) { + __ISAwritebyte(addr, data >> 0); + __ISAwritebyte(addr + 1, data >> 8); + } + else { + data = CPU_TO_LE16(data); + __ISAwriteword(addr, data); + } + break; + + case M_DWORD: + if (BYTESONLY || (addr & 0x3)) { + __ISAwritebyte(addr, data >> 0); + __ISAwritebyte(addr + 1, data >> 8); + __ISAwritebyte(addr + 2, data >> 16); + __ISAwritebyte(addr + 3, data >> 24); + } + else { + data = CPU_TO_LE32(data); + __ISAwritedword(addr, data); + } + break; + } +} + + +static u8 __x86emu_rdb(u32 addr) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Read %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + return x86mem_readb(&x86mem,addr); +} + + +static u16 __x86emu_rdw(u32 addr) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Read %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + return x86mem_readw(&x86mem,addr); +} + + +static u32 __x86emu_rdl(u32 addr) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Read %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + return x86mem_readl(&x86mem,addr); +} + + +static void __x86emu_wrb(u32 addr, u8 val) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Write %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + x86mem_writeb(&x86mem,addr,val); +} + + +static void __x86emu_wrw(u32 addr, u16 val) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Write %08X %04X (int %02X) ",addr,val,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + x86mem_writew(&x86mem,addr,val); +} + + +static void __x86emu_wrl(u32 addr, u32 val) +{ +#if VGAINIT_NOISY + if ((addr < 0x400) || (addr > 0x100000)) { + xprintf("Write %08X (int %02X) ",addr,addr/4); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); + } +#endif + x86mem_writel(&x86mem,addr,val); +} + + +#define TS_COMMAND 0 +#define TS_DATA1 1 +#define TS_DATA2 2 +static uint16_t timerCount = 0; +static int timerState = TS_COMMAND; +static u8 __x86emu_inb(X86EMU_pioAddr port) +{ + u8 val; + + /* + * Emulate just enough functionality of the + * timer chip to fool the Trident BIOS + */ + if (port == 0x40) { + timerCount++; + switch (timerState) { + case TS_COMMAND: + return 0; + case TS_DATA1: + timerState = TS_DATA1; + return timerCount & 0xFF; + case TS_DATA2: + timerState = TS_COMMAND; + return (timerCount >> 8) & 0xFF; + } + } + + val = INB(port); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("INB %08X %02X\n",port,val); + if (console_status()) ui_restart(0); +#endif + + + return val; +} + + +static u16 __x86emu_inw(X86EMU_pioAddr port) +{ + u16 val; + + val = INW(port); + + val = LE16_TO_CPU(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("INW %08X %04X\n",port,val); +#endif + + return val; +} + + +static u32 __x86emu_inl(X86EMU_pioAddr port) +{ + u32 val; + + val = INL(port); + + val = LE32_TO_CPU(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("INL %08X %08X\n",port,val); +#endif + + + return val; +} + + +static void __x86emu_outb(X86EMU_pioAddr port, u8 val) +{ + /* + * Emulate just enough functionality of the timer + * chip to fool the Trident BIOS + */ + if (port == 0x43) { + timerCount++; + timerState = TS_DATA1; + return; + } + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("OUTB %08X %08X\n",port,val); +#endif + + OUTB(port,val); +} + + +static void __x86emu_outw(X86EMU_pioAddr port, u16 val) +{ + val = CPU_TO_LE16(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("OUTW %08X %04X ",port,val); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); +#endif + + OUTW(port,val); +} + + +static void __x86emu_outl(X86EMU_pioAddr port, u32 val) +{ + if (port == 0x2D) return; + + val = CPU_TO_LE32(val); + +#if VGAINIT_NOISY + /*if (port < 0x100)*/ xprintf("OUTL %08X %08X ",port,val); + printf("CS:IP = %04X:%04X\n",M.x86.R_CS,M.x86.R_IP); +#endif + + + OUTL(port,val); +} + + +static void regs2tag(pcitag_t *tag) +{ + pcitag_t mytag; + int bus,device,function; + + bus = M.x86.R_BH; + device = M.x86.R_BL >> 3; + function = M.x86.R_BL & 0x07; + + mytag = pci_make_tag(bus,device,function); + + *tag = mytag; +} + +static void __SIMint10(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int10: BIOS function AX=%04X\n",M.x86.R_AX); +#endif + + /* + * The only BIOS function that VGAs appear to + * depend on in the real BIOS is the one + * that enables/disables video memory. + */ + + if ((M.x86.R_AH == 0x12) && (M.x86.R_BL == 0x32)) { + if (M.x86.R_AL == 0) { + /* enable video memory */ + __x86emu_outb(VGA_MISCOUTPUT_W, __x86emu_inb(VGA_MISCOUTPUT_R) | 0x02); + return; + } + else if (M.x86.R_AL == 1) { + /* disable video memory */ + __x86emu_outb(VGA_MISCOUTPUT_W, __x86emu_inb(VGA_MISCOUTPUT_R) & ~0x02); + return; + } + else { + xprintf("Int10 unknown function AX=%04X\n", + M.x86.R_AX); + } + } + else { + + /* Otherwise, pass the int10 on to the ROM */ + + X86EMU_prepareForInt(0x10); + } +} + + +static void __SIMint3(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int3: Breakpoint reached.\n"); +#endif + HALT_SYS(); +} + + +static void __SIMintunk(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int%02X: Unhandled interrupt!\n",intno); +#endif + HALT_SYS(); +} + +static void __SIMint42(int intno) +{ +#if VGAINIT_NOISY + xprintf("Int42: Function AX=%04X\n",M.x86.R_AX); +#endif + switch (M.x86.R_AH) { + case 0: + vga_reset(&vga); + break; + default: +#if VGAINIT_NOISY + xprintf("Int42: Unknown INT42 command: %x\n",M.x86.R_AH); +#endif + break; + } +} + + +static void __SIMint6D(int intno) +{ + int reflect = 1; + +#if VGAINIT_NOISY + xprintf("Int6D: Function AX=%04X\n",M.x86.R_AX); +#endif + + switch (M.x86.R_AH) { + case 0: + break; + case 0x13: + if (M.x86.R_AL == 1) { + unsigned long addr; + unsigned long count; + uint8_t ch; + + addr = (M.x86.R_ES << 4) + M.x86.R_BP; + count = M.x86.R_CX; + + while (count) { + ch = __x86emu_rdb(addr); + vga_writechar(&vga,ch,M.x86.R_BL); + addr++; + count--; + } + reflect = 0; + } + break; + default: +#if VGAINIT_NOISY + xprintf("Unknown INT6D command: %x\n",M.x86.R_AH); +#endif + break; + } + + if (reflect) X86EMU_prepareForInt(0x6D); +} + + + +static void __SIMint1A(int intno) +{ + pcitag_t tag; + int bus,device,function; + int ret; + + if (M.x86.R_AH != PCIBIOS_FN_MAJOR) return; + + switch (M.x86.R_AL) { + case PCIBIOS_FN_INSTCHK: + M.x86.R_EAX = 0x00; + M.x86.R_AL = 0x01; + M.x86.R_EDX = PCIBIOS_SIGNATURE; + M.x86.R_EBX = PCIBIOS_VERSION; + M.x86.R_ECX &= 0xFF00; + M.x86.R_CL = 0; /* Highest bus number */ +#ifdef VGAINIT_NOISY + xprintf("Int1A: Installation check\n"); +#endif + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_FINDDEV: + ret = pci_find_device(M.x86.R_DX,M.x86.R_CX,M.x86.R_SI,&tag); +#if VGAINIT_NOISY + xprintf("Int1A: Find device VID=%04X,DID=%04X,Idx=%d: ", + M.x86.R_DX,M.x86.R_CX,M.x86.R_SI); + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + xprintf("Found Bus%d, Dev%d, Func%d\n",bus,device,function); + } + else { + xprintf("not found.\n"); + } +#endif + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + M.x86.R_BH = bus; + M.x86.R_BL = (device << 3) | function; + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + } + else { + M.x86.R_AH = PCIBIOS_DEVICE_NOT_FOUND; + } + + CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL),F_CF); + break; + + case PCIBIOS_FN_FINDCLASS: + ret = pci_find_class(M.x86.R_ECX,M.x86.R_SI,&tag); +#if VGAINIT_NOISY + xprintf("Int1A: Find Class %08X,Idx=%d: ", + M.x86.R_ECX,M.x86.R_SI); + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + xprintf("Found Bus%d, Dev%d, Func%d\n",bus,device,function); + } + else { + xprintf("not found.\n"); + } +#endif + + if (ret == 0) { + pci_break_tag(tag,&bus,&device,&function); + M.x86.R_BH = bus; + M.x86.R_BL = (device << 3) | function; + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + } + else { + M.x86.R_AH =PCIBIOS_DEVICE_NOT_FOUND; + } + + CONDITIONAL_SET_FLAG((M.x86.R_AH != PCIBIOS_SUCCESSFUL),F_CF); + break; + + case PCIBIOS_FN_RDCFGBYTE: + regs2tag(&tag); + M.x86.R_CL = pci_conf_read8(tag,M.x86.R_DI); + M.x86.R_AH = PCIBIOS_SUCCESSFUL; +#if VGAINIT_NOISY + xprintf("Int1A: Read Cfg Byte %04X from ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %02X\n",M.x86.R_CX); +#endif + + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_RDCFGWORD: + regs2tag(&tag); + M.x86.R_CX = pci_conf_read16(tag,M.x86.R_DI); + M.x86.R_AH = PCIBIOS_SUCCESSFUL; +#if VGAINIT_NOISY + xprintf("Int1A: Read Cfg Word %04X from ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %04X\n",M.x86.R_CX); +#endif + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_RDCFGDWORD: + regs2tag(&tag); + M.x86.R_ECX = pci_conf_read(tag,M.x86.R_DI); +#if VGAINIT_NOISY + xprintf("Int1A: Read Cfg Dword %04X from ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %08X\n",M.x86.R_ECX); +#endif + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_WRCFGBYTE: + regs2tag(&tag); + pci_conf_write8(tag,M.x86.R_DI,M.x86.R_CL); +#if VGAINIT_NOISY + xprintf("Int1A: Write Cfg byte %04X to ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %02X\n",M.x86.R_CL); +#endif + + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_WRCFGWORD: + regs2tag(&tag); + pci_conf_write16(tag,M.x86.R_DI,M.x86.R_CX); +#if VGAINIT_NOISY + xprintf("Int1A: Write Cfg Word %04X to ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %04X\n",M.x86.R_CX); +#endif + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + case PCIBIOS_FN_WRCFGDWORD: + regs2tag(&tag); + pci_conf_write(tag,M.x86.R_DI,M.x86.R_ECX); +#if VGAINIT_NOISY + xprintf("Int1A: Write Cfg Dword %04X to ",M.x86.R_DI); + pci_break_tag(tag,&bus,&device,&function); + xprintf("Bus%d, Dev%d, Func%d",bus,device,function); + xprintf(": %08X\n",M.x86.R_ECX); +#endif + M.x86.R_AH = PCIBIOS_SUCCESSFUL; + CLEAR_FLAG(F_CF); + break; + + default: +#if VGAINIT_NOISY + xprintf("Int1A: Unimplemented PCI BIOS function AX=%04x\n", M.x86.R_AX); +#endif + break; + } +} + + + +static int x86init(void) +{ + /* + * Access functions for I/O ports + */ + static X86EMU_pioFuncs piofuncs = { + __x86emu_inb, + __x86emu_inw, + __x86emu_inl, + __x86emu_outb, + __x86emu_outw, + __x86emu_outl + }; + + /* + * Access functions for memory + */ + static X86EMU_memFuncs memfuncs = { + __x86emu_rdb, + __x86emu_rdw, + __x86emu_rdl, + __x86emu_wrb, + __x86emu_wrw, + __x86emu_wrl + }; + + /* + * Interrupt table + */ + void (*funcs[256])(int num); /* XXX: can be 2 kilobytes! */ + int idx; + + /* + * Establish hooks in the simulator + */ + X86EMU_setupMemFuncs(&memfuncs); + X86EMU_setupPioFuncs(&piofuncs); + + /* + * Decode what X86 software interrupts we need to hook + */ + + for (idx = 0; idx < 256; idx++) { + funcs[idx] = __SIMintunk; /* assume all are bad */ + } + funcs[0x42] = __SIMint42; /* int42: video BIOS */ + funcs[0x1F] = NULL; /* reflect INT1F */ + funcs[0x43] = NULL; /* reflect INT43 */ + funcs[0x6D] = __SIMint6D; /* int6D: video BIOS */ + + funcs[0x03] = __SIMint3; /* int3: firmware exit */ + funcs[0x10] = __SIMint10; /* int10: video BIOS */ + funcs[0x1A] = __SIMint1A; /* int1A: PCI BIOS */ + + X86EMU_setupIntrFuncs(funcs); + + x86mem_init(&x86mem); + x86mem_hook(&x86mem,0xA0000,__ISAreadmem,__ISAwritemem); + x86mem_hook(&x86mem,0xA8000,__ISAreadmem,__ISAwritemem); + x86mem_hook(&x86mem,0xB0000,__ISAreadmem,__ISAwritemem); + x86mem_hook(&x86mem,0xB8000,__ISAreadmem,__ISAwritemem); + + return 0; + +} + + +static void x86uninit(void) +{ + x86mem_uninit(&x86mem); +} + + +int vga_probe(void) +{ + pcitag_t tag; + + if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { + return 0; + } + + return -1; +} + +int vga_biosinit(void) +{ + physaddr_t biosaddr; + pcitag_t tag; + uint32_t addr; + uint32_t romaddr; + uint32_t destaddr; + uint32_t stackaddr; + uint32_t iretaddr; + unsigned int biossize; + int bus,device,function; + int idx; + int res; + + if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { + romaddr = pci_conf_read(tag,PCI_MAPREG_ROM); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr | PCI_MAPREG_ROM_ENABLE); + } + else { + xprintf("No suitable VGA device found in the system.\n"); + return -1; + } + + addr = romaddr; + addr &= PCI_MAPREG_ROM_ADDR_MASK; +#if defined(_P5064_) || defined(_P6064_) + biosaddr = cpu_isamap((vm_offset_t) romaddr,0); +#else + biosaddr = (physaddr_t) romaddr; +#endif + + /* + * Check for the presence of a VGA BIOS on this adapter. + */ + + if (!((phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+0) == PCIBIOS_ROMSIG1) && + (phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+1) == PCIBIOS_ROMSIG2))) { + xprintf("No VGA BIOS on this adapter.\n"); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + return -1; + } + biossize = PCIBIOS_ROMSIZE(phys_read8(biosaddr+PCIBIOS_ROMSIZE_OFFSET)); + +#if VGAINIT_NOISY + xprintf("VGA BIOS size is %d bytes\n",biossize); +#endif + + /* + * Initialize the X86 emulator + */ + + if (x86init() != 0) { + xprintf("X86 emulator did not initialize.\n"); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + return -1; + } + + /* + * Allocate space for the ROM BIOS and the stack. + * The basic layout is: + * + * C000:0000 VGA BIOS + * C000:XXXX end of VGA BIOS, start of stack + * C000:YYYY end of stack, start of init code + * C000:ZZZZ end of allocated memory + * + * We put a little code stub after the stack to allow us to have + * a clean exit from the simulator. + */ + + + destaddr = BIOSRAMLOC; + stackaddr = destaddr + biossize + STACKSIZE; + + /* + * Copy the BIOS from the PCI rom into RAM + */ + +#if VGAINIT_NOISY + xprintf("Copying VGA BIOS to RAM.\n"); +#endif + + for (idx = 0; idx < biossize; idx+=4) { + uint32_t b; + + b = phys_read32(biosaddr+idx); + x86mem_memcpy(&x86mem,destaddr+idx,(uint8_t *) &b,sizeof(uint32_t)); + } + + /* + * Gross! The NVidia TNT2 BIOS expects to + * find a PC ROM BIOS date (just the slashes) + * at the right place in the ROMs. + */ + + x86mem_memcpy(&x86mem,0xFFFF5,"08/13/99",8); + + /* + * Turn off the BIOS ROM, we have our copy now. + */ + + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + + /* + * Point certain vectors at a dummy IRET in our code space. + * Some ROMs don't take too kindly to null vectors, like + * the 3dfx Voodoo3 BIOS, which makes sure int1a is + * filled in before it attempts to call it. The + * code here is never really executed, since the emulator + * hooks it. + */ + + iretaddr = stackaddr + IRETOFFSET; + __x86emu_wrw(0x1A*4+0,OFFSET(iretaddr)); + __x86emu_wrw(0x1A*4+2,SEGMENT(iretaddr)); + + + /* + * The actual code begins 3 bytes after the beginning of the ROM. Set + * the start address to the first byte of executable code. + */ + + M.x86.R_CS = SEGMENT(destaddr + PCIBIOS_ROMENTRY_OFFSET); + M.x86.R_IP = OFFSET(destaddr + PCIBIOS_ROMENTRY_OFFSET); + + /* + * Set the stack to point after our copy of the ROM + */ + + M.x86.R_SS = SEGMENT(stackaddr - 8); + M.x86.R_SP = OFFSET(stackaddr - 8); + + /* + * GROSS! The Voodoo3 card expects BP to have + * the following value: + */ + + M.x86.R_BP = 0x197; + + /* + * The PCI BIOS spec says you pass the bus, device, and function + * numbers in the AX register when starting the ROM code. + */ + + pci_break_tag(tag,&bus,&device,&function); + M.x86.R_AH = bus; + M.x86.R_AL = (device << 3) | (function & 7); + + /* + * Arrange for the return address to point to a little piece + * of code that will do an int10 to set text mode, followed + * by storing a couple of simple signatures in the registers, + * and an int3 to stop the simulator. + * + * The location of this piece of code is just after our + * stack, and since the stack grows down, this is in 'stackaddr' + */ + + __x86emu_wrw(stackaddr-8,OFFSET(stackaddr)); + __x86emu_wrw(stackaddr-6,SEGMENT(stackaddr)); + + /* copy in the code. */ + + for (idx = 0; idx < sizeof(x86initcode); idx++) { + __x86emu_wrb(stackaddr+idx,x86initcode[idx]); + } + + /* + * Set up the VGA console descriptor. We need this to process the + * int10's that write firmware copyright notices and such. + */ + + vga_init(&vga,(__ISAaddr(VGA_TEXTBUF_COLOR)),outb); + + /* + * Launch the simulator. + */ + + xprintf("Initializing VGA.\n"); +#ifdef DEBUG + X86EMU_trace_on(); +#endif + X86EMU_exec(); + + /* + * Check for the magic exit values in the registers. These get set + * by the code in the array 'x86initcode' that was loaded above + */ + + if ((M.x86.R_AX == 0x1234) && (M.x86.R_BX == 0x5678)) res = 0; + else res = -1; + + /* + * Done! + */ + + x86uninit(); + + if (res < 0) { + xprintf("VGA initialization failed.\n"); + } + else { + char temp[32]; + char *str = "If you can see this message, the VGA has been successfully initialized!\r\n\r\n"; + + xprintf("VGA initialization successful.\n"); + vga_writestr(&vga,str,0x07,strlen(str)); + + sprintf(temp,"%d",VGA_TEXTMODE_ROWS); + env_setenv("VGA_ROWS",temp,ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); + sprintf(temp,"%d",VGA_TEXTMODE_COLS); + env_setenv("VGA_COLS",temp,ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); + + } + + return res; +} + +int x86emutest(void) +{ + uint32_t destaddr; + uint32_t stackaddr; + int res; + + /* + * Initialize the X86 emulator + */ + + if (x86init() != 0) { + xprintf("X86 emulator did not initialize.\n"); + return -1; + } + + destaddr = BIOSRAMLOC; + stackaddr = destaddr + 1024; + + /* + * Copy the BIOS from the PCI rom into RAM + */ + + xprintf("Copying test program to RAM.\n"); + x86mem_memcpy(&x86mem,destaddr,x86testcode,sizeof(x86testcode)); + + /* + * The actual code begins 3 bytes after the beginning of the ROM. Set + * the start address to the first byte of executable code. + */ + + M.x86.R_CS = SEGMENT(destaddr + PCIBIOS_ROMENTRY_OFFSET); + M.x86.R_IP = OFFSET(destaddr + PCIBIOS_ROMENTRY_OFFSET); + + /* + * Set the stack to point after our copy of the ROM + */ + + M.x86.R_SS = SEGMENT(stackaddr - 8); + M.x86.R_SP = OFFSET(stackaddr - 8); + + /* + * Launch the simulator. + */ + + xprintf("Running X86emu test.\n"); +#ifdef DEBUG + X86EMU_trace_on(); +#endif + X86EMU_exec(); + + /* + * Check for the magic exit values in the registers. These get set + * by the code in the array 'x86initcode' that was loaded above + */ + + if ((M.x86.R_AX == 0x1234) && (M.x86.R_BX == 0x5678)) res = 0; + else res = -1; + + /* + * Done! + */ + + x86uninit(); + + if (res < 0) xprintf("X86emu test failed.\n"); + else xprintf("X86emu test successful.\n"); + + return res; +} + + + +void vgaraw_dump(char *tail) +{ + physaddr_t biosaddr; + pcitag_t tag; + uint32_t addr; + uint32_t romaddr; + unsigned int biossize; + int idx; + int res; + + if (pci_find_class(PCI_CLASS_DISPLAY,0,&tag) == 0) { + romaddr = pci_conf_read(tag,PCI_MAPREG_ROM); + pci_conf_write(tag,PCI_MAPREG_ROM,romaddr | PCI_MAPREG_ROM_ENABLE); + } + else { + xprintf("No suitable VGA device found in the system.\n"); + return ; + } + + addr = romaddr; + addr &= PCI_MAPREG_ROM_ADDR_MASK; + + /* XXX This won't work if the PCI space is remapped somewhere else. */ +#if defined(_P5064_) || defined(_P6064_) + biosaddr = cpu_isamap((vm_offset_t) romaddr,0); +#else + biosaddr = romaddr; +#endif + + /* + * Check for the presence of a VGA BIOS on this adapter. + */ + + xprintf("VGA BIOS is mapped to %08X\n",(uint32_t) biosaddr); + + if (!((phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+0) == PCIBIOS_ROMSIG1) && + (phys_read8(biosaddr+PCIBIOS_ROMSIG_OFFSET+1) == PCIBIOS_ROMSIG2))) { + xprintf("No VGA BIOS on this adapter, assuming 32K ROM\n"); + biossize = 32768; + return; + } + else { + biossize = PCIBIOS_ROMSIZE(phys_read8(biosaddr+PCIBIOS_ROMSIZE_OFFSET)); + xprintf("VGA BIOS size is %d bytes\n",biossize); + } + + for (idx = 0; idx < biossize; idx+=16) { + xprintf("%04X: ",idx); + for (res = 0; res < 16; res++) { + xprintf("%02X ",phys_read8(biosaddr+idx+res)); + } + xprintf("\n"); + if (console_status()) break; + } + +// pci_conf_write(tag,PCI_MAPREG_ROM,romaddr); + +} diff --git a/cfe/cfe/pccons/x86mem.c b/cfe/cfe/pccons/x86mem.c new file mode 100644 index 0000000..2e9c49e --- /dev/null +++ b/cfe/cfe/pccons/x86mem.c @@ -0,0 +1,423 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * X86 simulator sparse memory File: X86MEM.C + * + * This module implements X86 memory for the X86 emulator + * used by the BIOS simulator. To avoid allocating the + * entire 1MB of PC's addressable memory, this is a "sparse" + * memory model, allocating chunks of storage as needed. + * VGA BIOSes seem to do all sorts of bizarre things to memory + * so this helps reduce the total amount we need to allocate + * significantly. + * + * In addition, this module lets the simulator "hook" + * ranges of memory to be handled by a callback + * routine. This is used so that we can redirect + * accesses to VGA memory space to the PCI bus handler. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "x86mem.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define BSWAP_SHORT(s) ((((s) >> 8) & 0xFF) | (((s)&0xFF) << 8)) +#define BSWAP_LONG(s) ((((s) & 0xFF000000) >> 24) | \ + (((s) & 0x00FF0000) >> 8) | \ + (((s) & 0x0000FF00) << 8) | \ + (((s) & 0x000000FF) << 24)) + + +/* ********************************************************************* + * X86MEM_INIT() + * + * Initialize an X86mem object + * + * Input parameters: + * mem - X86mem object + * + * Return value: + * nothing + ********************************************************************* */ + +void x86mem_init(x86mem_t *mem) +{ + memset(mem,0,sizeof(mem)); +} + +/* ********************************************************************* + * X86MEM_UNINIT(mem) + * + * Uninitialize an X86mem object, freeing any storage + * associated with it. + * + * Input parameters: + * mem - x86mem object + * + * Return value: + * nothing + ********************************************************************* */ + +void x86mem_uninit(x86mem_t *mem) +{ + int idx; + + for (idx = 0; idx < X86MEM_CHUNKS; idx++) { + if (mem->data[idx]) { + KFREE(mem->data[idx]); + mem->data[idx] = NULL; + } + } +} + +/* ********************************************************************* + * X86MEM_READB(mem,addr) + * + * Read a byte of memory from the X86mem object. + * + * Input parameters: + * mem - x86mem object + * addr - address of byte to read + * + * Return value: + * byte read + ********************************************************************* */ + +uint8_t x86mem_readb(x86mem_t *mem,uint32_t addr) +{ + uint8_t *p; + + if (mem->read[X86MEM_REGION(addr)]) { + return (uint8_t) (*(mem->read[X86MEM_REGION(addr)]))(mem,addr,1); + } + + p = (mem->data[X86MEM_REGION(addr)]); + + if (p) { + return *(p + X86MEM_OFFSET(addr)); + } + else { + return 0; + } +} + +/* ********************************************************************* + * X86MEM_READW(mem,addr) + * + * Read a 16-bit word of memory from the X86mem object. + * + * Input parameters: + * mem - x86mem object + * addr - address of word to read + * + * Return value: + * word read + ********************************************************************* */ + +uint16_t x86mem_readw(x86mem_t *mem,uint32_t addr) +{ + uint8_t *p; + uint16_t ret; + + if (mem->read[X86MEM_REGION(addr)]) { + return (uint8_t) (*(mem->read[X86MEM_REGION(addr)]))(mem,addr,2); + } + + p = (mem->data[X86MEM_REGION(addr)]); + if (!p) return 0; + + if ((addr & 1) || (X86MEM_OFFSET(addr) == X86MEM_CHUNKSIZE-1)) { + + ret = ((uint16_t) x86mem_readb(mem,addr+0)) | + (((uint16_t) x86mem_readb(mem,addr+1)) << 8); + return ret; + } + else { + ret = *((uint16_t *) (p+X86MEM_OFFSET(addr))); +#ifdef __MIPSEB + ret = BSWAP_SHORT(ret); +#endif + } + + return ret; +} + +/* ********************************************************************* + * X86MEM_READL(mem,addr) + * + * Read a 32-bit dword of memory from the X86mem object. + * + * Input parameters: + * mem - x86mem object + * addr - address of dword to read + * + * Return value: + * dword read + ********************************************************************* */ + +uint32_t x86mem_readl(x86mem_t *mem,uint32_t addr) +{ + uint8_t *p; + uint32_t ret; + + if (mem->read[X86MEM_REGION(addr)]) { + return (uint8_t) (*(mem->read[X86MEM_REGION(addr)]))(mem,addr,4); + } + + p = (mem->data[X86MEM_REGION(addr)]); + if (!p) return 0; + + if ((addr & 3) || (X86MEM_OFFSET(addr) >= X86MEM_CHUNKSIZE-3)) { + ret = ((uint32_t) x86mem_readb(mem,addr+0)) | + (((uint32_t) x86mem_readb(mem,addr+1)) << 8) | + (((uint32_t) x86mem_readb(mem,addr+2)) << 16) | + (((uint32_t) x86mem_readb(mem,addr+3)) << 24); + } + else { + ret = *((uint32_t *) (p+X86MEM_OFFSET(addr))); +#ifdef __MIPSEB + ret = BSWAP_LONG(ret); +#endif + } + + return ret; +} + +/* ********************************************************************* + * X86MEM_WRITEB(mem,addr,data) + * + * Write a byte to the X86mem object + * + * Input parameters: + * mem - x86mem object + * addr - address of byte to write + * data - data to write + * + * Return value: + * nothing + ********************************************************************* */ +void x86mem_writeb(x86mem_t *mem,uint32_t addr,uint8_t data) +{ + uint8_t *p; + + if (mem->write[X86MEM_REGION(addr)]) { + (*(mem->write[X86MEM_REGION(addr)]))(mem,addr,data,1); + return; + } + + p = (mem->data[X86MEM_REGION(addr)]); + + if (p) { + *(p + X86MEM_OFFSET(addr)) = data; + } + else { + p = mem->data[X86MEM_REGION(addr)] = KMALLOC(X86MEM_CHUNKSIZE,sizeof(uint32_t)); + if (p) { + memset(p,0,X86MEM_CHUNKSIZE); + *(p + X86MEM_OFFSET(addr)) = data; + } + } +} + +/* ********************************************************************* + * X86MEM_WRITEW(mem,addr,data) + * + * Write a 16-bit word to the X86mem object + * + * Input parameters: + * mem - x86mem object + * addr - address of word to write + * data - data to write + * + * Return value: + * nothing + ********************************************************************* */ +void x86mem_writew(x86mem_t *mem,uint32_t addr,uint16_t data) +{ + uint8_t *p; + + if (mem->write[X86MEM_REGION(addr)]) { + (*(mem->write[X86MEM_REGION(addr)]))(mem,addr,data,2); + return; + } + + p = (mem->data[X86MEM_REGION(addr)]); + + if (!p || (addr & 1) || (X86MEM_OFFSET(addr) == X86MEM_CHUNKSIZE-1)) { + x86mem_writeb(mem,addr+0,(data & 0xFF)); + x86mem_writeb(mem,addr+1,((data >> 8) & 0xFF)); + } + else { +#ifdef __MIPSEB + data = BSWAP_SHORT(data); +#endif + *((uint16_t *) (p+X86MEM_OFFSET(addr))) = data; + } +} + +/* ********************************************************************* + * X86MEM_WRITEL(mem,addr,data) + * + * Write a 32-bit dword to the X86mem object + * + * Input parameters: + * mem - x86mem object + * addr - address of dword to write + * data - data to write + * + * Return value: + * nothing + ********************************************************************* */ +void x86mem_writel(x86mem_t *mem,uint32_t addr,uint32_t data) +{ + uint8_t *p; + + if (mem->write[X86MEM_REGION(addr)]) { + (*(mem->write[X86MEM_REGION(addr)]))(mem,addr,data,4); + return; + } + + p = (mem->data[X86MEM_REGION(addr)]); + + if (!p || (addr & 3) || (X86MEM_OFFSET(addr) >= X86MEM_CHUNKSIZE-3)) { + x86mem_writeb(mem,addr+0,(data & 0xFF)); + x86mem_writeb(mem,addr+1,((data >> 8) & 0xFF)); + x86mem_writeb(mem,addr+2,((data >> 16) & 0xFF)); + x86mem_writeb(mem,addr+3,((data >> 24) & 0xFF)); + } + else { +#ifdef __MIPSEB + data = BSWAP_LONG(data); +#endif + *((uint32_t *) (p+X86MEM_OFFSET(addr))) = data; + } +} + +/* ********************************************************************* + * X86MEM_MEMCPY(mem,dest,src,cnt) + * + * memcpy data into the X86mem object + * + * Input parameters: + * mem - x86mem object + * destaddr - destination x86mem address + * src - source local address + * cnt - number of bytes to copy + * + * Return value: + * nothing + ********************************************************************* */ + +void x86mem_memcpy(x86mem_t *mem,uint32_t destaddr,uint8_t *src,int count) +{ + while (count) { + x86mem_writeb(mem,destaddr,*src); + destaddr++; + src++; + count--; + } +} + + +/* ********************************************************************* + * X86MEM_HOOK(mem,addr,readf,writef) + * + * Establish a hook for a block of simulated memory + * + * Input parameters: + * mem - x86mem object + * addr - address in memory, should be aligned on a "chunk" + * boundary. + * readf - function to call on READ accesses + * writef - function to call on WRITE accesses + * + * Return value: + * nothing + ********************************************************************* */ + +void x86mem_hook(x86mem_t *mem,uint32_t chunkaddr, + uint32_t (*readf)(x86mem_t *mem,uint32_t addr,int size), + void (*writef)(x86mem_t *mem,uint32_t addr,uint32_t val,int size)) +{ + if (mem->data[X86MEM_REGION(chunkaddr)]) { + KFREE(mem->data[X86MEM_REGION(chunkaddr)]); + mem->data[X86MEM_REGION(chunkaddr)] = NULL; + } + mem->read[X86MEM_REGION(chunkaddr)] = readf; + mem->write[X86MEM_REGION(chunkaddr)] = writef; +} + +/* ********************************************************************* + * X86MEM_HOOK_RANGE(mem,addr,size,readf,writef) + * + * Establish a hook for a block of simulated memory + * + * Input parameters: + * mem - x86mem object + * addr - address in memory, should be aligned on a "chunk" + * boundary. + * size - size of region to hook. Should be a multiple + * of the chunk size + * readf - function to call on READ accesses + * writef - function to call on WRITE accesses + * + * Return value: + * nothing + ********************************************************************* */ + +void x86mem_hook_range(x86mem_t *mem,uint32_t chunkaddr,int size, + uint32_t (*readf)(x86mem_t *mem,uint32_t addr,int size), + void (*writef)(x86mem_t *mem,uint32_t addr,uint32_t val,int size)) +{ + while (size > 0) { + x86mem_hook(mem,chunkaddr,readf,writef); + size -= X86MEM_CHUNKSIZE; + chunkaddr += X86MEM_CHUNKSIZE; + } +} + diff --git a/cfe/cfe/pccons/x86mem.h b/cfe/cfe/pccons/x86mem.h new file mode 100644 index 0000000..ed9132b --- /dev/null +++ b/cfe/cfe/pccons/x86mem.h @@ -0,0 +1,109 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * X86 simulator sparse memory File: X86MEM.H + * + * This module implements X86 memory for the X86 emulator + * used by the BIOS simulator. To avoid allocating the + * entire 1MB of PC's addressable memory, this is a "sparse" + * memory model, allocating chunks of storage as needed. + * VGA BIOSes seem to do all sorts of bizarre things to memory + * so this helps reduce the total amount we need to allocate + * significantly. + * + * In addition, this module lets the simulator "hook" + * ranges of memory to be handled by a callback + * routine. This is used so that we can redirect + * accesses to VGA memory space to the PCI bus handler. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define X86MEM_CHUNKBITS 15 +#define X86MEM_ADDRESSBITS 20 +#define X86MEM_CHUNKSIZE (1<> X86MEM_CHUNKBITS) & (X86MEM_CHUNKS-1)) +#define X86MEM_OFFSET(addr) ((addr) & (X86MEM_CHUNKSIZE-1)) + +#define M_BYTE 1 +#define M_WORD 2 +#define M_DWORD 4 + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct x86mem_s { + uint8_t *data[X86MEM_CHUNKS]; + uint32_t (*read[X86MEM_CHUNKS])(struct x86mem_s *x86mem, + uint32_t addr,int size); + void (*write[X86MEM_CHUNKS])(struct x86mem_s *x86mem, + uint32_t addr,uint32_t val,int size); +} x86mem_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +void x86mem_init(x86mem_t *mem); +void x86mem_uninit(x86mem_t *mem); + + +uint8_t x86mem_readb(x86mem_t *mem,uint32_t addr); +uint16_t x86mem_readw(x86mem_t *mem,uint32_t addr); +uint32_t x86mem_readl(x86mem_t *mem,uint32_t addr); + + +void x86mem_writeb(x86mem_t *mem,uint32_t addr,uint8_t data); +void x86mem_writew(x86mem_t *mem,uint32_t addr,uint16_t data); +void x86mem_writel(x86mem_t *mem,uint32_t addr,uint32_t data); +void x86mem_memcpy(x86mem_t *mem,uint32_t destaddr,uint8_t *src,int count); +void x86mem_hook(x86mem_t *mem,uint32_t chunkaddr, + uint32_t (*readf)(x86mem_t *mem,uint32_t addr,int size), + void (*writef)(x86mem_t *mem,uint32_t addr,uint32_t val,int size)); +void x86mem_hook_range(x86mem_t *mem,uint32_t chunkaddr,int size, + uint32_t (*readf)(x86mem_t *mem,uint32_t addr,int size), + void (*writef)(x86mem_t *mem,uint32_t addr,uint32_t val,int size)); + diff --git a/cfe/cfe/pci/cfe_pci.h b/cfe/cfe/pci/cfe_pci.h new file mode 100644 index 0000000..8780a6f --- /dev/null +++ b/cfe/cfe/pci/cfe_pci.h @@ -0,0 +1,52 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PCI definitions File: cfe_pci.h + * + * This file includes other files and defines macros to make + * our environment match that of the PCI configuration code + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" + +#define panic(x) printf(x) diff --git a/cfe/cfe/pci/devlist2h.awk b/cfe/cfe/pci/devlist2h.awk new file mode 100644 index 0000000..1f0b9b4 --- /dev/null +++ b/cfe/cfe/pci/devlist2h.awk @@ -0,0 +1,220 @@ +#! /usr/bin/awk -f +# $NetBSD: devlist2h.awk,v 1.2 1996/01/22 21:08:09 cgd Exp $ +# +# Copyright (c) 1995, 1996 Christopher G. Demetriou +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Christopher G. Demetriou. +# 4. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +BEGIN { + nproducts = nvendors = 0 + dfile="pcidevs_data.h" + hfile="pcidevs.h" +} +NR == 1 { + VERSION = $0 + gsub("\\$", "", VERSION) + + printf("/*\n") > dfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > dfile + printf(" *\n") > dfile + printf(" * generated from:\n") > dfile + printf(" *\t%s\n", VERSION) > dfile + printf(" */\n") > dfile + + printf("/*\n") > hfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > hfile + printf(" *\n") > hfile + printf(" * generated from:\n") > hfile + printf(" *\t%s\n", VERSION) > hfile + printf(" */\n") > hfile + + next +} +$1 == "vendor" { + nvendors++ + + vendorindex[$2] = nvendors; # record index for this name, for later. + vendors[nvendors, 1] = $2; # name + vendors[nvendors, 2] = $3; # id + printf("#define\tPCI_VENDOR_%s\t%s\t", vendors[nvendors, 1], + vendors[nvendors, 2]) > hfile + + i = 3; f = 4; + + # comments + ocomment = oparen = 0 + if (f <= NF) { + printf("\t/* ") > hfile + ocomment = 1; + } + while (f <= NF) { + if ($f == "#") { + printf("(") > hfile + oparen = 1 + f++ + continue + } + if (oparen) { + printf("%s", $f) > hfile + if (f < NF) + printf(" ") > hfile + f++ + continue + } + vendors[nvendors, i] = $f + printf("%s", vendors[nvendors, i]) > hfile + if (f < NF) + printf(" ") > hfile + i++; f++; + } + if (oparen) + printf(")") > hfile + if (ocomment) + printf(" */") > hfile + printf("\n") > hfile + + next +} +$1 == "product" { + nproducts++ + + products[nproducts, 1] = $2; # vendor name + products[nproducts, 2] = $3; # product id + products[nproducts, 3] = $4; # id + printf("#define\tPCI_PRODUCT_%s_%s\t%s\t", products[nproducts, 1], + products[nproducts, 2], products[nproducts, 3]) > hfile + + i=4; f = 5; + + # comments + ocomment = oparen = 0 + if (f <= NF) { + printf("\t/* ") > hfile + ocomment = 1; + } + while (f <= NF) { + if ($f == "#") { + printf("(") > hfile + oparen = 1 + f++ + continue + } + if (oparen) { + printf("%s", $f) > hfile + if (f < NF) + printf(" ") > hfile + f++ + continue + } + products[nproducts, i] = $f + printf("%s", products[nproducts, i]) > hfile + if (f < NF) + printf(" ") > hfile + i++; f++; + } + if (oparen) + printf(")") > hfile + if (ocomment) + printf(" */") > hfile + printf("\n") > hfile + + next +} +{ + if ($0 == "") + blanklines++ + print $0 > hfile + if (blanklines < 2) + print $0 > dfile +} +END { + # print out the match tables + + printf("\n") > dfile + + + printf("static const struct pci_knowndev pci_knowndevs[] = {\n") > dfile + for (i = 1; i <= nproducts; i++) { + printf("\t{\n") > dfile + printf("\t PCI_VENDOR_%s, PCI_PRODUCT_%s_%s,\n", + products[i, 1], products[i, 1], products[i, 2]) \ + > dfile + printf("\t ") > dfile + printf("0") > dfile + printf(",\n") > dfile + + vendi = vendorindex[products[i, 1]]; + printf("\t \"") > dfile + j = 3; + needspace = 0; + while (vendors[vendi, j] != "") { + if (needspace) + printf(" ") > dfile + printf("%s", vendors[vendi, j]) > dfile + needspace = 1 + j++ + } + printf("\",\n") > dfile + + printf("\t \"") > dfile + j = 4; + needspace = 0; + while (products[i, j] != "") { + if (needspace) + printf(" ") > dfile + printf("%s", products[i, j]) > dfile + needspace = 1 + j++ + } + printf("\",\n") > dfile + printf("\t},\n") > dfile + } + for (i = 1; i <= nvendors; i++) { + printf("\t{\n") > dfile + printf("\t PCI_VENDOR_%s, 0,\n", vendors[i, 1]) \ + > dfile + printf("\t PCI_KNOWNDEV_NOPROD,\n") \ + > dfile + printf("\t \"") > dfile + j = 3; + needspace = 0; + while (vendors[i, j] != "") { + if (needspace) + printf(" ") > dfile + printf("%s", vendors[i, j]) > dfile + needspace = 1 + j++ + } + printf("\",\n") > dfile + printf("\t NULL,\n") > dfile + printf("\t},\n") > dfile + } + printf("\t{ 0, 0, 0, NULL, NULL, }\n") > dfile + printf("};\n") > dfile +} diff --git a/cfe/cfe/pci/ldtinit.c b/cfe/cfe/pci/ldtinit.c new file mode 100644 index 0000000..26025af --- /dev/null +++ b/cfe/cfe/pci/ldtinit.c @@ -0,0 +1,641 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * LDT Fabric Initialization File: ldtinit.c + * + ********************************************************************* + * + * Copyright 2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ +/* + * Copyright 2001,2002 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. Neither the "Broadcom + * Corporation" name nor any trademark or logo of Broadcom + * Corporation may be used to endorse or promote products + * derived from this software without the prior written + * permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * ldtinit.c: generic LDT fabric initialization and capability + * management. + */ + +#include "lib_types.h" +#include "lib_printf.h" +#include "cfe_timer.h" + +#include "pcivar.h" +#include "pcireg.h" +#include "ldtreg.h" + +/* Write-to-clear bit masks */ + +#if CFG_LDT_REV_017 /* XXX not really the right test */ +#define LDT_LINKCTRL_WC (LDT_LINKCTRL_CRCERROR_MASK) +#else +#define LDT_LINKCTRL_WC (LDT_LINKCTRL_LINKFAIL | LDT_LINKCTRL_CRCERROR_MASK) +#endif + + +/* LDT capability lookup. */ + +unsigned +pci_find_ldt_cap (pcitag_t tag, int secondary) +{ + pcireg_t cpr; + pcireg_t cr; + int offset, prev; + int type; + + cpr = pci_conf_read(tag, PCI_CAPLISTPTR_REG); + offset = PCI_CAPLIST_PTR(cpr) &~ 0x3; + prev = 0; + + while (offset != 0 && offset != prev) { +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "read cap offset %04x\n", offset); +#endif + cr = pci_conf_read(tag, offset); + if (PCI_CAPLIST_CAP(cr) == PCI_CAP_LDT) { + type = LDT_COMMAND_TYPE(cr); + if (secondary && type == LDT_COMMAND_TYPE_HOST) + return offset; + if (!secondary && type == LDT_COMMAND_TYPE_SLAVE) + return offset; + } + prev = offset; + offset = PCI_CAPLIST_NEXT(cr) &~ 0x3; + } + return 0; +} + + +/* LDT utility functions, mostly for capabilities. */ + +static pcireg_t +ldt_get_link(pcitag_t tag, int offset, int index) +{ + return pci_conf_read(tag, offset + LDT_LINK_OFF(index)); +} + +static void +ldt_set_link(pcitag_t tag, int offset, int index, pcireg_t lr) +{ + pci_conf_write(tag, offset + LDT_LINK_OFF(index), lr); +} + +#if (LDT_DEBUG != 0) +static void +ldt_show_cap(pcitag_t tag, int offset, int secondary) +{ + printf(" Cmd %08x", pci_conf_read(tag, offset)); + offset += 4; + printf(" Lnk0 %08x", pci_conf_read(tag, offset)); + offset += 4; + if (!secondary) { + printf(" Lnk1 %08x", pci_conf_read(tag, offset)); + offset += 4; + } + printf(" Freq0 %08x", pci_conf_read(tag, offset)); + offset += 4; + if (!secondary) { + printf(" Freq1 %08x", pci_conf_read(tag, offset)); + offset += 4; + } + printf("\n"); +} +#else +static void +ldt_show_cap(pcitag_t tag, int offset, int secondary) +{ +} +#endif + + +/* LDT bus initialization and sizing. */ + +/* We expect the entire chain to be ready at approximately the same + time, but we add some delay here for possible node-to-node + differences. + + Empirically, neither InitDone nor LinkFail is reported for an + unconnected link. Thus we do not expect the outgoing link of a + terminating tunnel node to become ready. + + Also, CRC errors are observed to occur with InitDone, so link + errors do not necessarily force LinkFail. +*/ + +static int +ldt_wait_ready (pcitag_t tag, int offset, int index) +{ + int count; + pcireg_t lr; + int linkerr; + + linkerr = 0; + count = 0x10000; /* empirical */ + do { + if (--count == 0) + return 1; + lr = ldt_get_link(tag, offset, index); + if ((lr & (LDT_LINKCTRL_LINKFAIL | LDT_LINKCTRL_CRCERROR_MASK)) != 0) + linkerr = 1; + } while ((lr & (LDT_LINKCTRL_INITDONE | LDT_LINKCTRL_LINKFAIL)) == 0); + + return linkerr; +} + +static void +ldt_end_chain (pcitag_t tag, int offset, int index) +{ + pcireg_t lr, t; + + lr = ldt_get_link(tag, offset, index); + lr |= LDT_LINKCTRL_EOC; + ldt_set_link(tag, offset, index, lr); + lr |= LDT_LINKCTRL_TXOFF; + ldt_set_link(tag, offset, index, lr); + t = ldt_get_link(tag, offset, index); /* push */ +} + + +static uint16_t +ldt_freq_cap (pcitag_t tag, int offset, int index) +{ + pcireg_t cmd, cr; + uint16_t freq_cap; + + cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + if (LDT_COMMAND_TYPE(cmd) == LDT_COMMAND_TYPE_HOST) { + cr = pci_conf_read(tag, offset + LDT_FREQ_OFF); + if (LDT_REVISION_ID(cr) == LDT_REV_017) { + /* REV 0.17 has restricted support for setting + frequencies. We assume that this is the host bridge in + pseudo-1.0x mode, in which case the desired maximum + frequency was left in the LDT_FREQ register and all + lower frequencies are supported. */ + freq_cap = (1 << (LDT_LINKFREQ(cr) + 1)) - 1; + } else { + freq_cap = LDT_LINKFREQ_CAP(cr); + } + } else { + cr = pci_conf_read(tag, offset + LDT_FREQ0_OFF); + if (LDT_REVISION_ID(cr) == LDT_REV_017) { + /* REV 0.17 has restricted support for setting frequencies. + This is not the host bridge. What to do? XXX */ + freq_cap = (1 << LDT_FREQ_200); + } else { + cr = pci_conf_read(tag, offset + LDT_FREQn_OFF(index)); + freq_cap = LDT_LINKFREQ_CAP(cr); + } + } + return freq_cap; +} + +static uint8_t +ldt_max_freq (uint16_t freq_cap) +{ + unsigned ldt_freq; + + /* 200 MHz (encoded as 1 << 0) is required for all devices */ + freq_cap |= (1 << LDT_FREQ_200); + + ldt_freq = 0; + + while (freq_cap != 1) { + ldt_freq++; + freq_cap >>= 1; + } + + return (ldt_freq >= LDT_FREQ_200 && ldt_freq <= LDT_FREQ_1000) ? + ldt_freq : LDT_FREQ_200; +} + +static void +ldt_set_freq (pcitag_t tag, int offset, int index, uint8_t freq) +{ + pcireg_t cmd, cr; + + cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + if (LDT_COMMAND_TYPE(cmd) == LDT_COMMAND_TYPE_HOST) { + cr = pci_conf_read(tag, offset + LDT_FREQ_OFF); + cr &=~ LDT_LINKFREQ_MASK; + cr |= (freq << LDT_LINKFREQ_SHIFT); + pci_conf_write(tag, offset + LDT_FREQ_OFF, cr); + } else { + cr = pci_conf_read(tag, offset + LDT_FREQn_OFF(index)); + cr &=~ LDT_LINKFREQ_MASK; + cr |= (freq << LDT_LINKFREQ_SHIFT); + pci_conf_write(tag, offset + LDT_FREQn_OFF(index), cr); + } +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "set link %d freq = %02x\n", index, freq); +#endif +} + + +/* LDT fabric initialization. See LDT Spec, Section 13.3. */ +static int +ldt_fabric_init (pcitag_t br_tag, int br_offset, int bus, pci_flags_t flags) +{ + int next_free_id; + pcitag_t prev_tag, tag; + int offset, prev_offset; + int link, prev_link; + uint16_t prev_cap; + pcireg_t cmd, lr, id, t; + int double_ended; + int linkerr; + + prev_tag = br_tag; prev_offset = br_offset; prev_link = 0; + /* Since there is no direct peer-to-peer traffic, there is no + point in configuring a downstream link with more capability + than the current one. */ + prev_cap = ldt_freq_cap(br_tag, br_offset, 0); + + next_free_id = 1; + double_ended = 0; + +#if (LDT_DEBUG != 0) + printf("Link sizing for bus %d, bridge freq cap %04x\n", + bus, ldt_freq_cap(br_tag, br_offset, 0)); +#endif + for (;;) { + + tag = pci_make_tag(bus, 0, 0); + + id = pci_conf_read(tag, PCI_ID_REG); +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "ldt_fabric_init: id register %08x\n", id); +#endif + if (PCI_VENDOR(id) == 0xffff) { + /* The incoming link had InitDone set, but we got an NXA + trying to read the vendor id. Either the reverse link + is broken or we have found an LDT-Lite node. For now, + assume the latter. Since an LDT-Lite device cannot be + a tunnel, assume the chain terminates here. */ + pci_tagprintf(tag, "assumed LDT-LITE device (virtual unit %d)\n", + next_free_id); + break; + } + + offset = pci_find_ldt_cap(tag, LDT_PRIMARY); +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "ldt_fabric_init: offset %08x\n", offset); +#endif + if (offset == 0) { + /* There is no primary interface; we must have found a host. */ + offset = pci_find_ldt_cap(tag, LDT_SECONDARY); + if (offset != 0) { + lr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + lr |= LDT_COMMAND_DOUBLE_ENDED; + pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, lr); + double_ended = 1; + } + break; + } + + /* Otherwise, we have the primary interface. */ + + /* Rewrite the old value to set master host bit. */ + cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "ldt_fabric_init: set master host\n"); +#endif + pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cmd); + cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); /* push */ + + id = pci_conf_read(tag, PCI_ID_REG); + + /* Update the unit id, gingerly. */ + cmd &= ~LDT_COMMAND_UNIT_ID_MASK; + cmd |= (next_free_id << LDT_COMMAND_UNIT_ID_SHIFT); +#if (LDT_DEBUG != 0) + pci_tagprintf(tag, "ldt_fabric_init: set unit id %d\n", next_free_id); +#endif + if (!pci_conf_write_acked(tag, offset + LDT_COMMAND_CAP_OFF, cmd)) { + pci_tagprintf(tag, "no ack of id update to %d\n", next_free_id); + } + + /* The unit id just changed. Update the tag */ + tag = pci_make_tag(bus, next_free_id, 0); +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "ldt_fabric_init: check unit id\n"); +#endif + t = pci_conf_read(tag, PCI_ID_REG); + if (t != id) { + pci_tagprintf(tag, "id mismatch: old %08x, new %08x\n", id, t); + } + + next_free_id += LDT_COMMAND_UNIT_COUNT(cmd); + + link = LDT_COMMAND_MASTER_HOST(cmd); /* Upstream link index */ + + /* LDT Rev 0.17 does not support frequency updates. */ + if ((flags & PCI_FLG_LDT_REV_017) == 0) { + /* Find common frequency for upstream link. */ + uint16_t link_cap, freq_cap_in, freq_cap_out; + uint8_t ldt_freq; + + freq_cap_out = ldt_freq_cap(prev_tag, prev_offset, prev_link); + freq_cap_in = ldt_freq_cap(tag, offset, link); + link_cap = freq_cap_in & freq_cap_out; + ldt_freq = ldt_max_freq(link_cap & prev_cap); + +#if (LDT_DEBUG != 0) + pci_tagprintf(tag, "set freq %d\n", ldt_freq); +#endif + /* Set up frequency registers, next warm reset installs. */ + ldt_set_freq(prev_tag, prev_offset, prev_link, ldt_freq); + ldt_set_freq(tag, offset, link, ldt_freq); + + prev_cap &= link_cap; + } + + link ^= 1; /* Downstream */ + linkerr = ldt_wait_ready(tag, offset, link); + lr = ldt_get_link(tag, offset, link); + ldt_set_link(tag, offset, link, lr | LDT_LINKCTRL_WC); + +#if (LDT_DEBUG != 0) + pci_tagprintf(tag, "node: up %d down %d:\n", link ^ 1, link); +#endif + ldt_show_cap(tag, offset, LDT_PRIMARY); + + if (linkerr || next_free_id > 0x1f) { + /* No downstream link or too many devices, set end of chain */ + ldt_end_chain(tag, offset, link); + break; + } + + prev_tag = tag; prev_offset = offset; prev_link = link; + } + + return double_ended; +} + + +static int +ldt_fabric_reinit (int bus) +{ + int next_free_id; + pcitag_t tag; + int offset; + int link; + pcireg_t cmd, lr, id, t; + int linkerr; + + next_free_id = 1; + +#if (LDT_DEBUG != 0) + printf("Link resizing for bus %d\n", bus); +#endif + for (;;) { + + tag = pci_make_tag(bus, 0, 0); + + id = pci_conf_read(tag, PCI_ID_REG); + if (PCI_VENDOR(id) == 0xffff) { + /* Per the init pass, assume this indicates a link to an + LDT-Lite node, and the chain terminates here. */ + break; + } + + offset = pci_find_ldt_cap(tag, LDT_PRIMARY); + if (offset == 0) { + /* There is no primary interface; we must have found a host. */ + offset = pci_find_ldt_cap(tag, LDT_SECONDARY); + if (offset != 0) { + lr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + lr |= LDT_COMMAND_DOUBLE_ENDED; + pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, lr); + } + break; + } + + /* Otherwise, we have the primary interface. */ + + /* Rewrite the old value to set master host bit. */ + cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cmd); + cmd = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + + id = pci_conf_read(tag, PCI_ID_REG); + + /* (Re)update the unit id. See above. */ + cmd &= ~LDT_COMMAND_UNIT_ID_MASK; + cmd |= (next_free_id << LDT_COMMAND_UNIT_ID_SHIFT); + if (!pci_conf_write_acked(tag, offset + LDT_COMMAND_CAP_OFF, cmd)) { + pci_tagprintf(tag, "no ack of id update to %d\n", next_free_id); + } + + /* The unit id just changed. Update the tag */ + tag = pci_make_tag(bus, next_free_id, 0); + t = pci_conf_read(tag, PCI_ID_REG); /* for good measure */ + if (t != id) { + pci_tagprintf(tag, "id mismatch: old %08x, new %08x\n", id, t); + } + + next_free_id += LDT_COMMAND_UNIT_COUNT(cmd); + + link = LDT_COMMAND_MASTER_HOST(cmd); /* Upstream link index */ + link ^= 1; /* Downstream */ + + linkerr = ldt_wait_ready(tag, offset, link); + + lr = ldt_get_link(tag, offset, link); + ldt_set_link(tag, offset, link, lr | LDT_LINKCTRL_WC); +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "node: up %d down %d:\n", link ^ 1, link); + ldt_show_cap(tag, offset, LDT_PRIMARY); +#endif + if (linkerr || next_free_id > 0x1f) { + /* No downstream link or too many devices, set end of chain */ + ldt_end_chain(tag, offset, link); + break; + } + } + return next_free_id - 1; +} + + +/* LDT link reset (warm or cold as set by caller) */ + +void +ldt_link_reset (pcitag_t tag, int delay) +{ + pcireg_t brctl; + + /* This code may be necessary for LDT buses behind bridges (none + of which yet exist) but seems to be a bad idea for the SB-1250 + LDT bus in pass 1 parts. Note that if we do reset, we must + delay to give any attached devices a chance to (re)initialize + per the PCI spec. */ + + /* Attempt a Secondary Bus Reset. */ + brctl = pci_conf_read(tag, PPB_BRCTL_INTERRUPT_REG); + brctl |= PPB_BRCTL_SECONDARY_RESET; + pci_conf_write(tag, PPB_BRCTL_INTERRUPT_REG, brctl); + + brctl = pci_conf_read(tag, PPB_BRCTL_INTERRUPT_REG); + if ((brctl & PPB_BRCTL_SECONDARY_RESET) != 0) { + int i; + /* Bit can be written, assume soft reset is implemented. */ + brctl &=~ PPB_BRCTL_SECONDARY_RESET; + pci_conf_write(tag, PPB_BRCTL_INTERRUPT_REG, brctl); + + /* Add some delay (duration is a guess) */ + for (i = 0; i < delay; i++) + (void)pci_conf_read(tag, PPB_BRCTL_INTERRUPT_REG); + /* Alternatively, wait for LinkFail or InitDone. */ + } +} + + +/* LDT bridge and fabric initialization for a secondary chain */ + +int +ldt_chain_init (pcitag_t tag, int bus, pci_flags_t flags) +{ + int offset; + int double_ended; + int linkerr; + pcireg_t cr, lr; + int ndev, no_probe; + +#if 0 + /* This code may be necessary for LDT buses behind bridges (none + of which yet exist) but seems to be a bad idea for the SB-1250 + LDT bus in pass 1 parts. Note that if we do reset, we must + delay to give any attached devices a chance to (re)initialize + per the PCI spec. */ + + /* Attempt a Secondary Bus Reset. */ + ldt_link_reset(tag, 100); +#endif /* 0 */ + + /* To avoid a chip erratum, we must prevent Type 0 configuration + probes that get NXAs on a double hosted chain. */ + no_probe = 0; + + offset = pci_find_ldt_cap(tag, LDT_SECONDARY); + if (offset != 0) { + linkerr = ldt_wait_ready(tag, offset, 0); + +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "bridge secondary:\n"); + ldt_show_cap(tag, offset, LDT_SECONDARY); +#endif + if (linkerr) { + pci_tagprintf(tag, "secondary bad or never ready\n"); + } else { + lr = ldt_get_link(tag, offset, 0); + if ((lr & LDT_LINKCTRL_INITDONE) != 0) + double_ended = ldt_fabric_init(tag, offset, bus, flags); + else { + ldt_end_chain(tag, offset, 0); + double_ended = 0; + } + cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + if (double_ended) + cr |= LDT_COMMAND_DOUBLE_ENDED; + else + cr &=~ LDT_COMMAND_DOUBLE_ENDED; + pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cr); + + /* Rev 0.17 does not support dynamic link resizing. */ + if ((flags & PCI_FLG_LDT_REV_017) == 0) { + /* Issue a warm reset to update link frequencies. */ + cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + cr |= LDT_COMMAND_WARM_RESET; + pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cr); + cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + ldt_link_reset(tag, 100); + ldt_wait_ready(tag, offset, 0); + +#if (LDT_DEBUG > 1) + pci_tagprintf(tag, "bridge secondary:\n"); + ldt_show_cap(tag, offset, LDT_SECONDARY); +#endif + /* After reset, let secondary devices reinitialize. */ + cfe_sleep(CFE_HZ/2); + + ndev = ldt_fabric_reinit(bus); + + if (double_ended) { + cr = pci_conf_read(tag, offset + LDT_COMMAND_CAP_OFF); + cr |= LDT_COMMAND_DOUBLE_ENDED; + pci_conf_write(tag, offset + LDT_COMMAND_CAP_OFF, cr); + + /* Bug workaround -- don't scan simple dual-hosted chain */ + if (ndev == 0) + no_probe = 1; + } + } + } + } + + return no_probe; +} diff --git a/cfe/cfe/pci/ldtreg.h b/cfe/cfe/pci/ldtreg.h new file mode 100644 index 0000000..140effe --- /dev/null +++ b/cfe/cfe/pci/ldtreg.h @@ -0,0 +1,184 @@ +/* + * Copyright 2000,2001 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. Neither the "Broadcom + * Corporation" name nor any trademark or logo of Broadcom + * Corporation may be used to endorse or promote products + * derived from this software without the prior written + * permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LDTREG_H_ +#define _LDTREG_H_ + +/* + * LDT capability register definitions and macros. + * Derived from Revison 0.17 of the LDT (now HyperTransport) + * Specification with some 1.02/1.03 features. + * + * Note: Register and field definitions assume 32-bit register accesses. + */ + +/* + * LDT Capability registers (identified by offsets within the capability) + */ + +/* + * Command Register; contains command and capability fields. + */ +#define LDT_COMMAND_CAP_OFF 0x00 + +#define LDT_CAP_ID_MASK 0x000000ff +#define LDT_CAP_ID_SHIFT 0 +#define LDT_CAP_PTR_MASK 0x0000ff00 +#define LDT_CAP_PTR_SHIFT 8 + +#define LDT_COMMAND_MASK 0xffff0000 +#define LDT_COMMAND_SHIFT 16 +#define LDT_COMMAND(cmd) \ + (((cmd) & LDT_COMMAND_MASK) >> LDT_COMMAND_SHIFT) +#define LDT_COMMAND_TYPE_MASK 0xe0000000 +#define LDT_COMMAND_TYPE_SHIFT (16+13) +#define LDT_COMMAND_TYPE(cmd) \ + (((cmd) & LDT_COMMAND_TYPE_MASK) >> LDT_COMMAND_TYPE_SHIFT) +#define LDT_COMMAND_TYPE_SLAVE 0x0 +#define LDT_COMMAND_TYPE_HOST 0x1 +#define LDT_COMMAND_TYPE_IDC 0x4 +#define LDT_COMMAND_TYPE_AMAP 0x5 +/* Following for 1.0x only */ +#define LDT_COMMAND_DROP_ON_INIT 0x10000000 + +/* + * An LDT capability for type Slave (aka Primary, aka "tunnel") consists + * of a Command register, two Link registers, and two Freq/Rev registers. + */ +/* Slave/Primary commands */ +#define LDT_COMMAND_UNIT_ID_MASK 0x001f0000 +#define LDT_COMMAND_UNIT_ID_SHIFT (16+0) +#define LDT_COMMAND_UNIT_ID(cmd) \ + (((cmd) & LDT_COMMAND_UNIT_ID_MASK) >> LDT_COMMAND_UNIT_ID_SHIFT) +#define LDT_COMMAND_UNIT_COUNT_MASK 0x03e00000 +#define LDT_COMMAND_UNIT_COUNT_SHIFT (16+5) +#define LDT_COMMAND_UNIT_COUNT(cmd) \ + (((cmd) & LDT_COMMAND_UNIT_COUNT_MASK) >> LDT_COMMAND_UNIT_COUNT_SHIFT) +#define LDT_COMMAND_MASTER_HOST_MASK 0x04000000 +#define LDT_COMMAND_MASTER_HOST(cmd) \ + (((cmd) & LDT_COMMAND_MASTER_HOST_MASK) ? 1 : 0) +#define LDT_COMMAND_DEFAULT_DIRECTION_MASK 0x08000000 +#define LDT_COMMAND_DEFAULT_DIRECTION(cmd) \ + (((cmd) & LDT_COMMAND_DEFAULT_DIRECTION_MASK) ? 1 : 0) + +/* + * An LDT capability for type Host (aka Secondary) consists of a + * Command register, a single Link register, and a Freq/Rev register. + */ +/* Host/Secondary command fields */ +#define LDT_COMMAND_WARM_RESET 0x00010000 +#define LDT_COMMAND_DOUBLE_ENDED 0x00020000 +#define LDT_COMMAND_DEVICE_NUMBER_MASK 0x007c0000 +#define LDT_COMMAND_DEVICE_NUMBER_SHIFT (16+2) +/* Following for 1.0x only */ +#define LDT_COMMAND_CHAIN_SIDE 0x00800000 +#define LDT_COMMAND_HOST_HIDE 0x01000000 +#define LDT_COMMAND_ACT_AS_SLAVE 0x02000000 +#define LDT_COMMAND_INBOUND_EOC_ERROR 0x04000000 + + +/* + * Link Register; contains control and config fields. + */ +#define LDT_LINK_OFF(n) (0x04 + ((n)<<2)) + +#define LDT_LINKCTRL_MASK 0x0000ffff +#define LDT_LINKCTRL_SHIFT 0 +#define LDT_LINKCTRL(cr) \ + (((cr) & LDT_LINKCTRL_MASK) >> LDT_LINKCTRL_SHIFT) +#define LDT_LINKCTRL_CFLE 0x00000002 +#define LDT_LINKCTRL_CST 0x00000004 +#define LDT_LINKCTRL_CFE 0x00000008 +#define LDT_LINKCTRL_LINKFAIL 0x00000010 +#define LDT_LINKCTRL_INITDONE 0x00000020 +#define LDT_LINKCTRL_EOC 0x00000040 +#define LDT_LINKCTRL_TXOFF 0x00000080 +#define LDT_LINKCTRL_CRCERROR_MASK 0x00000f00 +#define LDT_LINKCTRL_CRCERROR_SHIFT 8 +#define LDT_LINKCTRL_ISOCEN 0x00001000 +#define LDT_LINKCTRL_LSEN 0x00002000 +/* Following for 1.0x only */ +#define LDT_LINKCTRL_EXTCTL 0x00004000 + +#define LDT_LINKCFG_MASK 0xffff0000 +#define LDT_LINKCFG_SHIFT 16 +#define LDT_LINKCFG(cr) \ + (((cr) & LDT_LINKCFG_MASK) >> LDT_LINKCFG_SHIFT) +#define LDT_LINKCFG_MAX_WIDTH_IN(cr) \ + (((cr) >> (16+0)) & 0xf) +#define LDT_LINKCFG_MAX_WIDTH_OUT(cr) \ + (((cr) >> (16+4)) & 0xf) +#define LDT_LINKCFG_WIDTH_IN(cr) \ + (((cr) >> (16+8)) & 0xf) +#define LDT_LINKCFG_WIDTH_OUT(cr) \ + (((cr) >> (16+12)) & 0xf) + + +/* + * Link Frequency Register; contains version and frequency fields. + */ +#define LDT_LINKFREQ_CAP(cr) \ + (((cr) >> 16) & 0xffff) + +#define LDT_LINKFREQ_MASK 0x00000f00 +#define LDT_LINKFREQ_SHIFT 8 +#define LDT_LINKFREQ(cr) \ + (((cr) >> 8) & 0x0f) + +#define LDT_REVISION_ID(cr) \ + (((cr) >> 0) & 0xff) + +#define LDT_REV_017 0x11 +#define LDT_REV_102 0x22 + +/* Slave/Primary offsets */ +#define LDT_FREQ0_OFF 0x0c +#define LDT_FREQ1_OFF 0x10 +#define LDT_FREQn_OFF(n) (0x0c + ((n)<<2)) + +/* Host/Secondary offsets */ +#define LDT_FREQ_OFF 0x08 + +#define LDT_FREQ_200 0x00 +#define LDT_FREQ_300 0x01 +#define LDT_FREQ_400 0x02 +#define LDT_FREQ_500 0x03 +#define LDT_FREQ_600 0x04 +#define LDT_FREQ_800 0x05 +#define LDT_FREQ_1000 0x06 + +#endif /* _LDTREG_H_ */ diff --git a/cfe/cfe/pci/pci_machdep.h b/cfe/cfe/pci/pci_machdep.h new file mode 100644 index 0000000..c8b57ec --- /dev/null +++ b/cfe/cfe/pci/pci_machdep.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2001,2002 SiByte, Inc. All rights reserved. + */ + +#ifndef _PCI_MACHDEP_H_ +#define _PCI_MACHDEP_H_ + +/* + * Machine-specific definitions for PCI autoconfiguration. + * + * See the comments in pci_machdep.c for more explanation. + */ + +#include "lib_types.h" + +/* + * Address types, as integers. + */ + +typedef uint32_t pci_addr_t; +typedef uint64_t phys_addr_t; /* ZBbus physical addresses. */ + +/* + * Configuration tag; created from a {bus,device,function} triplet by + * pci_make_tag(), and passed to pci_conf_read() and pci_conf_write(). + */ +typedef uint32_t pcitag_t; + +/* + * Type of a value read from or written to a configuration register. + * Always 32 bits. + */ +typedef uint32_t pcireg_t; + +#endif /* _PCI_MACHDEP_H_ */ diff --git a/cfe/cfe/pci/pci_subr.c b/cfe/cfe/pci/pci_subr.c new file mode 100644 index 0000000..56c65b1 --- /dev/null +++ b/cfe/cfe/pci/pci_subr.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 1997 Zubin D. Dittia. All rights reserved. + * Copyright (c) 1995, 1996, 1998 + * Christopher G. Demetriou. All rights reserved. + * Copyright (c) 1994 Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * PCI autoconfiguration support functions. + */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#ifndef PCIVERBOSE +# if CFG_MINIMAL_SIZE +# define PCIVERBOSE 0 +# else +# define PCIVERBOSE 1 +# endif +#endif + +#include "pcireg.h" +#include "pcivar.h" + +const char *pci_findvendor(pcireg_t id_reg); + +static void pci_conf_print_ids(pcireg_t rval, const char *prefix); +static int pci_conf_print_bar (pcitag_t, + const pcireg_t *, int, const char *, int, int); + +/* + * Descriptions of known PCI classes and subclasses. + * + * Subclasses are described in the same way as classes, but have a + * NULL subclass pointer. + */ +struct pci_class { + char *name; + int val; /* as wide as pci_{,sub}class_t */ + struct pci_class *subclasses; +}; + +struct pci_class pci_subclass_prehistoric[] = { + { "miscellaneous", PCI_SUBCLASS_PREHISTORIC_MISC, }, + { "VGA", PCI_SUBCLASS_PREHISTORIC_VGA, }, + { 0 } +}; + +struct pci_class pci_subclass_mass_storage[] = { + { "SCSI", PCI_SUBCLASS_MASS_STORAGE_SCSI, }, + { "IDE", PCI_SUBCLASS_MASS_STORAGE_IDE, }, + { "floppy", PCI_SUBCLASS_MASS_STORAGE_FLOPPY, }, + { "IPI", PCI_SUBCLASS_MASS_STORAGE_IPI, }, + { "RAID", PCI_SUBCLASS_MASS_STORAGE_RAID, }, + { "miscellaneous", PCI_SUBCLASS_MASS_STORAGE_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_network[] = { + { "ethernet", PCI_SUBCLASS_NETWORK_ETHERNET, }, + { "token ring", PCI_SUBCLASS_NETWORK_TOKENRING, }, + { "FDDI", PCI_SUBCLASS_NETWORK_FDDI, }, + { "ATM", PCI_SUBCLASS_NETWORK_ATM, }, + { "ISDN", PCI_SUBCLASS_NETWORK_ISDN, }, + { "WorldFip", PCI_SUBCLASS_NETWORK_WORLDFIP, }, + { "PCMIG MultiComp", PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP, }, + { "miscellaneous", PCI_SUBCLASS_NETWORK_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_display[] = { + { "VGA", PCI_SUBCLASS_DISPLAY_VGA, }, + { "XGA", PCI_SUBCLASS_DISPLAY_XGA, }, + { "3D", PCI_SUBCLASS_DISPLAY_3D, }, + { "miscellaneous", PCI_SUBCLASS_DISPLAY_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_multimedia[] = { + { "video", PCI_SUBCLASS_MULTIMEDIA_VIDEO, }, + { "audio", PCI_SUBCLASS_MULTIMEDIA_AUDIO, }, + { "telephony", PCI_SUBCLASS_MULTIMEDIA_TELEPHONY, }, + { "miscellaneous", PCI_SUBCLASS_MULTIMEDIA_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_memory[] = { + { "RAM", PCI_SUBCLASS_MEMORY_RAM, }, + { "flash", PCI_SUBCLASS_MEMORY_FLASH, }, + { "miscellaneous", PCI_SUBCLASS_MEMORY_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_bridge[] = { + { "host", PCI_SUBCLASS_BRIDGE_HOST, }, + { "ISA", PCI_SUBCLASS_BRIDGE_ISA, }, + { "EISA", PCI_SUBCLASS_BRIDGE_EISA, }, + { "MicroChannel", PCI_SUBCLASS_BRIDGE_MCA, }, + { "PCI", PCI_SUBCLASS_BRIDGE_PCI, }, + { "PCMCIA", PCI_SUBCLASS_BRIDGE_PCMCIA, }, + { "NuBus", PCI_SUBCLASS_BRIDGE_NUBUS, }, + { "CardBus", PCI_SUBCLASS_BRIDGE_CARDBUS, }, + { "RACEway", PCI_SUBCLASS_BRIDGE_RACEWAY, }, + { "Semi-transparent PCI", PCI_SUBCLASS_BRIDGE_STPCI, }, + { "InfiniBand", PCI_SUBCLASS_BRIDGE_INFINIBAND, }, + { "miscellaneous", PCI_SUBCLASS_BRIDGE_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_communications[] = { + { "serial", PCI_SUBCLASS_COMMUNICATIONS_SERIAL, }, + { "parallel", PCI_SUBCLASS_COMMUNICATIONS_PARALLEL, }, + { "multi-port serial", PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL, }, + { "modem", PCI_SUBCLASS_COMMUNICATIONS_MODEM, }, + { "miscellaneous", PCI_SUBCLASS_COMMUNICATIONS_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_system[] = { + { "8259 PIC", PCI_SUBCLASS_SYSTEM_PIC, }, + { "8237 DMA", PCI_SUBCLASS_SYSTEM_DMA, }, + { "8254 timer", PCI_SUBCLASS_SYSTEM_TIMER, }, + { "RTC", PCI_SUBCLASS_SYSTEM_RTC, }, + { "PCI Hot-Plug", PCI_SUBCLASS_SYSTEM_PCIHOTPLUG, }, + { "miscellaneous", PCI_SUBCLASS_SYSTEM_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_input[] = { + { "keyboard", PCI_SUBCLASS_INPUT_KEYBOARD, }, + { "digitizer", PCI_SUBCLASS_INPUT_DIGITIZER, }, + { "mouse", PCI_SUBCLASS_INPUT_MOUSE, }, + { "scanner", PCI_SUBCLASS_INPUT_SCANNER, }, + { "game port", PCI_SUBCLASS_INPUT_GAMEPORT, }, + { "miscellaneous", PCI_SUBCLASS_INPUT_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_dock[] = { + { "generic", PCI_SUBCLASS_DOCK_GENERIC, }, + { "miscellaneous", PCI_SUBCLASS_DOCK_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_processor[] = { + { "386", PCI_SUBCLASS_PROCESSOR_386, }, + { "486", PCI_SUBCLASS_PROCESSOR_486, }, + { "Pentium", PCI_SUBCLASS_PROCESSOR_PENTIUM, }, + { "Alpha", PCI_SUBCLASS_PROCESSOR_ALPHA, }, + { "PowerPC", PCI_SUBCLASS_PROCESSOR_POWERPC, }, + { "MIPS", PCI_SUBCLASS_PROCESSOR_MIPS, }, + { "Co-processor", PCI_SUBCLASS_PROCESSOR_COPROC, }, + { 0 }, +}; + +struct pci_class pci_subclass_serialbus[] = { + { "Firewire", PCI_SUBCLASS_SERIALBUS_FIREWIRE, }, + { "ACCESS.bus", PCI_SUBCLASS_SERIALBUS_ACCESS, }, + { "SSA", PCI_SUBCLASS_SERIALBUS_SSA, }, + { "USB", PCI_SUBCLASS_SERIALBUS_USB, }, + /* XXX Fiber Channel/_FIBRECHANNEL */ + { "Fiber Channel", PCI_SUBCLASS_SERIALBUS_FIBER, }, + { "SMBus", PCI_SUBCLASS_SERIALBUS_SMBUS, }, + { "InfiniBand", PCI_SUBCLASS_SERIALBUS_INFINIBAND, }, + { "IPMI", PCI_SUBCLASS_SERIALBUS_IPMI, }, + { "SERCOS", PCI_SUBCLASS_SERIALBUS_SERCOS, }, + { "CANbus", PCI_SUBCLASS_SERIALBUS_CANBUS, }, + { 0 }, +}; + +struct pci_class pci_subclass_wireless[] = { + { "iRDA", PCI_SUBCLASS_WIRELESS_IRDA, }, + { "Consumer IR", PCI_SUBCLASS_WIRELESS_CONSUMERIR, }, + { "RF", PCI_SUBCLASS_WIRELESS_RF, }, + { "miscellaneous", PCI_SUBCLASS_WIRELESS_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_i2o[] = { + { "1.0", PCI_SUBCLASS_I2O_STANDARD, }, + { 0 }, +}; + +struct pci_class pci_subclass_satcom[] = { + { "TV", PCI_SUBCLASS_SATCOM_TV, }, + { "audio", PCI_SUBCLASS_SATCOM_AUDIO, }, + { "voice", PCI_SUBCLASS_SATCOM_VOICE, }, + { "data", PCI_SUBCLASS_SATCOM_DATA, }, + { 0 }, +}; + +struct pci_class pci_subclass_crypto[] = { + { "network/computing", PCI_SUBCLASS_CRYPTO_NETCOMP, }, + { "entertainment", PCI_SUBCLASS_CRYPTO_ENTERTAINMENT, }, + { "miscellaneous", PCI_SUBCLASS_CRYPTO_MISC, }, + { 0 }, +}; + +struct pci_class pci_subclass_dasp[] = { + { "DPIO", PCI_SUBCLASS_DASP_DPIO, }, + { "time and frequency", PCI_SUBCLASS_DASP_TIMERFREQ, }, + { "miscellaneous", PCI_SUBCLASS_DASP_MISC, }, + { 0 }, +}; + +struct pci_class pci_class[] = { + { "prehistoric", PCI_CLASS_PREHISTORIC, + pci_subclass_prehistoric, }, + { "mass storage", PCI_CLASS_MASS_STORAGE, + pci_subclass_mass_storage, }, + { "network", PCI_CLASS_NETWORK, + pci_subclass_network, }, + { "display", PCI_CLASS_DISPLAY, + pci_subclass_display, }, + { "multimedia", PCI_CLASS_MULTIMEDIA, + pci_subclass_multimedia, }, + { "memory", PCI_CLASS_MEMORY, + pci_subclass_memory, }, + { "bridge", PCI_CLASS_BRIDGE, + pci_subclass_bridge, }, + { "communications", PCI_CLASS_COMMUNICATIONS, + pci_subclass_communications, }, + { "system", PCI_CLASS_SYSTEM, + pci_subclass_system, }, + { "input", PCI_CLASS_INPUT, + pci_subclass_input, }, + { "dock", PCI_CLASS_DOCK, + pci_subclass_dock, }, + { "processor", PCI_CLASS_PROCESSOR, + pci_subclass_processor, }, + { "serial bus", PCI_CLASS_SERIALBUS, + pci_subclass_serialbus, }, + { "wireless", PCI_CLASS_WIRELESS, + pci_subclass_wireless, }, + { "I2O", PCI_CLASS_I2O, + pci_subclass_i2o, }, + { "satellite comm", PCI_CLASS_SATCOM, + pci_subclass_satcom, }, + { "crypto", PCI_CLASS_CRYPTO, + pci_subclass_crypto, }, + { "DASP", PCI_CLASS_DASP, + pci_subclass_dasp, }, + { "undefined", PCI_CLASS_UNDEFINED, + 0, }, + { 0 }, +}; + +#if PCIVERBOSE +/* + * Descriptions of of known vendors and devices ("products"). + */ +#include "pcidevs.h" + +struct pci_knowndev2 { + pci_vendor_id_t vendor; + pci_product_id_t product; + int flags; + int vendorname, productname; +}; +#define PCI_KNOWNDEV_NOPROD 0x01 /* match on vendor only */ +#include "pcidevs_data2.h" + +const char * +pci_findvendor(pcireg_t id_reg) +{ + pci_vendor_id_t vendor = PCI_VENDOR(id_reg); + const struct pci_knowndev2 *kdp; + + kdp = pci_knowndevs; + while (kdp->vendorname != PCI_STRING_NULL) { /* all have vendor name */ + if (kdp->vendor == vendor) + break; + kdp++; + } + if (kdp->vendorname == PCI_STRING_NULL) return NULL; + return PCI_STRING(kdp->vendorname); +} +#else +const char * +pci_findvendor(pcireg_t id_reg) +{ + return NULL; +} +#endif /* PCIVERBOSE */ + +void +pci_devinfo(pcireg_t id_reg, pcireg_t class_reg, int showclass, char *cp) +{ + pci_vendor_id_t vendor; + pci_product_id_t product; + pci_class_t class; + pci_subclass_t subclass; + pci_interface_t interface; + pci_revision_t revision; + const char *vendor_namep, *product_namep; + struct pci_class *classp, *subclassp; +#if PCIVERBOSE + const struct pci_knowndev2 *kdp; + const char *unmatched = "unknown "; +#else + const char *unmatched = ""; +#endif + + vendor = PCI_VENDOR(id_reg); + product = PCI_PRODUCT(id_reg); + + class = PCI_CLASS(class_reg); + subclass = PCI_SUBCLASS(class_reg); + interface = PCI_INTERFACE(class_reg); + revision = PCI_REVISION(class_reg); + +#if PCIVERBOSE + kdp = pci_knowndevs; + while (kdp->vendorname != PCI_STRING_NULL) { /* all have vendor name */ + if (kdp->vendor == vendor && (kdp->product == product || + (kdp->flags & PCI_KNOWNDEV_NOPROD) != 0)) + break; + kdp++; + } + if (kdp->vendorname == PCI_STRING_NULL) + vendor_namep = product_namep = NULL; + else { + vendor_namep = PCI_STRING(kdp->vendorname); + product_namep = ((kdp->flags & PCI_KNOWNDEV_NOPROD) == 0 ? + PCI_STRING(kdp->productname) : NULL); + } +#else /* PCIVERBOSE */ + vendor_namep = product_namep = NULL; +#endif /* PCIVERBOSE */ + + classp = pci_class; + while (classp->name != NULL) { + if (class == classp->val) + break; + classp++; + } + + subclassp = (classp->name != NULL) ? classp->subclasses : NULL; + while (subclassp && subclassp->name != NULL) { + if (subclass == subclassp->val) + break; + subclassp++; + } + + if (vendor_namep == NULL) + cp += sprintf(cp, "%svendor 0x%04x product 0x%04x", + unmatched, vendor, product); + else if (product_namep != NULL) + cp += sprintf(cp, "%s %s", vendor_namep, product_namep); + else + cp += sprintf(cp, "%s product 0x%04x", vendor_namep, product); + if (showclass) { + cp += sprintf(cp, " ("); + if (classp->name == NULL) + cp += sprintf(cp, "class 0x%02x, subclass 0x%02x", + class, subclass); + else { + if (subclassp == NULL || subclassp->name == NULL) + cp += sprintf(cp, "%s subclass 0x%02x", + classp->name, subclass); + else + cp += sprintf(cp, "%s %s", subclassp->name, classp->name); + } + if (interface != 0) + cp += sprintf(cp, ", interface 0x%02x", interface); + if (revision != 0) + cp += sprintf(cp, ", revision 0x%02x", revision); + cp += sprintf(cp, ")"); + } +} + + +/* + * Support routines for printing out PCI configuration registers. + */ + +#define i2o(i) ((i) * 4) +#define o2i(o) ((o) / 4) +#define onoff(str, bit) \ + do { \ + printf(" %s: %s\n", (str), (rval & (bit)) ? "on" : "off"); \ + } while (0) + +#if PCIVERBOSE +static void +pci_conf_print_ids(pcireg_t rval, const char *prefix) +{ + const struct pci_knowndev2 *kdp; + + for (kdp = pci_knowndevs; kdp->vendorname != PCI_STRING_NULL; kdp++) { + if (kdp->vendor == PCI_VENDOR(rval) && + (kdp->product == PCI_PRODUCT(rval) || + (kdp->flags & PCI_KNOWNDEV_NOPROD) != 0)) { + break; + } + } + if (kdp->vendorname != PCI_STRING_NULL) + printf("%sVendor Name: %s (0x%04x)\n", prefix, + PCI_STRING(kdp->vendorname), PCI_VENDOR(rval)); + else + printf("%sVendor ID: 0x%04x\n", prefix, PCI_VENDOR(rval)); + if (kdp->productname != PCI_STRING_NULL + && (kdp->flags & PCI_KNOWNDEV_NOPROD) == 0) + printf("%sDevice Name: %s (0x%04x)\n", prefix, + PCI_STRING(kdp->productname), PCI_PRODUCT(rval)); + else + printf("%sDevice ID: 0x%04x\n", prefix, PCI_PRODUCT(rval)); +} +#else +static void +pci_conf_print_ids(pcireg_t rval, const char *prefix) +{ + printf("%sVendor ID: 0x%04x\n", prefix, PCI_VENDOR(rval)); + printf("%sDevice ID: 0x%04x\n", prefix, PCI_PRODUCT(rval)); +} +#endif /* PCIVERBOSE */ + +static int +pci_conf_print_bar( + pcitag_t tag, const pcireg_t *regs, + int reg, const char *name, + int sizebar, int onlyimpl) +{ + int width; + pcireg_t mask, rval; + pcireg_t mask64h, rval64h; + +#ifdef __GNUC__ /* XXX GCC -Wuninitialized inadequacies */ + mask64h = rval64h = 0; +#endif + + width = 4; + + /* + * Section 6.2.5.1, `Address Maps', tells us that: + * + * 1) The builtin software should have already mapped the + * device in a reasonable way. + * + * 2) A device which wants 2^n bytes of memory will hardwire + * the bottom n bits of the address to 0. As recommended, + * we write all 1s and see what we get back. + */ + rval = regs[o2i(reg)]; + /* XXX don't size unknown memory type? */ + if (rval != 0 && sizebar) { + uint32_t cmdreg; + + /* + * The following sequence seems to make some devices + * (e.g. host bus bridges, which don't normally + * have their space mapped) very unhappy, to + * the point of crashing the system. + * + * Therefore, if the mapping register is zero to + * start out with, don't bother trying. + */ + + cmdreg = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + cmdreg &= (PCI_COMMAND_MASK << PCI_COMMAND_SHIFT); /* keep status */ + pci_conf_write(tag, PCI_COMMAND_STATUS_REG, + cmdreg & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)); + + pci_conf_write(tag, reg, 0xffffffff); + mask = pci_conf_read(tag, reg); + pci_conf_write(tag, reg, rval); + if (PCI_MAPREG_TYPE(rval) == PCI_MAPREG_TYPE_MEM && + PCI_MAPREG_MEM_TYPE(rval) == PCI_MAPREG_MEM_TYPE_64BIT) { + rval64h = regs[o2i(reg + 4)]; + pci_conf_write(tag, reg + 4, 0xffffffff); + mask64h = pci_conf_read(tag, reg + 4); + pci_conf_write(tag, reg + 4, rval64h); + width = 8; + } + + pci_conf_write(tag, PCI_COMMAND_STATUS_REG, cmdreg); + } else + mask = 0; + + if (rval == 0 && onlyimpl) + return width; + + printf(" Base Address Register at 0x%02x", reg); + if (name) + printf(" (%s)", name); + printf("\n "); + if (rval == 0) { + printf("not implemented(?)\n"); + return width; + } + printf("type: "); + if (PCI_MAPREG_TYPE(rval) == PCI_MAPREG_TYPE_MEM) { + const char *type, *prefetch; + + switch (PCI_MAPREG_MEM_TYPE(rval)) { + case PCI_MAPREG_MEM_TYPE_32BIT: + type = "32-bit"; + break; + case PCI_MAPREG_MEM_TYPE_32BIT_1M: + type = "32-bit-1M"; + break; + case PCI_MAPREG_MEM_TYPE_64BIT: + type = "64-bit"; + break; + default: + type = "unknown (XXX)"; + break; + } + if (PCI_MAPREG_MEM_PREFETCHABLE(rval)) + prefetch = ""; + else + prefetch = "non"; + printf("%s %sprefetchable memory\n", type, prefetch); + switch (PCI_MAPREG_MEM_TYPE(rval)) { + case PCI_MAPREG_MEM_TYPE_64BIT: + printf(" base: 0x%016llx, ", + PCI_MAPREG_MEM64_ADDR( + ((((long long) rval64h) << 32) | rval))); + if (sizebar) + printf("size: 0x%016llx", + PCI_MAPREG_MEM64_SIZE( + ((((long long) mask64h) << 32) | mask))); + else + printf("not sized"); + printf("\n"); + break; + case PCI_MAPREG_MEM_TYPE_32BIT: + case PCI_MAPREG_MEM_TYPE_32BIT_1M: + default: + printf(" base: 0x%08x, ", PCI_MAPREG_MEM_ADDR(rval)); + if (sizebar) + printf("size: 0x%08x", PCI_MAPREG_MEM_SIZE(mask)); + else + printf("not sized"); + printf("\n"); + break; + } + } else { + if (sizebar) + printf("%d-bit ", mask & ~0x0000ffff ? 32 : 16); + printf("i/o\n"); + printf(" base: 0x%08x, ", PCI_MAPREG_IO_ADDR(rval)); + if (sizebar) + printf("size: 0x%08x", PCI_MAPREG_IO_SIZE(mask)); + else + printf("not sized"); + printf("\n"); + } + + return width; +} + + +/* Summary printing: Display device ID, status, memory map only. */ + +#define on(str, bit) \ + do { if (rval & (bit)) printf(" %s: on\n", (str)); } while (0) + +void +pci_conf_print(pcitag_t tag) +{ + pcireg_t regs[o2i(256)]; + int off, width; + pcireg_t rval; + uint32_t base, limit; + int sizebars; + + if (!pci_probe_tag(tag)) { + printf("no device\n"); + return; + } + + for (off = 0; off < 256; off += 4) + regs[o2i(off)] = pci_conf_read(tag, off); + + rval = regs[o2i(PCI_ID_REG)]; + pci_conf_print_ids(rval, " "); + + rval = regs[o2i(PCI_COMMAND_STATUS_REG)]; + + printf(" Command: 0x%04x\n", rval & 0xffff); + on("I/O space accesses", PCI_COMMAND_IO_ENABLE); + on("Memory space accesses", PCI_COMMAND_MEM_ENABLE); + on("Bus mastering", PCI_COMMAND_MASTER_ENABLE); + + printf(" Status: 0x%04x\n", PCI_STATUS(rval)); + on("Slave signaled Target Abort", PCI_STATUS_TARGET_TARGET_ABORT); + on("Master received Target Abort", PCI_STATUS_MASTER_TARGET_ABORT); + on("Master received Master Abort", PCI_STATUS_MASTER_ABORT); + on("Asserted System Error (SERR)", PCI_STATUS_SYSTEM_ERROR); + on("Parity error detected", PCI_STATUS_PARITY_DETECT); + + switch (PCI_HDRTYPE_TYPE(regs[o2i(PCI_BHLC_REG)])) { + case 0: + /* Standard device header */ + printf(" Type 0 (normal) header:\n"); + + /* sizing host BARs is often bad news */ + sizebars = 1; + if (PCI_CLASS(regs[o2i(PCI_CLASS_REG)]) == PCI_CLASS_BRIDGE && + PCI_SUBCLASS(regs[o2i(PCI_CLASS_REG)]) == PCI_SUBCLASS_BRIDGE_HOST) + sizebars = 0; + for (off = PCI_MAPREG_START; off < PCI_MAPREG_END; off += width) + width = pci_conf_print_bar(tag, regs, off, NULL, sizebars, 1); + + rval = regs[o2i(PCI_BPARAM_INTERRUPT_REG)]; + printf(" Interrupt Line: 0x%02x\n", PCI_INTERRUPT_LINE(rval)); + break; + + case 1: + /* PCI-PCI bridge header */ + printf(" Type 1 (PCI-PCI bridge) header:\n"); + + rval = regs[o2i(PPB_BUSINFO_REG)]; + printf(" Buses:\n"); + printf(" Primary: %d,", PPB_BUSINFO_PRIMARY(rval)); + printf(" Secondary: %d,", PPB_BUSINFO_SECONDARY(rval)); + printf(" Subordinate: %d\n", PPB_BUSINFO_SUBORD(rval)); + + rval = regs[o2i(PPB_IO_STATUS_REG)]; + printf(" Secondary Status: 0x%04x\n", PPB_SECSTATUS(rval)); + on(" Data parity error detected", PCI_STATUS_PARITY_ERROR); + on(" Signaled Target Abort", PCI_STATUS_TARGET_TARGET_ABORT); + on(" Received Target Abort", PCI_STATUS_MASTER_TARGET_ABORT); + on(" Received Master Abort", PCI_STATUS_MASTER_ABORT); + on(" System Error", PCI_STATUS_SYSTEM_ERROR); + on(" Parity Error", PCI_STATUS_PARITY_DETECT); + + rval = regs[o2i(PPB_IO_STATUS_REG)]; + base = PPB_IO_BASE(rval); + limit = PPB_IO_LIMIT(rval); + if (base != 0 || limit != 0) { + printf(" I/O Range:\n"); + + if ((base & 0xf) != 0 || (limit & 0xf) != 0) { + base = ((base & 0xf0) << 8) | 0x000; + limit = ((limit & 0xf0) << 8) | 0xfff; + rval = regs[o2i(PPB_IO_UPPER_REG)]; + base |= PPB_BASE(rval) << 16; + limit |= PPB_LIMIT(rval) << 16; + printf(" base: 0x%08x, limit: 0x%08x\n", base, limit); + } else { + base = (base << 8) | 0x000; + limit = (limit << 8) | 0xfff; + printf(" base: 0x%04x, limit: 0x%04x\n", base, limit); + } + } + + base = PPB_BASE(regs[o2i(PPB_MEM_REG)]) & 0xfff0; + limit = PPB_LIMIT(regs[o2i(PPB_MEM_REG)]) & 0xfff0; + printf(" Memory Range:\n"); + base = (base << 16) | 0x00000; + limit = (limit << 16) | 0xfffff; + printf(" base: 0x%08x, limit: 0x%08x\n", base, limit); + + base = PPB_BASE(regs[o2i(PPB_PREFMEM_REG)]) & 0xffff; + limit = PPB_LIMIT(regs[o2i(PPB_PREFMEM_REG)]) & 0xffff; + if (base != 0 || limit != 0 + || regs[o2i(PPB_PREFMEM_BASE_UPPER_REG)] != 0 + || regs[o2i(PPB_PREFMEM_LIMIT_UPPER_REG)] != 0) { + printf(" Prefetchable Memory Range:\n"); + if ((base & 0xf) != 0 || (limit & 0xf) != 0) { + base = ((base & 0xfff0) << 16) | 0x00000; + limit = ((limit & 0xfff0) << 16) | 0xfffff; + printf(" base: 0x%08x%08x, limit: 0x%08x%08x\n", + regs[o2i(PPB_PREFMEM_BASE_UPPER_REG)], base, + regs[o2i(PPB_PREFMEM_LIMIT_UPPER_REG)], limit); + } else { + base = (base << 16) | 0x00000; + limit = (limit << 16) | 0xfffff; + printf(" base: 0x%08x, limit: 0x%08x\n", base, limit); + } + } + + if (regs[o2i(PPB_MAPREG_ROM)] != 0) + printf(" Expansion ROM Base Address: 0x%08x\n", + regs[o2i(PPB_MAPREG_ROM)]); + break; + + default: + break; + } +} + diff --git a/cfe/cfe/pci/pciconf.c b/cfe/cfe/pci/pciconf.c new file mode 100644 index 0000000..9f23f7c --- /dev/null +++ b/cfe/cfe/pci/pciconf.c @@ -0,0 +1,1296 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PCI Configuration File: pciconf.c + * + ********************************************************************* + * + * Copyright 2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Based in part on the algor p5064 version of pciconf.c: + * generic PCI bus configuration + * Copyright (c) 1999 Algorithmics Ltd + * which in turn appears to be based on PMON code. + */ + +#include "cfe_pci.h" +#include "cfe_timer.h" +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_malloc.h" + +#include "pcivar.h" +#include "pcireg.h" +#include "pcidevs.h" +#include "ldtreg.h" + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#define PRINTF printf +#define VPRINTF vprintf + +extern void cfe_ledstr(const char *); +#define SBD_DISPLAY(msg) cfe_ledstr(msg) + +int _pciverbose; + +/* pci_devinfo uses sprintf(), and we don't necessarily want to drag + in all those tables for a minimal build, so set this function + pointer if it is required. */ +void (*_pci_devinfo_func) (pcireg_t, pcireg_t, int, char *); + +int _pci_nbus; /* start off with one bus */ +const int _pci_maxbus; /* maximum number of busses */ +int _pci_enumerated = 0; + +/* The "devices" here are actually PCI "functions" */ +#ifndef PCIMAX_DEV +#define PCIMAX_DEV 16 /* arbitrary */ +#endif +#ifndef PCIMAX_MEMWIN +#define PCIMAX_MEMWIN 3 /* arbitrary per device */ +#endif +#ifndef PCIMAX_IOWIN +#define PCIMAX_IOWIN 1 /* arbitrary per device */ +#endif + +struct pcidev { + struct pci_attach_args *pa; + int bus; + unsigned char min_gnt; + unsigned char max_lat; + short nmemwin; + short niowin; +}; + +struct pciwin { + struct pcidev *dev; + int reg; + size_t size; + pcireg_t address; +}; + +struct pcirange { + pcireg_t base; + pcireg_t next; + pcireg_t limit; +}; + +static struct pci_attach_args *pciarg; /* the array of devices (external) */ +static struct pcidev *pcidev; /* parallel attr array (internal) */ +static int pcindev; +static int pcimaxdev; + +static struct pciwin *pcimemwin; /* the array of memory windows */ +static int pcinmemwin; +static int pcimaxmemwin; +static struct pcirange pcimemaddr; + +static struct pciwin *pciiowin; /* the array of i/o windows */ +static int pciniowin; +static int pcimaxiowin; +static struct pcirange pciioaddr; + + +/* The pass 1 SB-1250 LDT host bridge (LHB) does not implement the base + and limit registers for its secondary bus correctly. To compensate, + the following code includes hardware-dependent extensions to: + - pad the assignment of addresses on the "first" bus behind that + bridge (its secondary) so that the 32 bytes starting at the base + address are unused. + - pad the assignment of addresses on the "first" bus not behind that + bridge (the successor to its subordinate bus) so that the 32 bytes + starting at the limit address + 1 are unused. + - derive values assigned to the mem and io limit registers from + the last allocated address + 1, not from the last allocated + address as specified for conforming PCI bridges. + For pass 1 parts, the revision of the LHB is 1. This problem is fixed + and the workaround is unnecessary for revision numbers greater than 1. +*/ + +static int lhb_secondary_bus; +static int lhb_subordinate_bus; + + +static void +print_bdf (int bus, int device, int function) +{ + PRINTF ("PCI"); + if (bus >= 0) + PRINTF (" bus %d", bus); + if (device >= 0) + PRINTF (" slot %d", device); + if (function >= 0) + PRINTF ("/%d", function); + PRINTF (": "); +} + +void +pci_bdfprintf (int bus, int device, int function, const char *fmt, ...) +{ + va_list arg; + + print_bdf (bus, device, function); +#ifdef __VARARGS_H + va_start(arg); +#else + va_start(arg, fmt); +#endif + VPRINTF (fmt, arg); + va_end(arg); +} + +void +pci_tagprintf (pcitag_t tag, const char *fmt, ...) +{ + va_list arg; + int bus, device, function; + + pci_break_tag (tag, &bus, &device, &function); + print_bdf (bus, device, function); + +#ifdef __VARARGS_H + va_start(arg); +#else + va_start(arg, fmt); +#endif + VPRINTF (fmt, arg); + va_end(arg); +} + + +/* Initialize the pci-pci bridges and bus hierarchy. */ + +/* let rec */ +static void pci_businit (int bus, pci_flags_t flags); + +static void +pci_businit_dev_func (pcitag_t tag, pci_flags_t flags) +{ + pcireg_t id, class, bhlc; + + class = pci_conf_read(tag, PCI_CLASS_REG); + id = pci_conf_read(tag, PCI_ID_REG); + bhlc = pci_conf_read(tag, PCI_BHLC_REG); + + pcindev++; + + if (PCI_CLASS(class) == PCI_CLASS_BRIDGE && PCI_HDRTYPE_TYPE(bhlc) == 1) { + enum {NONE, PCI, LDT} sec_type; + int offset; + int bus, device, function; + int bus2; + struct pci_bus *psec; + pcireg_t data; + + sec_type = NONE; + offset = 0; + switch (PCI_SUBCLASS(class)) { + case PCI_SUBCLASS_BRIDGE_PCI: + /* See if there is an LDT capability for the secondary. */ + offset = pci_find_ldt_cap(tag, LDT_SECONDARY); + sec_type = offset == 0 ? PCI : LDT; + break; + case PCI_SUBCLASS_BRIDGE_HOST: + case PCI_SUBCLASS_BRIDGE_MISC: + /* A Type 1 host bridge (e.g., SB-1250 LDT) or an + X-to-LDT bridge with unassigned subclass (LDT?). + Probe iff the secondary is LDT (best policy?) */ + offset = pci_find_ldt_cap(tag, LDT_SECONDARY); + if (offset != 0) sec_type = LDT; + break; + } + + if (sec_type == NONE || _pci_nbus == _pci_maxbus) + return; + + pci_break_tag(tag, &bus, &device, &function); + + if (sec_type == LDT && offset != 0) { + pcireg_t cr = pci_conf_read(tag, offset+LDT_COMMAND_CAP_OFF); + if ((cr & LDT_COMMAND_DOUBLE_ENDED) != 0) + return; + } + + bus2 = _pci_nbus; + psec = &_pci_bus[_pci_nbus]; + _pci_nbus++; + + psec->tag = tag; + psec->primary = bus; + + /* + * set primary to bus + * set secondary to _pci_nbus + * set subordinate to max possible bus number + */ + data = (PCI_BUSMAX << 16) | (bus2 << 8) | bus; + pci_conf_write(tag, PPB_BUSINFO_REG, data); + + /* + * set base interrupt mapping. + */ + if (bus == 0) { + /* We assume board-specific wiring for bus 0 devices. */ + psec->inta_shift = pci_int_shift_0(tag); + } else { + /* We assume expansion boards wired per PCI Bridge spec */ + psec->inta_shift = (_pci_bus[bus].inta_shift + device) % 4; + } + + /* if the new bus is LDT, do the fabric initialization */ + if (sec_type == LDT) + _pci_bus[bus2].no_probe = ldt_chain_init(tag, bus2, flags); + else + _pci_bus[bus2].no_probe = 0; + +#ifdef _CSWARM_ + /* We must avoid attempting to scan the secondary bus of the + diagnostic sturgeon on a cswarm (MasterAbortMode == 0 + appears not to suppress propagation of aborts). We know + its secondary bus number will be 2 on cswarm. */ + if (bus2 == 2) + _pci_bus[bus2].no_probe = 1; +#endif + + /* Scan the new bus for PCI-PCI bridges and initialize. To + avoid a chip erratum, we must skip this for double-hosted + chains with no secondary devices. The no_probe attribute + is a workaround (see ldt_chain_init above). */ + if (_pci_bus[bus2].no_probe) { + _pci_bus[bus2].min_io_addr = 0xffffffff; + _pci_bus[bus2].max_io_addr = 0; + _pci_bus[bus2].min_mem_addr = 0xffffffff; + _pci_bus[bus2].max_mem_addr = 0; + } else + pci_businit(bus2, flags); + + /* reset subordinate bus number */ + data = (data & 0xff00ffff) | ((_pci_nbus - 1) << 16); + pci_conf_write(tag, PPB_BUSINFO_REG, data); + + /* SB-1250 pass 1 work-around: remember the buses behind the + LDT host bridge. This is not the far end of a + double-hosted chain. */ + if (PCI_VENDOR(id) == PCI_VENDOR_SIBYTE && + PCI_PRODUCT(id) == PCI_PRODUCT_SIBYTE_SB1250_LDT && + PCI_REVISION(class) == 1) { + lhb_secondary_bus = bus2; + lhb_subordinate_bus = _pci_nbus - 1; + } + } +} + +static void +pci_businit_dev (int bus, int device, pci_flags_t flags) +{ + pcitag_t tag; + pcireg_t bhlc; + int function, maxfunc; + + tag = pci_make_tag(bus, device, 0); + if (!pci_canscan (tag)) + return; + + if (!pci_probe_tag(tag)) + return; + + bhlc = pci_conf_read(tag, PCI_BHLC_REG); + maxfunc = PCI_HDRTYPE_MULTIFN(bhlc) ? PCI_FUNCMAX : 0; + + for (function = 0; function <= maxfunc; function++) { + tag = pci_make_tag(bus, device, function); + if (pci_probe_tag(tag)) + pci_businit_dev_func(tag, flags); + } +} + + +static void +pci_businit (int bus, pci_flags_t flags) +{ + struct pci_bus *ppri; + int device; + + ppri = &_pci_bus[bus]; + ppri->min_io_addr = 0xffffffff; + ppri->max_io_addr = 0; + ppri->min_mem_addr = 0xffffffff; + ppri->max_mem_addr = 0; + + /* Pass 1 errata: we must number the buses in ascending order to + avoid problems with the LDT host bridge capturing all + configuration cycles. */ + + for (device = 0; device <= PCI_DEVMAX; device++) + pci_businit_dev (bus, device, flags); +} + + +/* Scan each PCI device on the system and record its configuration + requirements. */ + +static void +pci_query_dev_func (pcitag_t tag) +{ + pcireg_t id, class; + pcireg_t old, mask; + pcireg_t stat; + pcireg_t bparam; + pcireg_t icr; + pcireg_t bhlc; + pcireg_t t; /* used for pushing writes to cfg registers */ + unsigned int x; + int reg, mapreg_end, mapreg_rom; + struct pci_bus *pb; + struct pci_attach_args *pa; + struct pcidev *pd; + struct pciwin *pm, *pi; + int bus, device, function, incr; + uint16_t cmd; + uint8_t pin, pci_int; + + class = pci_conf_read(tag, PCI_CLASS_REG); + id = pci_conf_read(tag, PCI_ID_REG); + pci_break_tag(tag, &bus, &device, &function); + + if (_pciverbose && _pci_devinfo_func) { + char devinfo[256]; + (*_pci_devinfo_func)(id, class, 1, devinfo); + pci_tagprintf(tag, "%s\n", devinfo); + } + + if (pcindev >= pcimaxdev) { + panic ("pci: unexpected device number\n"); + return; + } + + pa = &pciarg[pcindev]; + pa->pa_tag = tag; + pa->pa_id = id; + pa->pa_class = class; + + pd = &pcidev[pcindev++]; + pd->pa = pa; + pd->bus = bus; + pd->nmemwin = 0; + pd->niowin = 0; + + pb = &_pci_bus[bus]; + pb->ndev++; + + stat = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + + /* do all devices support fast back-to-back */ + if ((stat & PCI_STATUS_BACKTOBACK_SUPPORT) == 0) + pb->fast_b2b = 0; /* no, sorry */ + + /* do all devices run at 66 MHz */ + if ((stat & PCI_STATUS_66MHZ_SUPPORT) == 0) + pb->freq66 = 0; /* no, sorry */ + + /* find slowest devsel */ + x = PCI_STATUS_DEVSEL(stat); + if (x > pb->devsel) + pb->devsel = x; + + bparam = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG); + + pd->min_gnt = PCI_BPARAM_GRANT (bparam); + pd->max_lat = PCI_BPARAM_LATENCY (bparam); + + if (pd->min_gnt != 0 || pd->max_lat != 0) { + /* find largest minimum grant time of all devices */ + if (pd->min_gnt != 0 && pd->min_gnt > pb->min_gnt) + pb->min_gnt = pd->min_gnt; + + /* find smallest maximum latency time of all devices */ + if (pd->max_lat != 0 && pd->max_lat < pb->max_lat) + pb->max_lat = pd->max_lat; + + if (pd->max_lat != 0) + /* subtract our minimum on-bus time per sec from bus bandwidth */ + pb->bandwidth -= pd->min_gnt * 4000000 / + (pd->min_gnt + pd->max_lat); + } + + /* Hook any special setup code and test for skipping resource + allocation, e.g., for our own host bridges. */ + if (pci_device_preset(tag) != 0) + return; + + /* Does the function need an interrupt mapping? */ + icr = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG); + pin = PCI_INTERRUPT_PIN(icr); + icr &=~ (PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); + if (pin == PCI_INTERRUPT_PIN_NONE) + pci_int = 0; + else if (bus == 0) + pci_int = pci_int_map_0(tag); + else + pci_int = (pb->inta_shift + device + (pin - 1)) % 4 + 1; + icr |= pci_int_line(pci_int) << PCI_INTERRUPT_LINE_SHIFT; + pci_conf_write(tag, PCI_BPARAM_INTERRUPT_REG, icr); + + /* Find and size the BARs */ + bhlc = pci_conf_read(tag, PCI_BHLC_REG); + switch (PCI_HDRTYPE_TYPE(bhlc)) { + case 0: /* Type 0 */ + mapreg_end = PCI_MAPREG_END; + mapreg_rom = PCI_MAPREG_ROM; + break; + case 1: /* Type 1 (bridge) */ + mapreg_end = PCI_MAPREG_PPB_END; + mapreg_rom = PCI_MAPREG_PPB_ROM; + break; + case 2: /* Type 2 (cardbus) */ + mapreg_end = PCI_MAPREG_PCB_END; + mapreg_rom = PCI_MAPREG_NONE; + break; + default: /* unknown */ + mapreg_end = PCI_MAPREG_START; /* assume none */ + mapreg_rom = PCI_MAPREG_NONE; + break; + } + + cmd = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + cmd &= (PCI_COMMAND_MASK << PCI_COMMAND_SHIFT); /* don't clear status */ + pci_conf_write(tag, PCI_COMMAND_STATUS_REG, + cmd & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)); + t = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); /* push the write */ + + for (reg = PCI_MAPREG_START; reg < mapreg_end; reg += incr) { + old = pci_conf_read(tag, reg); + pci_conf_write(tag, reg, 0xffffffff); + mask = pci_conf_read(tag, reg); + pci_conf_write(tag, reg, old); + + /* Assume 4 byte reg, unless we find out otherwise below. */ + incr = 4; + + /* 0 if not implemented, all-1s if (for some reason) 2nd half + of 64-bit BAR or if device broken and reg not implemented + (should return 0). */ + if (mask == 0 || mask == 0xffffffff) + continue; + + if (_pciverbose >= 3) + pci_tagprintf (tag, "reg 0x%x = 0x%x\n", reg, mask); + + if (PCI_MAPREG_TYPE(mask) == PCI_MAPREG_TYPE_IO) { + + mask |= 0xffff0000; /* must be ones */ + + if (pciniowin >= pcimaxiowin) { + PRINTF ("pci: too many i/o windows\n"); + continue; + } + pi = &pciiowin[pciniowin++]; + + pi->dev = pd; + pi->reg = reg; + pi->size = -(PCI_MAPREG_IO_ADDR(mask)); + pd->niowin++; + } else { + switch (PCI_MAPREG_MEM_TYPE(mask)) { + case PCI_MAPREG_MEM_TYPE_32BIT: + case PCI_MAPREG_MEM_TYPE_32BIT_1M: + break; + case PCI_MAPREG_MEM_TYPE_64BIT: + incr = 8; + { + pcireg_t oldhi, maskhi; + + if (reg + 4 >= PCI_MAPREG_END) { + pci_tagprintf (tag, + "misplaced 64-bit region ignored\n"); + continue; + } + + oldhi = pci_conf_read(tag, reg + 4); + pci_conf_write(tag, reg + 4, 0xffffffff); + maskhi = pci_conf_read(tag, reg + 4); + pci_conf_write(tag, reg + 4, oldhi); + + if (maskhi != 0xffffffff) { + pci_tagprintf (tag, + "true 64-bit region (%08x) ignored\n", + maskhi); + continue; + } + } + break; + default: + pci_tagprintf (tag, "reserved mapping type 0x%x\n", + PCI_MAPREG_MEM_TYPE(mask)); + continue; + } + + if (!PCI_MAPREG_MEM_PREFETCHABLE(mask)) + _pci_bus[bus].prefetch = 0; + + if (pcinmemwin >= pcimaxmemwin) { + PRINTF ("pci: too many memory windows\n"); + continue; + } + pm = &pcimemwin[pcinmemwin++]; + + pm->dev = pd; + pm->reg = reg; + pm->size = -(PCI_MAPREG_MEM_ADDR(mask)); + pd->nmemwin++; + } + } + + /* Finally check for Expansion ROM */ + if (mapreg_rom != PCI_MAPREG_NONE) { + reg = mapreg_rom; + old = pci_conf_read(tag, reg); + pci_conf_write(tag, reg, 0xfffffffe); + mask = pci_conf_read(tag, reg); + pci_conf_write(tag, reg, old); + + /* 0 if not implemented, 0xfffffffe or 0xffffffff if device + broken and/or register not implemented. */ + if (mask != 0 && mask != 0xfffffffe && mask != 0xffffffff) { + if (_pciverbose >= 3) + pci_tagprintf (tag, "reg 0x%x = 0x%x\n", reg, mask); + + if (pcinmemwin >= pcimaxmemwin) { + PRINTF ("pci: too many memory windows\n"); + goto done; + } + + pm = &pcimemwin[pcinmemwin++]; + pm->dev = pd; + pm->reg = reg; + pm->size = -(PCI_MAPREG_ROM_ADDR(mask)); + pd->nmemwin++; + } + } + +done: + cmd |= PCI_COMMAND_INVALIDATE_ENABLE; /* any reason not to? */ + pci_conf_write(tag, PCI_COMMAND_STATUS_REG, cmd); +} + +static void +pci_query_dev (int bus, int device) +{ + pcitag_t tag; + pcireg_t bhlc; + int probed, function, maxfunc; + + tag = pci_make_tag(bus, device, 0); + if (!pci_canscan (tag)) + return; + + if (_pciverbose >= 2) + pci_bdfprintf (bus, device, -1, "probe..."); + + probed = pci_probe_tag(tag); + + if (_pciverbose >= 2) + PRINTF ("completed\n"); + + if (!probed) + return; + + bhlc = pci_conf_read(tag, PCI_BHLC_REG); + maxfunc = PCI_HDRTYPE_MULTIFN(bhlc) ? PCI_FUNCMAX : 0; + + for (function = 0; function <= maxfunc; function++) { + tag = pci_make_tag(bus, device, function); + if (pci_probe_tag(tag)) + pci_query_dev_func(tag); + } + + if (_pciverbose >= 2) + pci_bdfprintf (bus, device, -1, "done\n"); +} + + +static void +pci_query (int bus) +{ + int device; + struct pci_bus *pb = &_pci_bus[bus]; + pcireg_t sec_status; + unsigned int def_ltim, max_ltim; + + if (bus != 0) { + sec_status = pci_conf_read(pb->tag, PPB_IO_STATUS_REG); + pb->fast_b2b = (sec_status & PCI_STATUS_BACKTOBACK_SUPPORT) ? 1 : 0; + pb->freq66 = (sec_status & PCI_STATUS_66MHZ_SUPPORT) ? 1 : 0; + } + + if (pb->no_probe) + pb->ndev = 0; + else { + for (device = 0; device <= PCI_DEVMAX; device++) + pci_query_dev (bus, device); + } + + if (pb->ndev != 0) { + /* convert largest minimum grant time to cycle count */ + max_ltim = pb->min_gnt * (pb->freq66 ? 66 : 33) / 4; + + /* now see how much bandwidth is left to distribute */ + if (pb->bandwidth <= 0) { + pci_bdfprintf (bus, -1, -1, "warning: total bandwidth exceeded\n"); + def_ltim = 1; + } else { + /* calculate a fair share for each device */ + def_ltim = pb->bandwidth / pb->ndev; + if (def_ltim > pb->max_lat) + /* that would exceed critical time for some device */ + def_ltim = pb->max_lat; + /* convert to cycle count */ + def_ltim = def_ltim * (pb->freq66 ? 66 : 33) / 4; + } + /* most devices don't implement bottom three bits, so round up */ + def_ltim = (def_ltim + 7) & ~7; + max_ltim = (max_ltim + 7) & ~7; + + pb->def_ltim = MIN (def_ltim, 255); + pb->max_ltim = MIN (MAX (max_ltim, def_ltim), 255); + } +} + + +static int +wincompare (const void *a, const void *b) +{ + const struct pciwin *wa = a, *wb = b; + if (wa->dev->bus != wb->dev->bus) + /* sort into ascending order of bus number */ + return (int)(wa->dev->bus - wb->dev->bus); + else + /* sort into descending order of size */ + return (int)(wb->size - wa->size); +} + + +static pcireg_t +pci_allocate_io(pcitag_t tag, size_t size) +{ + pcireg_t address; + + /* allocate upwards after rounding to size boundary */ + address = (pciioaddr.next + (size - 1)) & ~(size - 1); + if (address < pciioaddr.next || address + size > pciioaddr.limit) + return -1; + pciioaddr.next = address + size; + return address; +} + +static pcireg_t +pci_align_io_addr(pcireg_t addr) +{ + /* align to appropriate bridge boundaries (4K for Rev 1.1 Bridge Arch). + Over/underflow will show up in subsequent allocations. */ + return (addr + ((1 << 12)-1)) & ~((1 << 12)-1); +} + +static void +pci_assign_iowins(int bus, struct pciwin *pi_first, struct pciwin *pi_limit) +{ + struct pciwin *pi; + struct pci_bus *pb = &_pci_bus[bus]; + pcireg_t t; /* for pushing writes */ + + pciioaddr.next = pci_align_io_addr(pciioaddr.next); + + /* Pass 1 errata work around. Avoid assigning any real devices + at the base address of the LDT host bridge. */ + if (bus == lhb_secondary_bus) { + pb->min_io_addr = pciioaddr.next; + pciioaddr.next += (1 << 12); + pb->max_io_addr = pciioaddr.next - 1; + } + + for (pi = pi_first; pi < pi_limit; pi++) { + struct pcidev *pd = pi->dev; + pcitag_t tag = pd->pa->pa_tag; + pcireg_t base; + + if (pd->niowin < 0) + continue; + pi->address = pci_allocate_io (tag, pi->size); + if (pi->address == -1) { + pci_tagprintf (tag, + "not enough PCI i/o space (%ld requested)\n", + (long)pi->size); + pd->nmemwin = pd->niowin = -1; + continue; + } + + if (pi->address < pb->min_io_addr) + pb->min_io_addr = pi->address; + if (pi->address + pi->size - 1 > pb->max_io_addr) + pb->max_io_addr = pi->address + pi->size - 1; + + if (_pciverbose >= 2) + pci_tagprintf (tag, + "I/O BAR at 0x%x gets %ld bytes @ 0x%x\n", + pi->reg, (long)pi->size, pi->address); + base = pci_conf_read(tag, pi->reg); + base = (base & ~PCI_MAPREG_IO_ADDR_MASK) | pi->address; + pci_conf_write(tag, pi->reg, base); + t = pci_conf_read(tag, pi->reg); + } + + if (pb->min_io_addr < pb->max_io_addr) { + /* if any io on bus, expand to valid bridge limit */ + pb->max_io_addr |= ((1 << 12)-1); + pciioaddr.next = pb->max_io_addr + 1; + } + + /* More Pass 1 errata work around. Make sure the 32 bytes beyond + the LDT window are not allocated by reserving an entire quantum + of io space. */ + if (bus == lhb_subordinate_bus) { + pciioaddr.next = pci_align_io_addr(pciioaddr.next) + (1 << 12); + } +} + +static void +pci_setup_iowins (void) +{ + struct pciwin *pi, *pi_first, *pi_limit; + int bus; + + qsort(pciiowin, pciniowin, sizeof(struct pciwin), wincompare); + pi_first = pciiowin; + pi_limit = &pciiowin[pciniowin]; + + for (bus = 0; bus < _pci_nbus; bus++) { + pi = pi_first; + while (pi != pi_limit && pi->dev->bus == bus) + pi++; + pci_assign_iowins(bus, pi_first, pi); + pi_first = pi; + } +} + + +static pcireg_t +pci_allocate_mem(pcitag_t tag, size_t size) +{ + pcireg_t address; + + /* allocate upwards after rounding to size boundary */ + address = (pcimemaddr.next + (size - 1)) & ~(size - 1); + if (address < pcimemaddr.next || address + size > pcimemaddr.limit) + return -1; + pcimemaddr.next = address + size; + return address; +} + +static pcireg_t +pci_align_mem_addr(pcireg_t addr) +{ + /* align to appropriate bridge boundaries (1M for Rev 1.1 Bridge Arch). + Over/underflow will show up in subsequent allocations. */ + return (addr + ((1 << 20)-1)) & ~((1 << 20)-1); +} + +static void +pci_assign_memwins(int bus, struct pciwin *pm_first, struct pciwin *pm_limit) +{ + struct pciwin *pm; + struct pci_bus *pb = &_pci_bus[bus]; + pcireg_t t; /* for pushing writes */ + + pcimemaddr.next = pci_align_mem_addr(pcimemaddr.next); + + /* Pass 1 errata work around. Avoid assigning any real devices + at the base address of the LDT host bridge. */ + if (bus == lhb_secondary_bus) { + pb->min_mem_addr = pcimemaddr.next; + pcimemaddr.next += (1 << 20); + pb->max_mem_addr = pcimemaddr.next - 1; + } + + for (pm = pm_first; pm < pm_limit; ++pm) { + struct pcidev *pd = pm->dev; + pcitag_t tag = pd->pa->pa_tag; + + if (pd->nmemwin < 0) + continue; + pm->address = pci_allocate_mem (tag, pm->size); + if (pm->address == -1) { + pci_tagprintf (tag, + "not enough PCI mem space (%ld requested)\n", + (long)pm->size); + pd->nmemwin = pd->niowin = -1; + continue; + } + if (_pciverbose >= 2) + pci_tagprintf (tag, + "%s BAR at 0x%x gets %ld bytes @ 0x%x\n", + pm->reg != PCI_MAPREG_ROM ? "MEM" : "ROM", + pm->reg, (long)pm->size, pm->address); + + if (pm->address < pb->min_mem_addr) + pb->min_mem_addr = pm->address; + if (pm->address + pm->size - 1 > pb->max_mem_addr) + pb->max_mem_addr = pm->address + pm->size - 1; + + if (pm->reg != PCI_MAPREG_ROM) { + /* normal memory - expansion rom done below */ + pcireg_t base = pci_conf_read(tag, pm->reg); + base = pm->address | (base & ~PCI_MAPREG_MEM_ADDR_MASK); + pci_conf_write(tag, pm->reg, base); + t = pci_conf_read(tag, pm->reg); + if (PCI_MAPREG_MEM_TYPE(t) == PCI_MAPREG_MEM_TYPE_64BIT) { + pci_conf_write(tag, pm->reg + 4, 0); + t = pci_conf_read(tag, pm->reg + 4); + } + } + } + + /* align final bus window */ + if (pb->min_mem_addr < pb->max_mem_addr) { + pb->max_mem_addr |= ((1 << 20) - 1); + pcimemaddr.next = pb->max_mem_addr + 1; + } + + /* More pass 1 errata work around. Make sure the next 32 bytes + beyond the LDT window are not used by reserving an entire + quantum of PCI memory space. */ + if (bus == lhb_subordinate_bus) { + pcimemaddr.next = pci_align_mem_addr(pcimemaddr.next) + (1 << 20); + } +} + +static void +pci_setup_memwins (void) +{ + struct pciwin *pm, *pm_first, *pm_limit; + int bus; + + qsort(pcimemwin, pcinmemwin, sizeof(struct pciwin), wincompare); + pm_first = pcimemwin; + pm_limit = &pcimemwin[pcinmemwin]; + + for (bus = 0; bus < _pci_nbus; bus++) { + pm = pm_first; + while (pm != pm_limit && pm->dev->bus == bus) + pm++; + pci_assign_memwins(bus, pm_first, pm); + pm_first = pm; + } + + /* Program expansion rom address base after normal memory base, + to keep DEC ethernet chip happy */ + for (pm = pcimemwin; pm < pm_limit; pm++) { + if (pm->reg == PCI_MAPREG_ROM && pm->address != -1) { + struct pcidev *pd = pm->dev; /* expansion rom */ + pcitag_t tag = pd->pa->pa_tag; + pcireg_t base; + pcireg_t t; /* for pushing writes */ + + /* Do not enable ROM at this time -- PCI spec 2.2 s6.2.5.2 last + paragraph, says that if the expansion ROM is enabled, accesses + to other registers via the BARs may not be done by portable + software!!! */ + base = pci_conf_read(tag, pm->reg); + base = pm->address | (base & ~PCI_MAPREG_ROM_ADDR_MASK); + base &= ~PCI_MAPREG_ROM_ENABLE; + pci_conf_write(tag, pm->reg, base); + t = pci_conf_read(tag, pm->reg); + } + } +} + + +static void +pci_setup_ppb(pci_flags_t flags) +{ + int i; + + for (i = _pci_nbus - 1; i > 0; i--) { + struct pci_bus *psec = &_pci_bus[i]; + struct pci_bus *ppri = &_pci_bus[psec->primary]; + if (ppri->min_io_addr > psec->min_io_addr) + ppri->min_io_addr = psec->min_io_addr; + if (ppri->max_io_addr < psec->max_io_addr) + ppri->max_io_addr = psec->max_io_addr; + if (ppri->min_mem_addr > psec->min_mem_addr) + ppri->min_mem_addr = psec->min_mem_addr; + if (ppri->max_mem_addr < psec->max_mem_addr) + ppri->max_mem_addr = psec->max_mem_addr; + } + + if (_pciverbose >= 2) { + struct pci_bus *pb = &_pci_bus[0]; + if (pb->min_io_addr < pb->max_io_addr) + pci_bdfprintf (0, -1, -1, "io 0x%08x-0x%08x\n", + pb->min_io_addr, pb->max_io_addr); + if (pb->min_mem_addr < pb->max_mem_addr) + pci_bdfprintf (0, -1, -1, "mem 0x%08x-0x%08x\n", + pb->min_mem_addr, pb->max_mem_addr); + } + + for (i = 1; i < _pci_nbus; i++) { + struct pci_bus *pb = &_pci_bus[i]; + pcireg_t cmd; + pcireg_t iodata, memdata; + pcireg_t brctl; + pcireg_t t; /* for pushing writes */ + + cmd = pci_conf_read(pb->tag, PCI_COMMAND_STATUS_REG); + if (_pciverbose >= 2) + pci_bdfprintf (i, -1, -1, "subordinate to bus %d\n", pb->primary); + + cmd |= PCI_COMMAND_MASTER_ENABLE; + if (pb->min_io_addr < pb->max_io_addr) { + uint32_t io_limit; + + /* Pass 1 work-round: limits are next free, not last used. */ + io_limit = pb->max_io_addr; + if (i == lhb_secondary_bus) + io_limit++; + + cmd |= PCI_COMMAND_IO_ENABLE; + if (_pciverbose >= 2) + pci_bdfprintf (i, -1, -1, "io 0x%08x-0x%08x\n", + pb->min_io_addr, io_limit); + iodata = pci_conf_read(pb->tag, PPB_IO_STATUS_REG); + if ((iodata & PPB_IO_ADDR_CAP_MASK) == PPB_IO_ADDR_CAP_32) { + pcireg_t upperdata; + + upperdata = ((pb->min_io_addr) >> 16) & PPB_IO_UPPER_BASE_MASK; + upperdata |= (io_limit & PPB_IO_UPPER_LIMIT_MASK); + pci_conf_write(pb->tag, PPB_IO_UPPER_REG, upperdata); + } + iodata = (iodata & ~PPB_IO_BASE_MASK) + | ((pb->min_io_addr >> 8) & 0xf0); + iodata = (iodata & ~PPB_IO_LIMIT_MASK) + | ((io_limit & PPB_IO_LIMIT_MASK) & 0xf000); + } else { + /* Force an empty window */ + iodata = pci_conf_read(pb->tag, PPB_IO_STATUS_REG); + iodata &=~ (PPB_IO_BASE_MASK | PPB_IO_LIMIT_MASK); + iodata |= (1 << 4) | (0 << (8+4)); + } + pci_conf_write(pb->tag, PPB_IO_STATUS_REG, iodata); + /* Push the write (see SB-1250 Errata, Section 8.10) */ + t = pci_conf_read(pb->tag, PPB_IO_STATUS_REG); + + if (pb->min_mem_addr < pb->max_mem_addr) { + uint32_t mem_limit; + + /* SB-1250 pass 1 workaround: limit is next free, not last used */ + mem_limit = pb->max_mem_addr; + if (i == lhb_secondary_bus) + mem_limit++; + + cmd |= PCI_COMMAND_MEM_ENABLE; + if (_pciverbose >= 2) + pci_bdfprintf (i, -1, -1, "mem 0x%08x-0x%08x\n", + pb->min_mem_addr, mem_limit); + memdata = pci_conf_read(pb->tag, PPB_MEM_REG); + memdata = (memdata & ~PPB_MEM_BASE_MASK) + | ((pb->min_mem_addr >> 16) & 0xfff0); + memdata = (memdata & ~PPB_MEM_LIMIT_MASK) + | ((mem_limit & PPB_MEM_LIMIT_MASK) & 0xfff00000); + } else { + /* Force an empty window */ + memdata = pci_conf_read(pb->tag, PPB_MEM_REG); + memdata &=~ (PPB_MEM_BASE_MASK | PPB_MEM_LIMIT_MASK); + memdata |= (1 << 4) | (0 << (16+4)); + } + pci_conf_write(pb->tag, PPB_MEM_REG, memdata); + /* Push the write (see SB-1250 Errata, Section 8.10) */ + t = pci_conf_read(pb->tag, PPB_MEM_REG); + + /* Force an empty prefetchable memory window */ + memdata = pci_conf_read(pb->tag, PPB_PREFMEM_REG); + memdata &=~ (PPB_MEM_BASE_MASK | PPB_MEM_LIMIT_MASK); + memdata |= (1 << 4) | (0 << (16+4)); + pci_conf_write(pb->tag, PPB_PREFMEM_REG, memdata); + /* Push the write (see SB-1250 Errata, Section 8.10) */ + t = pci_conf_read(pb->tag, PPB_PREFMEM_REG); + + /* Do any final bridge dependent initialization */ + pci_bridge_setup(pb->tag, flags); + + brctl = pci_conf_read(pb->tag, PPB_BRCTL_INTERRUPT_REG); +#ifdef _SB1250_PASS2_ + /* LDT MasterAborts _will_ cause bus errors in pass 2 when + enabled. Pending negotiations with clients, leave + MasterAbortMode off to disable their propagation. */ +#else + brctl |= (PPB_BRCTL_SERR_ENABLE | PPB_BRCTL_MASTER_ABORT_MODE); +#endif + if (pb->fast_b2b) + brctl |= PPB_BRCTL_BACKTOBACK_ENABLE; + pci_conf_write(pb->tag, PPB_BRCTL_INTERRUPT_REG, brctl); + t = pci_conf_read(pb->tag, PPB_BRCTL_INTERRUPT_REG); /* push */ + + pci_conf_write(pb->tag, PCI_COMMAND_STATUS_REG, cmd); + } +} + + +int +pci_cacheline_log2 (void) +{ + /* default to 8 words == 2^3 */ + return 3; +} + + +int +pci_maxburst_log2 (void) +{ + return 32; /* no limit */ +} + +static void +pci_setup_devices (pci_flags_t flags) +{ + struct pcidev *pd; + + /* Enable each PCI interface */ + for (pd = pcidev; pd < &pcidev[pcindev]; pd++) { + struct pci_bus *pb = &_pci_bus[pd->bus]; + pcitag_t tag = pd->pa->pa_tag; + pcireg_t cmd, misc; + unsigned int ltim; + + /* Consider setting interrupt line here */ + + cmd = pci_conf_read(tag, PCI_COMMAND_STATUS_REG); + cmd |= PCI_COMMAND_MASTER_ENABLE + | PCI_COMMAND_SERR_ENABLE + | PCI_COMMAND_PARITY_ENABLE; + /* Always enable i/o & memory space, in case this card is + just snarfing space from the fixed ISA block and doesn't + declare separate PCI space. */ + cmd |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE; + if (pb->fast_b2b) + cmd |= PCI_COMMAND_BACKTOBACK_ENABLE; + + /* Write status too, to clear any pending error bits. */ + pci_conf_write(tag, PCI_COMMAND_STATUS_REG, cmd); + + ltim = pd->min_gnt * (pb->freq66 ? 66 : 33) / 4; + ltim = MIN (MAX (pb->def_ltim, ltim), pb->max_ltim); + + misc = pci_conf_read (tag, PCI_BHLC_REG); + PCI_LATTIMER_SET (misc, ltim); + PCI_CACHELINE_SET (misc, 1 << pci_cacheline_log2()); + pci_conf_write (tag, PCI_BHLC_REG, misc); + + pci_device_setup (tag); /* hook for post setup */ + } +} + + +void +pci_configure (pci_flags_t flags) +{ + int bus; + +#if (PCI_DEBUG > 1) + _pciverbose = 3; +#else + _pciverbose = (flags & PCI_FLG_VERBOSE); +#endif + _pci_devinfo_func = (_pciverbose != 0) ? pci_devinfo : NULL; + pciarg = NULL; + + /* SB-1250 pass 1 workaround: discover LHB buses during traversal. */ + lhb_secondary_bus = lhb_subordinate_bus = -1; + + /* initialise the host bridge(s) */ + SBD_DISPLAY ("PCIH"); + if (pci_hwinit(flags) < 0) + return; + + /* initialise any PCI-PCI bridges, discover and number buses */ + SBD_DISPLAY ("PCIB"); + pcindev = 0; + pci_businit(0, flags); + + /* scan configuration space of all devices to collect attributes */ + SBD_DISPLAY ("PCIS"); + pcimaxdev = pcindev; + pciarg = (struct pci_attach_args *) KMALLOC (pcimaxdev * sizeof(struct pci_attach_args), 0); + if (pciarg == NULL) { + PRINTF ("pci: no memory for device table\n"); + pcimaxdev = 0; + } else { + pcidev = (struct pcidev *) KMALLOC (pcimaxdev * sizeof(struct pcidev), 0); + if (pcidev == NULL) { + KFREE (pciarg); pciarg = NULL; + PRINTF ("pci: no memory for device attribute table\n"); + pcimaxdev = 0; + } + } + pcindev = 0; + + pcimaxmemwin = PCIMAX_DEV * PCIMAX_MEMWIN; + pcimemwin = (struct pciwin *) KMALLOC (pcimaxmemwin * sizeof(struct pciwin), 0); + if (pcimemwin == NULL) { + PRINTF ("pci: no memory for window table\n"); + pcimaxmemwin = 0; + } + pcimaxiowin = PCIMAX_DEV * PCIMAX_IOWIN; + pciiowin = (struct pciwin *) KMALLOC (pcimaxiowin * sizeof(struct pciwin), 0); + if (pciiowin == NULL) { + PRINTF ("pci: no memory for window table\n"); + pcimaxiowin = 0; + } + + pcinmemwin = pciniowin = 0; + for (bus = 0; bus < _pci_nbus; bus++) { + pci_query (bus); + } + + if (pcindev != pcimaxdev) { + panic ("Inconsistent device count\n"); + return; + } + + /* alter PCI bridge parameters based on query data */ + pci_hwreinit (flags); + + /* setup the individual device windows */ + pcimemaddr.base = minpcimemaddr; + pcimemaddr.limit = maxpcimemaddr; + pciioaddr.base = minpciioaddr; + pciioaddr.limit = maxpciioaddr; + + pcimemaddr.next = pcimemaddr.base; + pciioaddr.next = pciioaddr.base; + pci_setup_iowins (); + pci_setup_memwins (); + + /* set up and enable each device */ + if (_pci_nbus > 1) + pci_setup_ppb (flags); + pci_setup_devices (flags); + + KFREE (pciiowin); pciiowin = NULL; + KFREE (pcimemwin); pcimemwin = NULL; + KFREE (pcidev); pcidev = NULL; + + _pci_enumerated = 1; +} + + +int +pci_foreachdev(int (*fn)(pcitag_t tag)) +{ + int i, rv; + + for (i = 0, rv = 0; i < pcindev && rv == 0; i++) + rv = (*fn)(pciarg[i].pa_tag); + + return rv; +} + + +static int +dump_configuration(pcitag_t tag) +{ + pci_tagprintf(tag, "dump of "); + pci_conf_print(tag); + return 0; +} + +void +pci_show_configuration(void) +{ + pci_foreachdev(dump_configuration); +} + +int +pci_find_class(uint32_t class, int enumidx, pcitag_t *tag) +{ + int i; + struct pci_attach_args *thisdev; + + thisdev = pciarg; + for (i = 0; i < pcindev && enumidx >= 0; i++) { + if (PCI_CLASS(thisdev->pa_class) == class) { + if (enumidx == 0) { + *tag = thisdev->pa_tag; + return 0; + } else { + enumidx--; + } + } + thisdev++; + } + + return -1; +} + +int +pci_find_device(uint32_t vid, uint32_t did, int enumidx, pcitag_t *tag) +{ + int i; + struct pci_attach_args *thisdev; + + thisdev = pciarg; + for (i = 0; i < pcindev && enumidx >= 0; i++) { + if ((PCI_VENDOR(thisdev->pa_id) == vid) && + (PCI_PRODUCT(thisdev->pa_id) == did)) { + if (enumidx == 0) { + *tag = thisdev->pa_tag; + return 0; + } else { + enumidx--; + } + } + thisdev++; + } + + return -1; +} diff --git a/cfe/cfe/pci/pcidevs b/cfe/cfe/pci/pcidevs new file mode 100644 index 0000000..65b03ab --- /dev/null +++ b/cfe/cfe/pci/pcidevs @@ -0,0 +1,1355 @@ +$pcidevs 2002/09/03 broadcom $ + +/* + * Copyright (c) 1995, 1996 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * NOTE: a fairly complete list of PCI codes can be found at: + * + * http://members.hyperlink.net.au/~chart/pci.htm + * + * which replaces the database found at + * + * http://www.yourvote.com/pci/ + * + * (but it doesn't always seem to match vendor documentation) + */ + +/* + * List of known PCI vendors. This list has been trimmed to include + * only vendors with products appearing in the lists below. + */ + +vendor COMPAQ 0x0e11 Compaq +vendor SYMBIOS 0x1000 Symbios Logic +vendor ATI 0x1002 ATI Technologies +vendor ULSI 0x1003 ULSI Systems +vendor VLSI 0x1004 VLSI Technology +vendor AVANCE 0x1005 Avance Logic +vendor NS 0x100b National Semiconductor +vendor TSENG 0x100c Tseng Labs +vendor WEITEK 0x100e Weitek +vendor DEC 0x1011 Digital Equipment +vendor CIRRUS 0x1013 Cirrus Logic +vendor IBM 0x1014 IBM +vendor WD 0x101c Western Digital +vendor AMD 0x1022 Advanced Micro Devices +vendor TRIDENT 0x1023 Trident Microsystems +vendor ACER 0x1025 Acer +vendor MATROX 0x102b Matrox +vendor CHIPS 0x102c Chips and Technologies +vendor TOSHIBA 0x102f Toshiba America +vendor NEC 0x1033 NEC +vendor FUTUREDOMAIN 0x1036 Future Domain +vendor SIS 0x1039 Silicon Integrated System +vendor HP 0x103c Hewlett-Packard +vendor PCTECH 0x1042 PC Technology +vendor DPT 0x1044 Distributed Processing Technology +vendor OPTI 0x1045 Opti +vendor ELSA 0x1048 Elsa +vendor SGSTHOMSON 0x104a SGS Thomson Microelectric +vendor BUSLOGIC 0x104b BusLogic +vendor TI 0x104c Texas Instruments +vendor SONY 0x104d Sony +vendor OAKTECH 0x104e Oak Technology +vendor WINBOND 0x1050 Winbond Electronics +vendor MOT 0x1057 Motorola +vendor PROMISE 0x105a Promise Technology +vendor NUMBER9 0x105d Number 9 Computer Company +vendor UMC 0x1060 United Microelectronics +vendor ITT 0x1061 I. T. T. +vendor MYLEX 0x1069 Mylex +vendor APPLE 0x106b Apple Computer +vendor YAMAHA 0x1073 Yamaha +vendor NEXGEN 0x1074 NexGen Microsystems +vendor QLOGIC 0x1077 Q Logic +vendor LEADTEK 0x107d LeadTek Research +vendor CONTAQ 0x1080 Contaq Microsystems +vendor BIT3 0x108a Bit3 Computer Corp. +vendor OLICOM 0x108d Olicom +vendor SUN 0x108e Sun Microsystems +vendor INTERGRAPH 0x1091 Intergraph +vendor DIAMOND 0x1092 Diamond Computer Systems +vendor CMDTECH 0x1095 CMD Technology +vendor QUANTUMDESIGNS 0x1098 Quantum Designs +vendor BROOKTREE 0x109e Brooktree +vendor SGI 0x10a9 Silicon Graphics +vendor ACC 0x10aa ACC Microelectronics +vendor SYMPHONY 0x10ad Symphony Labs +vendor PLX 0x10b5 PLX Technology +vendor MADGE 0x10b6 Madge Networks +vendor 3COM 0x10B7 3Com +vendor SMC 0x10b8 Standard Microsystems +vendor ALI 0x10b9 Acer Labs +vendor SURECOM 0x10bd Surecom Technology +vendor SAMSUNGSEMI 0x10c3 Samsung Semiconductors +vendor NEOMAGIC 0x10c8 Neomagic +vendor ADVSYS 0x10cd Advanced System Products +vendor MACRONIX 0x10d9 Macronix +vendor ES 0x10dd Evans & Sutherland +vendor NVIDIA 0x10de Nvidia Corporation +vendor EMULEX 0x10df Emulex +vendor IMS 0x10e0 Integrated Micro Solutions +vendor TEKRAM 0x10e1 Tekram Technology (1st PCI Vendor ID) +vendor NEWBRIDGE 0x10e3 Newbridge Microsystems / Tundra Semiconductor +vendor AMCIRCUITS 0x10e8 Applied Micro Circuits +vendor REALTEK 0x10ec Realtek Semiconductor +vendor NKK 0x10f5 NKK Corporation +vendor INITIO 0x1101 Initio +vendor CREATIVELABS 0x1102 Creative Labs +vendor TRIONES 0x1103 Triones Technologies +vendor SIGMA 0x1105 Sigma Designs +vendor VIATECH 0x1106 VIA Technologies +vendor COGENT 0x1109 Cogent Data Technologies +vendor RNS 0x1112 RNS +vendor ACCTON 0x1113 Accton Technology +vendor VORTEX 0x1119 Vortex Computer Systems +vendor EFFICIENTNETS 0x111a Efficent Networks +vendor IDT 0x111d IDT +vendor FORE 0x1127 FORE Systems +vendor ZIATECH 0x1138 Ziatech +vendor ALLIANCE 0x1142 Alliance Semiconductor +vendor SCHNEIDERKOCH 0x1148 Schneider & Koch +vendor MUTECH 0x1159 Mutech +vendor XIRCOM 0x115d Xircom +vendor ALTERA 0x1172 Altera Corporation +vendor TOSHIBA2 0x1179 Toshiba America Info Systems +vendor RICOH 0x1180 Ricoh +vendor DLINK 0x1186 D-Link Systems +vendor COROLLARY 0x118c Corrollary +vendor ACARD 0x1191 Acard +vendor ZEINET 0x1193 Zeinet +vendor GALILEO 0x11ab Galileo Technology +vendor LITEON 0x11ad Lite-On Communications +vendor V3 0x11b0 V3 Semiconductor +vendor LUCENT 0x11c1 AT&T Microelectronics +vendor DOLPHIN 0x11c8 Dolphin Interconnect Solutions +vendor AURAVISION 0x11d1 Auravision +vendor ZORAN 0x11de Zoran Corporation +vendor COMPEX 0x11f6 Compex +vendor PMCSIERRA 0x11f8 PMC-Sierra +vendor CYCLADES 0x120e Cyclades +vendor ESSENTIAL 0x120f Essential Communications +vendor O2MICRO 0x1217 O2 Micro Inc +vendor 3DFX 0x121a 3Dfx Interactive +vendor CCUBE 0x123f C-Cube Microsystems +vendor AVM 0x1244 AVM +vendor LINEARSYS 0x1254 Linear Systems +vendor ASIX 0x125b ASIX Electronics +vendor ESSTECH 0x125d ESS Technology Inc +vendor SILMOTION 0x126f Silicon Motion +vendor ENSONIQ 0x1274 Ensoniq +vendor DAVICOM 0x1282 Davicom Semiconductor +vendor ESSTECH2 0x1285 ESS Technology Inc +vendor TRITECH 0x1292 TriTech Microelectronics +vendor ALTEON 0x12ae Alteon +vendor RISCOM 0x12aa RISCom +vendor USR 0x12b9 US Robotics (3Com) +vendor NVIDIA_SGS 0x12d2 Nvidia Corporation & SGS Thomson Microelectric +vendor AUREAL 0x12eb Aureal Semiconductor +vendor ADMTEK 0x1317 ADMtek +vendor FORTEMEDIA 0x1319 Forte Media +vendor DOMEX 0x134a Domex +vendor LMC 0x1376 LAN Media Corporation +vendor API 0x14d9 API Networks +vendor CONEXANT 0x14f1 Conexant Systems +vendor NETGEAR 0x1385 Netgear +vendor 3WARE 0x13c1 3ware +vendor SUNDANCETI 0x13f0 Sundance Technology +vendor CMEDIA 0x13f6 C-Media Electronics Inc +vendor DELTA 0x1500 Delta Electronics +vendor SOLIDUM 0x1588 Solidum Systems Corp. +vendor SIBYTE 0x166d SiByte, Inc. +vendor SYMPHONY2 0x1c1c Symphony Labs (2nd PCI Vendor ID) +vendor TEKRAM2 0x1de1 Tekram Technology (2nd PCI Vendor ID) +vendor BROADCOM 0x14e4 Broadcom +vendor 3DLABS 0x3d3d 3D Labs +vendor AVANCE2 0x4005 Avance Logic (2nd PCI Vendor ID) +vendor ADDTRON 0x4033 Addtron Technology +vendor NETVIN 0x4a14 NetVin +vendor S3 0x5333 S3 +vendor C4T 0x6374 c't Magazin +vendor INTEL 0x8086 Intel +vendor PROLAN 0x8c4a ProLAN +vendor KTI 0x8e2e KTI +vendor ADP 0x9004 Adaptec +vendor ADP2 0x9005 Adaptec (2nd PCI Vendor ID) +vendor ATRONICS 0x907f Atronics +vendor ARC 0xedd8 ARC Logic +vendor EPIGRAM 0xfeda Epigram +vendor INVALID 0xffff INVALID VENDOR ID + +/* + * List of known products. Grouped by vendor. + */ + +/* 3COM Products */ +product 3COM 3C985 0x0001 3c985 Gigabit Ethernet +product 3COM 3C590 0x5900 3c590 Ethernet +product 3COM 3C595TX 0x5950 3c595-TX 10/100 Ethernet +product 3COM 3C595T4 0x5951 3c595-T4 10/100 Ethernet +product 3COM 3C595MII 0x5952 3c595-MII 10/100 Ethernet +product 3COM 3C900TPO 0x9000 3c900-TPO Ethernet +product 3COM 3C900COMBO 0x9001 3c900-COMBO Ethernet +product 3COM 3C905TX 0x9050 3c905-TX 10/100 Ethernet +product 3COM 3C905T4 0x9051 3c905-T4 10/100 Ethernet +product 3COM 3C900BTPO 0x9004 3c900B-TPO Ethernet +product 3COM 3C900BCOMBO 0x9005 3c900B-COMBO Ethernet +product 3COM 3C900BTPC 0x9006 3c900B-TPC Ethernet +product 3COM 3C905BTX 0x9055 3c905B-TX 10/100 Ethernet +product 3COM 3C905BT4 0x9056 3c905B-T4 10/100 Ethernet +product 3COM 3C905BCOMBO 0x9058 3c905B-COMBO 10/100 Ethernet +product 3COM 3C905BFX 0x905a 3c905B-FX 100 Ethernet +product 3COM 3C905CTX 0x9200 3c905C-TX 10/100 Ethernet with mngmt +product 3COM 3C980SRV 0x9800 3c980 Server Adapter 10/100 Ethernet +product 3COM 3C980CTXM 0x9805 3c980C-TXM 10/100 Ethernet +product 3COM 3CR990TX97 0x9903 3CR990-TX-97 10/100 Ethernet + +/* 3Dfx Interactive producs */ +product 3DFX VOODOO 0x0001 Voodoo +product 3DFX VOODOO2 0x0002 Voodoo2 +product 3DFX BANSHEE 0x0003 Banshee +product 3DFX VOODOO3 0x0005 Voodoo3 + +/* 3D Labs products */ +product 3DLABS 300SX 0x0001 GLINT 300SX +product 3DLABS 500TX 0x0002 GLINT 500TX +product 3DLABS DELTA 0x0003 GLINT DELTA +product 3DLABS PERMEDIA 0x0004 GLINT Permedia +product 3DLABS 500MX 0x0006 GLINT 500MX +product 3DLABS PERMEDI2 0x0007 GLINT Permedia 2 + +/* 3ware products */ +product 3WARE ESCALADE 0x1000 Escalade IDE RAID + +/* ACC Products */ +product ACC 2188 0x0000 ACCM 2188 VL-PCI Bridge +product ACC 2051_HB 0x2051 2051 PCI Single Chip Solution (host bridge) +product ACC 2051_ISA 0x5842 2051 PCI Single Chip Solution (ISA bridge) + +/* Acard products */ +product ACARD AEC6710 0x8002 AEC6710 SCSI +product ACARD AEC6712UW 0x8010 AEC6712UW SCSI +product ACARD AEC6712U 0x8020 AEC6712U SCSI +product ACARD AEC6712S 0x8030 AEC6712S SCSI +product ACARD AEC6710D 0x8040 AEC6710D SCSI +product ACARD AEC6715UW 0x8050 AEC6715UW SCSI + +/* Accton products */ +product ACCTON MPX5030 0x1211 MPX 5030/5038 Ethernet + +/* Acer products */ +product ACER M1435 0x1435 M1435 VL-PCI Bridge + +/* Acer Labs products */ +product ALI M1445 0x1445 M1445 VL-PCI Bridge +product ALI M1449 0x1449 M1449 PCI-ISA Bridge +product ALI M1451 0x1451 M1451 Host-PCI Bridge +product ALI M1461 0x1461 M1461 Host-PCI Bridge +product ALI M1531 0x1531 M1531 Host-PCI Bridge +product ALI M1541 0x1541 M1541 Host-PCI Bridge +product ALI M1543 0x1533 M1543 PCI-ISA Bridge +product ALI M3309 0x3309 M3309 MPEG Decoder +product ALI M4803 0x5215 M4803 +product ALI M5229 0x5229 M5229 UDMA IDE Controller +product ALI M5237 0x5237 M5237 USB Host Controller +product ALI M7101 0x7101 M7101 Power Management Controller + +/* Adaptec products */ +product ADP AIC7850 0x5078 AIC-7850 +product ADP AIC7855 0x5578 AIC-7855 +product ADP AIC5900 0x5900 AIC-5900 ATM +product ADP AIC5905 0x5905 AIC-5905 ATM +product ADP AIC6915 0x6915 AIC-6915 10/100 Ethernet +product ADP AIC7860 0x6078 AIC-7860 +product ADP APA1480 0x6075 APA-1480 Ultra +product ADP 2940AU 0x6178 AHA-2940A Ultra +product ADP AIC7870 0x7078 AIC-7870 +product ADP 2940 0x7178 AHA-2940 +product ADP 3940 0x7278 AHA-3940 +product ADP 3985 0x7378 AHA-3985 +product ADP 2944 0x7478 AHA-2944 +product ADP AIC7895 0x7895 AIC-7895 Ultra +product ADP AIC7880 0x8078 AIC-7880 Ultra +product ADP 2940U 0x8178 AHA-2940 Ultra +product ADP 3940U 0x8278 AHA-3940 Ultra +product ADP 389XU 0x8378 AHA-389X Ultra +product ADP 2944U 0x8478 AHA-2944 Ultra +product ADP 2940UP 0x8778 AHA-2940 Ultra Pro + +product ADP2 2940U2 0x0010 AHA-2940 Ultra2 +product ADP2 2930U2 0x0011 AHA-2930 Ultra2 +product ADP2 AIC7890 0x001f AIC-7890/1 +product ADP2 3950U2B 0x0050 AHA-3950 Ultra2 +product ADP2 3950U2D 0x0051 AHA-3950 Ultra2 +product ADP2 AIC7896 0x005f AIC-7896/7 + +/* Addtron Products */ +product ADDTRON 8139 0x1360 8139 Ethernet + +/* ADMtek products */ +product ADMTEK AL981 0x0981 ADMtek AL981 10/100 Ethernet + +/* Advanced System Products */ +product ADVSYS 1200A 0x1100 +product ADVSYS 1200B 0x1200 +product ADVSYS ULTRA 0x1300 ABP-930/40UA +product ADVSYS WIDE 0x2300 ABP-940UW +product ADVSYS U2W 0x2500 ASB-3940U2W +product ADVSYS U3W 0x2700 ASB-3940U3W + +/* Alliance products */ +product ALLIANCE AT24 0x6424 AT24 +product ALLIANCE AT25 0x643d AT25 + +/* Alteon products */ +product ALTEON ACENIC 0x0001 ACEnic Gigabit Ethernet + +/* AMD products */ +product AMD PCNET_PCI 0x2000 79c970 PCnet-PCI LANCE Ethernet +product AMD PCNET_HOME 0x2001 79c978 PCnet-PCI Home +product AMD PCSCSI_PCI 0x2020 53c974 PCscsi-PCI SCSI +product AMD PCNETS_PCI 0x2040 79C974 PCnet-PCI Ethernet & SCSI +product AMD SC751_SC 0x7006 AMD751 System Controller +product AMD SC751_PPB 0x7007 AMD751 PCI-to-PCI Bridge +product AMD PBC756_ISA 0x7408 AMD756 PCI-to-ISA Bridge +product AMD PBC756_IDE 0x7409 AMD756 IDE controller +product AMD PBC756_PMC 0x740B AMD756 Power Management Controller +product AMD PBC756_USB 0x740C AMD756 USB Host Controller +product AMD HT7520 0x7450 (PLX) HT7520 PCIX Tunnel +product AMD HT7520_PIC 0x7451 (PLX) HT7520 PCIX IOAPIC +product AMD AMD8151_AGP 0x7454 AMD8151 AGP Device +product AMD AMD8151 0x7455 AMD8151 HyperTransport-AGP Bridge + +/* API Networks products */ +product API STURGEON 0x0010 AP1011 HyperTransport-PCI Bridge + +/* Apple products */ +product APPLE BANDIT 0x0001 Bandit Host-PCI Bridge +product APPLE GC 0x0002 Grand Central I/O Controller +product APPLE CONTROL 0x0003 Control +product APPLE PLANB 0x0004 PlanB +product APPLE OHARE 0x0007 OHare I/O Controller +product APPLE BANDIT2 0x0008 Bandit Host-PCI Bridge +product APPLE HEATHROW 0x0010 MAC-IO I/O Controller (Heathrow) +product APPLE PADDINGTON 0x0017 MAC-IO I/O Controller (Paddington) +product APPLE KEYLARGO_USB 0x0019 KeyLargo USB Controller +product APPLE UNINORTH1 0x001e UniNorth Host-PCI Bridge +product APPLE UNINORTH2 0x001f UniNorth Host-PCI Bridge +product APPLE UNINORTH_AGP 0x0020 UniNorth AGP Interface +product APPLE GMAC 0x0021 GMAC Ethernet +product APPLE KEYLARGO 0x0022 MAC-IO I/O Controller (KeyLargo) + +/* ARC Logic products */ +product ARC 1000PV 0xa091 1000PV +product ARC 2000PV 0xa099 2000PV +product ARC 2000MT 0xa0a1 2000MT + +/* ASIX Electronics products */ +product ASIX AX88140A 0x1400 AX88140A 10/100 Ethernet + +/* ATI products */ +product ATI MACH32 0x4158 Mach32 +product ATI MACH64_CT 0x4354 Mach64 CT +product ATI MACH64_CX 0x4358 Mach64 CX +product ATI MACH64_ET 0x4554 Mach64 ET +product ATI MACH64_VT 0x4654 Mach64 VT +product ATI MACH64_B 0x4750 Mach64 B +product ATI MACH64_GB 0x4742 Mach64 GB +product ATI MACH64_GD 0x4744 Mach64 GD +product ATI MACH64_GI 0x4749 Mach64 GI +product ATI MACH64_GP 0x4750 Mach64 GP +product ATI MACH64_GQ 0x4751 Mach64 GQ +product ATI MACH64_GT 0x4754 Mach64 GT +product ATI MACH64_GU 0x4755 Mach64 GU +product ATI MACH64_GV 0x4756 Mach64 GV +product ATI MACH64_GW 0x4757 Mach64 GW +product ATI MACH64_GX 0x4758 Mach64 GX +product ATI MACH64_GZ 0x475a Mach64 GZ +product ATI MACH64_LB 0x4c42 Mach64 LB +product ATI MACH64_LD 0x4c44 Mach64 LD +product ATI MACH64_LG 0x4c47 Mach64 LG +product ATI MACH64_LI 0x4c49 Mach64 LI +product ATI MACH64_LM 0x4c4d Mach64 LM +product ATI MACH64_LP 0x4c50 Mach64 LP +product ATI MACH64_LR 0x4c52 Mach64 LR + +/* Auravision products */ +product AURAVISION VXP524 0x01f7 VxP524 PCI Video Processor + +/* Aureal Semiconductor */ +product AUREAL AU8820 0x0001 AU8820 Vortex Digital Audio Processor + +/* Applied Micro Circuts products */ +product AMCIRCUITS S5933 0x4750 S5933 PCI Matchmaker +product AMCIRCUITS LANAI 0x8043 Myrinet LANai Interface +product AMCIRCUITS S5920 0x5920 S5920 PCI Target + +/* Atronics products */ +product ATRONICS IDE_2015PL 0x2015 IDE-2015PL + +/* Avance Logic products */ +product AVANCE AVL2301 0x2301 AVL2301 +product AVANCE AVG2302 0x2302 AVG2302 +product AVANCE2 ALG2301 0x2301 ALG2301 +product AVANCE2 ALG2302 0x2302 ALG2302 + +/* CCUBE products */ +product CCUBE CINEMASTER 0x8888 Cinemaster C 3.0 DVD Decoder + +/* AVM products */ +product AVM FRITZ_CARD 0x0a00 Fritz! Card ISDN Interface + +/* Bit3 products */ +product BIT3 PCIVME617 0x0001 PCI-VME Interface Mod. 617 +product BIT3 PCIVME618 0x0010 PCI-VME Interface Mod. 618 +product BIT3 PCIVME2706 0x0300 PCI-VME Interface Mod. 2706 + +/* Broadcom products */ +product BROADCOM BCM4211 0x4211 BCM4211 iLine10 Controller +product BROADCOM BCM4212 0x4212 BCM4212 V.90 Modem +product BROADCOM BCM5700 0x1644 BCM5700 10/100/1000 Ethernet +product BROADCOM BCM5701 0x1645 BCM5701 10/100/1000 Ethernet +product BROADCOM BCM5702 0x16a6 BCM5702 10/100/1000 Ethernet +product BROADCOM BCM5703 0x16a7 BCM5703 10/100/1000 Ethernet +product BROADCOM BCM5705 0x1653 BCM5705 10/100/1000 Ethernet +product BROADCOM BCM5820 0x5820 BCM5820 eCommerce Processor +product BROADCOM BCM5821 0x5821 BCM5821 Super-eCommerce Processor +product BROADCOM BCM5850 0x5850 BCM5850 SSL/TLS Protocol Processor + +/* Brooktree products */ +product BROOKTREE BT848 0x0350 Bt848 Video Capture +product BROOKTREE BT849 0x0351 Bt849 Video Capture +product BROOKTREE BT878 0x036e Bt878 Video Capture +product BROOKTREE BT879 0x036f Bt879 Video Capture + +/* BusLogic products */ +product BUSLOGIC MULTIMASTER_NC 0x0140 MultiMaster NC +product BUSLOGIC MULTIMASTER 0x1040 MultiMaster +product BUSLOGIC FLASHPOINT 0x8130 FlashPoint + +/* c't Magazin products */ +product C4T GPPCI 0x6773 GPPCI + +/* Chips and Technologies products */ +product CHIPS 64310 0x00b8 64310 +product CHIPS 65545 0x00d8 65545 +product CHIPS 65548 0x00dc 65548 +product CHIPS 65550 0x00e0 65550 +product CHIPS 65554 0x00e4 65554 + +/* Cirrus Logic products */ +product CIRRUS CL_GD7548 0x0038 CL-GD7548 +product CIRRUS CL_GD5430 0x00a0 CL-GD5430 +product CIRRUS CL_GD5434_4 0x00a4 CL-GD5434-4 +product CIRRUS CL_GD5434_8 0x00a8 CL-GD5434-8 +product CIRRUS CL_GD5436 0x00ac CL-GD5436 +product CIRRUS CL_GD5446 0x00b8 CL-GD5446 +product CIRRUS CL_GD5480 0x00bc CL-GD5480 +product CIRRUS CL_PD6729 0x1100 CL-PD6729 +product CIRRUS CL_PD6832 0x1110 CL-PD6832 PCI-CardBus Bridge +product CIRRUS CL_PD6833 0x1113 CL-PD6833 PCI-CardBus Bridge +product CIRRUS CL_GD7542 0x1200 CL-GD7542 +product CIRRUS CL_GD7543 0x1202 CL-GD7543 +product CIRRUS CL_GD7541 0x1204 CL-GD7541 +product CIRRUS CL_CD4400 0x4400 CL-CD4400 Communications Controller +product CIRRUS CS4610 0x6001 CS4610 SoundFusion Audio Accelerator +product CIRRUS CS4280 0x6003 CS4280 CrystalClear Audio Interface + +/* CMD Technology products -- info gleaned from their web site */ +product CMDTECH 640 0x0640 PCI0640 +/* No data on the CMD Tech. web site for the following as of Mar. 3 '98 */ +product CMDTECH 642 0x0642 PCI0642 +/* datasheets available from www.cmd.com for the followings */ +product CMDTECH 643 0x0643 PCI0643 +product CMDTECH 646 0x0646 PCI0646 +product CMDTECH 647 0x0647 PCI0647 +product CMDTECH 648 0x0648 PCI0648 +product CMDTECH 649 0x0649 PCI0649 + +/* Inclusion of 'A' in the following entry is probably wrong. */ +/* No data on the CMD Tech. web site for the following as of Mar. 3 '98 */ +product CMDTECH 650A 0x0650 PCI0650A +product CMDTECH 670 0x0670 USB0670 +product CMDTECH 673 0x0673 USB0673 + +/* C-Media products */ +product CMEDIA CMI8338A 0x0100 CMI8338A PCI Audio Device +product CMEDIA CMI8338B 0x0101 CMI8338B PCI Audio Device +product CMEDIA CMI8738 0x0111 CMI8738/C3DX PCI Audio Device +product CMEDIA HSP56 0x0211 HSP56 Audiomodem Riser + +/* Cogent Data Technologies products */ +product COGENT EM110TX 0x1400 EX110TX PCI Fast Ethernet Adapter + +/* Compaq products */ +product COMPAQ PCI_EISA_BRIDGE 0x0001 PCI-EISA Bridge +product COMPAQ PCI_ISA_BRIDGE 0x0002 PCI-ISA Bridge +product COMPAQ TRIFLEX1 0x1000 Triflex Host-PCI Bridge +product COMPAQ TRIFLEX2 0x2000 Triflex Host-PCI Bridge +product COMPAQ QVISION_V0 0x3032 QVision +product COMPAQ QVISION_1280P 0x3033 QVision 1280/p +product COMPAQ QVISION_V2 0x3034 QVision +product COMPAQ TRIFLEX4 0x4000 Triflex Host-PCI Bridge +product COMPAQ USB 0x7020 USB Controller +product COMPAQ SMART2P 0xae10 SMART2P RAID +product COMPAQ N100TX 0xae32 Netelligent 10/100 TX +product COMPAQ N10T 0xae34 Netelligent 10 T +product COMPAQ IntNF3P 0xae35 Integrated NetFlex 3/P +product COMPAQ DPNet100TX 0xae40 Dual Port Netelligent 10/100 TX +product COMPAQ IntPL100TX 0xae43 ProLiant Integrated Netelligent 10/100 TX +product COMPAQ DP4000 0xb011 Deskpro 4000 5233MMX +product COMPAQ NF3P_BNC 0xf150 NetFlex 3/P w/ BNC +product COMPAQ NF3P 0xf130 NetFlex 3/P + +/* Compex products - XXX better descriptions */ +product COMPEX NE2KETHER 0x1401 Ethernet +product COMPEX RL100ATX 0x2011 RL100-ATX 10/100 Ethernet +product COMPEX RL100TX 0x9881 RL100-TX 10/100 Ethernet + +/* Conexant Systems products */ +product CONEXANT SOFTK56 0x2443 SoftK56 PCI Software Modem + +/* Contaq Microsystems products */ +product CONTAQ 82C599 0x0600 82C599 PCI-VLB Bridge +product CONTAQ 82C693 0xc693 82C693 PCI-ISA Bridge + +/* Corollary Products */ +product COROLLARY CBUSII_PCIB 0x0014 \"C-Bus II\"-PCI Bridge + +/* Creative Labs products */ +product CREATIVELABS SBLIVE 0x0002 SBLive! EMU 10000 +product CREATIVELABS SBJOY 0x7002 PCI Gameport Joystick +product CREATIVELABS EV1938 0x8938 Ectiva 1938 + +/* Cyclades products */ +product CYCLADES CYCLOMY_1 0x0100 Cyclom-Y below 1M +product CYCLADES CYCLOMY_2 0x0101 Cyclom-Y above 1M +product CYCLADES CYCLOM4Y_1 0x0102 Cyclom-4Y below 1M +product CYCLADES CYCLOM4Y_2 0x0103 Cyclom-4Y above 1M +product CYCLADES CYCLOM8Y_1 0x0104 Cyclom-8Y below 1M +product CYCLADES CYCLOM8Y_2 0x0105 Cyclom-8Y above 1M +product CYCLADES CYCLOMZ_1 0x0200 Cyclom-Z below 1M +product CYCLADES CYCLOMZ_2 0x0201 Cyclom-Z above 1M + +/* Davicom Semiconductor products */ +product DAVICOM DM9102 0x9102 Davicom DM9102 10/100 Ethernet + +/* DEC products */ +product DEC 21050 0x0001 DECchip 21050 PCI-PCI Bridge +product DEC 21040 0x0002 DECchip 21040 Ethernet +product DEC 21030 0x0004 DECchip 21030 (\"TGA\") +product DEC NVRAM 0x0007 Zephyr NV-RAM +product DEC KZPSA 0x0008 KZPSA +product DEC 21140 0x0009 DECchip 21140 10/100 Ethernet +product DEC PBXGB 0x000d TGA2 +product DEC DEFPA 0x000f DEFPA +/* product DEC ??? 0x0010 ??? VME Interface */ +product DEC 21041 0x0014 DECchip 21041 Ethernet +product DEC DGLPB 0x0016 DGLPB (\"OPPO\") +product DEC 21142 0x0019 DECchip 21142/21143 10/100 Ethernet +product DEC 21052 0x0021 DECchip 21052 PCI-PCI Bridge +product DEC 21150 0x0022 DECchip 21150 PCI-PCI Bridge +product DEC 21152 0x0024 DECchip 21152 PCI-PCI Bridge +product DEC 21153 0x0025 DECchip 21153 PCI-PCI Bridge +product DEC 21154 0x0026 DECchip 21154 PCI-PCI Bridge +product DEC CPQ42XX 0x0046 Compaq SMART RAID 42xx + +/* Delta products */ +product DELTA 8139 0x1360 8139 Ethernet + +/* Diamond products */ +product DIAMOND VIPER 0x9001 Viper/PCI + +/* D-Link Systems products */ +product DLINK DFE550TX 0x1002 DFE-550TX 10/100 Ethernet + +/* Distributed Processing Technology products */ +product DPT SC_RAID 0xa400 SmartCache/SmartRAID +product DPT RAID_I2O 0xa501 SmartRAID (I2O) +product DPT MEMCTLR 0x1012 Memory Controller + +/* Dolphin products */ +product DOLPHIN PCISCI 0x0658 PCI-SCI Bridge + +/* Domex products */ +product DOMEX PCISCSI 0x0001 DMX-3191D + +/* ELSA products */ +product ELSA QS1PCI 0x1000 QuickStep 1000 ISDN card + +/* Emulex products */ +product EMULEX LPPFC 0x10df \"Light Pulse\" FibreChannel adapter + +/* Ensoniq products */ +product ENSONIQ AUDIOPCI 0x5000 AudioPCI +product ENSONIQ AUDIOPCI97 0x1371 AudioPCI 97 +product ENSONIQ CT5880 0x5880 CT5880 + +/* Epigram (now Broadcom) products */ +product EPIGRAM BCM4210 0xa0fa BCM4210 iLine10 Controller + +/* Essential Communications products */ +product ESSENTIAL RR_HIPPI 0x0001 RoadRunner HIPPI Interface +product ESSENTIAL RR_GIGE 0x0005 RoadRunner Gig-E Interface + +/* ESS Technology Inc products */ +product ESSTECH MAESTRO1 0x0100 Maestro 1 PCI Audio Accelerator +product ESSTECH MAESTRO2 0x1968 Maestro 2 PCI Audio Accelerator +product ESSTECH SOLO1 0x1969 Solo-1 PCI AudioDrive +product ESSTECH MAESTRO2E 0x1978 Maestro 2E PCI Audio Accelerator +product ESSTECH MAESTRO3 0x1998 Maestro 3 PCI Audio Accelerator +product ESSTECH MAESTRO3MODEM 0x1999 Maestro 3 Modem + +/* ESS Technology Inc products */ +product ESSTECH2 MAESTRO1 0x0100 Maestro 1 PCI Audio Accelerator + +/* O2 Micro Inc */ +product O2MICRO OZ6832 0x6832 OZ6832 CardBus Controller + +/* Evans & Sutherland products */ +product ES FREEDOM 0x0001 Freedom PCI-GBus Interface + +/* FORE products */ +product FORE PCA200 0x0210 ATM PCA-200 +product FORE PCA200E 0x0300 ATM PCA-200e + +/* Forte Media products */ +product FORTEMEDIA FM801 0x0801 Forte Media 801 Sound + +/* Future Domain products */ +product FUTUREDOMAIN TMC_18C30 0x0000 TMC-18C30 (36C70) + +/* Efficient Networks products */ +product EFFICIENTNETS ENI155PF 0x0000 155P-MF1 ATM (FPGA) +product EFFICIENTNETS ENI155PA 0x0002 155P-MF1 ATM (ASIC) +product EFFICIENTNETS ENI25P 0x0003 SpeedStream ENI-25p +product EFFICIENTNETS SS3000 0x0005 SpeedStream 3000 + +/* Galileo Technology products */ +product GALILEO GT64010A 0x0146 GT-64010A System Controller +product GALILEO GT64115 0x4111 GT-64115 System Controller +product GALILEO GT64011 0x4146 GT-64011 System Controller +product GALILEO GT64120 0x4620 GT-64120 System Controller +product GALILEO GT64130 0x6320 GT-64130 System Controller + +/* Hewlett-Packard products */ +product HP J2585A 0x1030 J2585A + +/* IBM products */ +product IBM MCABRIDGE 0x0002 MCA Bridge +product IBM ALTALITE 0x0005 CPU Bridge - Alta Lite +product IBM ALTAMP 0x0007 CPU Bridge - Alta MP +product IBM ISABRIDGE 0x000a ISA Bridge w/PnP +product IBM CPUBRIDGE 0x0017 CPU Bridge +product IBM LANSTREAMER 0x0018 Auto LANStreamer +product IBM GXT150P 0x001b GXT-150P 2D Accelerator +product IBM MCABRIDGE2 0x0020 MCA Bridge +product IBM 82351 0x0022 82351 PCI-PCI Bridge +product IBM SERVERAID 0x002e ServeRAID +product IBM OLYMPIC 0x003e Token Ring +product IBM MIAMI 0x0036 Miami/PCI +product IBM TURBOWAYS25 0x0053 Turboways 25 ATM +product IBM MPIC2 0xffff MPIC-II + +/* IDT products */ +product IDT 77201 0x0001 77201/77211 ATM (\"NICStAR\") + +/* Initio products */ +product INITIO I920 0x0002 INIC-920 SCSI +product INITIO I940 0x9400 INIC-940 SCSI +product INITIO I935 0x9401 INIC-935 SCSI +product INITIO I950 0x9500 INIC-950 SCSI + +/* Integrated Micro Solutions products */ +product IMS 8849 0x8849 8849 +product IMS TT128M 0x9128 TwinTurbo 128M + +/* Intel products */ +product INTEL PCEB 0x0482 82375EB/SB PCI-EISA Bridge (PCEB) +product INTEL CDC 0x0483 82424ZX Cache and DRAM controller (CDC) +product INTEL SIO 0x0484 82378ZB System I/O (SIO) +product INTEL 82426EX 0x0486 82426EX PCI-to-ISA Bridge (PCIB) +product INTEL PCMC 0x04a3 82434LX/NX PCI, Cache and Memory Controller (PCMC) +product INTEL IN_BUSINESS 0x1030 InBusiness Fast Ethernet LAN Controller +product INTEL 82559ER 0x1209 82559ER Fast Ethernet LAN Controller +product INTEL 82092AA 0x1222 82092AA IDE controller +product INTEL SAA7116 0x1223 SAA7116 +product INTEL 82596 0x1226 82596 LAN Controller +product INTEL EEPRO100 0x1227 EE Pro 100 10/100 Fast Ethernet +product INTEL EEPRO100S 0x1228 EE Pro 100 Smart 10/100 Fast Ethernet +product INTEL 82557 0x1229 82557 Fast Ethernet LAN Controller +product INTEL 82437FX 0x122d 82437FX System Controller (TSC) +product INTEL 82371FB_ISA 0x122e 82371FB PCI-to-ISA Bridge (PIIX) +product INTEL 82371FB_IDE 0x1230 82371FB IDE controller (PIIX) +product INTEL 82371MX 0x1234 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX) +product INTEL 82437MX 0x1235 82437MX Mobile System Controller (MTSC) +product INTEL 82441FX 0x1237 82441FX PCI and Memory Controller (PMC) +product INTEL 82380AB 0x123c 82380AB Mobile PCI-to-ISA Bridge (MISA) +product INTEL 82380FB 0x124b 82380FB Mobile PCI-to-PCI Bridge (MPCI2) +product INTEL 82439HX 0x1250 82439HX System Controller (TXC) +product INTEL 82801AA_LPC 0x2410 82801AA LPC Interface Bridge +product INTEL 82801AA_IDE 0x2411 82801AA IDE Controller +product INTEL 82801AA_USB 0x2412 82801AA USB Controller +product INTEL 82801AA_SMB 0x2413 82801AA SMBus Controller +product INTEL 82801AA_ACA 0x2415 82801AA AC-97 Audio Controller +product INTEL 82801AA_ACM 0x2416 82801AA AC-97 PCI Modem +product INTEL 82801AA_HPB 0x2418 82801AA Hub-to-PCI Bridge +product INTEL 82801AB_LPC 0x2420 82801AB LPC Interface Bridge +product INTEL 82801AB_IDE 0x2421 82801AB IDE Controller +product INTEL 82801AB_USB 0x2422 82801AB USB Controller +product INTEL 82801AB_SMB 0x2423 82801AB SMBus Controller +product INTEL 82801AB_ACA 0x2425 82801AB AC-97 Audio Controller +product INTEL 82801AB_ACM 0x2426 82801AB AC-97 PCI Modem +product INTEL 82801AB_HPB 0x2428 82801AB Hub-to-PCI Bridge +product INTEL 82801BA_LPC 0x2440 82801BA LPC Interface Bridge +product INTEL 82801BA_USB1 0x2442 82801BA USB Controller +product INTEL 82801BA_SMB 0x2443 82801BA SMBus Controller +product INTEL 82801BA_USB2 0x2444 82801BA USB Controller +product INTEL 82801BA_ACA 0x2445 82801BA AC-97 Audio Controller +product INTEL 82801BA_ACM 0x2446 82801BA AC-97 PCI Modem +product INTEL 82801BA_LAN 0x2449 82801BA LAN Controller +product INTEL 82801BA_IDE 0x244B 82801BA IDE Controller +product INTEL 82801BA_HPB 0x244E 82801BA Hub-to-PCI Bridge +product INTEL 82371SB_ISA 0x7000 82371SB PCI-to-ISA Bridge (PIIX3) +product INTEL 82371SB_IDE 0x7010 82371SB IDE Interface (PIIX3) +product INTEL 82371SB_USB 0x7020 82371SB USB Host Controller (PIIX3) +product INTEL 82437VX 0x7030 82437VX System Controller (TVX) +product INTEL 82439TX 0x7100 82439TX System Controller (MTXC) +product INTEL 82371AB_ISA 0x7110 82371AB PCI-to-ISA Bridge (PIIX4) +product INTEL 82371AB_IDE 0x7111 82371AB IDE controller (PIIX4) +product INTEL 82371AB_USB 0x7112 82371AB USB Host Controller (PIIX4) +product INTEL 82371AB_PMC 0x7113 82371AB Power Management Controller (PIIX4) +product INTEL 82810_MCH 0x7120 82810 Memory Controller Hub +product INTEL 82810_GC 0x7121 82810 Graphics Controller +product INTEL 82810_DC100_MCH 0x7122 82810-DC100 Memory Controller Hub +product INTEL 82810_DC100_GC 0x7123 82810-DC100 Graphics Controller +product INTEL 82810E_MCH 0x7124 82810E Memory Controller Hub +product INTEL 82810E_GC 0x7125 82810E Graphics Controller +product INTEL 82443LX 0x7180 82443LX PCI AGP Controller (PAC) +product INTEL 82443LX_AGP 0x7181 82443LX AGP Interface (PAC) +product INTEL 82443BX 0x7190 82443BX Host Bridge/Controller +product INTEL 82443BX_AGP 0x7191 82443BX AGP Interface +product INTEL 82443BX_NOAGP 0x7192 82443BX Host Bridge/Controller (AGP disabled) +product INTEL 82440MX 0x7194 82440MX Host Bridge/Controller +product INTEL 82440MX_ACA 0x7195 82440MX AC-97 Audio Controller +product INTEL 82440MX_ISA 0x7198 82440MX PCI-to-ISA Bridge +product INTEL 82440MX_IDE 0x7199 82440MX IDE Controller +product INTEL 82440MX_USB 0x719a 82440MX USB Host Controller +product INTEL 82440MX_PMC 0x719b 82440MX Power Management Controller +product INTEL I740 0x7800 i740 Graphics Accelerator +product INTEL PCI450_PB 0x84c4 82454KX/GX PCI Bridge (PB) +product INTEL PCI450_MC 0x84c5 82451KX/GX Memory Controller (MC) +product INTEL 82451NX_MIOC 0x84ca 82451NX Memory & I/O Controller (MIOC) +product INTEL 82451NX_PXB 0x84cb 82451NX PCI Expander Bridge (PXB) + +/* Intergraph products */ +product INTERGRAPH 4D50T 0x00e4 Powerstorm 4D50T + +/* I. T. T. products */ +product ITT AGX016 0x0001 AGX016 +product ITT ITT3204 0x0002 ITT3204 MPEG Decoder + +/* KTI products - XXX better descriptions */ +product KTI NE2KETHER 0x3000 Ethernet + +/* LAN Media Corporation */ +product LMC HSSI 0x0003 HSSI Interface +product LMC DS3 0x0004 DS3 Interface +product LMC SSI 0x0005 SSI + +/* LeadTek Research */ +product LEADTEK S3_805 0x0000 S3 805 + +/* Linear Systems / CompuModules */ +product LINEARSYS DVB_TX 0x7629 DVB Transmitter +product LINEARSYS DVB_RX 0x7630 DVB Receiver + +/* Lite-On products */ +product LITEON 82C168 0x0002 82C168/82C169 (PNIC) 10/100 Ethernet +product LITEON 82C115 0xc115 82C115 (PNIC II) 10/100 Ethernet + +/* Lucent products */ +product LUCENT LTMODEM_0440 0x0440 K56flex DSVD LTMODEM +product LUCENT LTMODEM_0441 0x0441 LTMODEM +product LUCENT LTMODEM_0442 0x0442 LTMODEM +product LUCENT LTMODEM_0443 0x0443 LTMODEM +product LUCENT LTMODEM_0444 0x0444 LTMODEM +product LUCENT LTMODEM_0445 0x0445 LTMODEM +product LUCENT LTMODEM_0446 0x0446 LTMODEM +product LUCENT LTMODEM_0447 0x0447 LTMODEM +product LUCENT LTMODEM_0448 0x0448 LTMODEM +product LUCENT LTMODEM_0449 0x0449 LTMODEM +product LUCENT LTMODEM_044A 0x044A LTMODEM +product LUCENT LTMODEM_044B 0x044B LTMODEM +product LUCENT LTMODEM_044C 0x044C LTMODEM +product LUCENT LTMODEM_044D 0x044D LTMODEM +product LUCENT LTMODEM_044E 0x044E LTMODEM +product LUCENT LTMODEM_0450 0x0450 LTMODEM +product LUCENT LTMODEM_0451 0x0451 LTMODEM +product LUCENT LTMODEM_0452 0x0452 LTMODEM +product LUCENT LTMODEM_0453 0x0453 LTMODEM +product LUCENT LTMODEM_0454 0x0454 LTMODEM +product LUCENT LTMODEM_0455 0x0455 LTMODEM +product LUCENT LTMODEM_0456 0x0456 LTMODEM +product LUCENT LTMODEM_0457 0x0457 LTMODEM +product LUCENT LTMODEM_0458 0x0458 LTMODEM +product LUCENT LTMODEM_0459 0x0459 LTMODEM +product LUCENT LTMODEM_045A 0x045A LTMODEM +product LUCENT USBHC 0x5801 USB Host Controller + +/* Macronix */ +product MACRONIX MX98713 0x0512 MX98713 (PMAC) 10/100 Ethernet +product MACRONIX MX987x5 0x0531 MX987x5 (PMAC) 10/100 Ethernet + +/* Madge Networks products */ +product MADGE COLLAGE25 0x1000 Collage 25 ATM adapter +product MADGE COLLAGE155 0x1001 Collage 155 ATM adapter + +/* Matrox products */ +product MATROX ATLAS 0x0518 MGA PX2085 (\"Atlas\") +product MATROX MILLENNIUM 0x0519 MGA Millennium 2064W +product MATROX MYSTIQUE 0x051a MGA Mystique 1064SG +product MATROX MILLENNIUM2 0x051b MGA Millennium II 2164W +product MATROX MILLENNIUM2_AGP 0x051f MGA Millennium II 2164WA-B AG +product MATROX G200_PCI 0x0520 MGA G200 PCI +product MATROX G200_AGP 0x0521 MGA G200 AGP +product MATROX G400_AGP 0x0525 MGA G400 AGP +product MATROX IMPRESSION 0x0d10 MGA Impression +product MATROX G100_PCI 0x1000 MGA G100 PCI +product MATROX G100_AGP 0x1001 MGA G100 AGP + +/* Motorola products */ +product MOT MPC105 0x0001 MPC105 \"Eagle\" Host Bridge +product MOT MPC106 0x0002 MPC106 \"Grackle\" Host Bridge + +/* Mylex products */ +product MYLEX 960P 0x0001 DAC960P RAID controller + +/* Mutech products */ +product MUTECH MV1000 0x0001 MV1000 + +/* NetVin products - XXX better descriptions */ +product NETVIN 5000 0x5000 5000 Ethernet + +/* Newbridge / Tundra products */ +product NEWBRIDGE CA91CX42 0x0000 Universe VME bridge + +/* National Semiconductor products */ +product NS DP83810 0x0001 DP83810 10/100 Ethernet +product NS DP83815 0x0020 DP83815 10/100 Ethernet +product NS NS87410 0xd001 NS87410 + +/* NCR/Symbios Logic products */ +product SYMBIOS 810 0x0001 53c810 +product SYMBIOS 820 0x0002 53c820 +product SYMBIOS 825 0x0003 53c825 +product SYMBIOS 815 0x0004 53c815 +product SYMBIOS 810AP 0x0005 53c810AP +product SYMBIOS 860 0x0006 53c860 +product SYMBIOS 896 0x000b 53c896 +product SYMBIOS 895 0x000c 53c895 +product SYMBIOS 885 0x000d 53c885 +product SYMBIOS 875 0x000f 53c875 +product SYMBIOS 1510 0x0010 53c1510 +product SYMBIOS 875J 0x008f 53c875J + +/* Packet Engines products */ +product SYMBIOS PE_GNIC 0x0702 Packet Engines G-NIC Ethernet + +/* NEC products */ +product NEC USB 0x0035 USB Host Controller +product NEC POWERVR2 0x0046 PowerVR PCX2 +product NEC PD72872 0x0063 uPD72872 IEEE 1394 OHCI Host Controller +product NEC PD72870 0x00cd uPD72870 IEEE 1394 OHCI Host Controller +product NEC PD72871 0x00ce uPD72871 IEEE 1394 OHCI Host Controller + +/* Neomagic products */ +product NEOMAGIC NMMG128ZV 0x0003 MagicGraph 128ZV +product NEOMAGIC NMMG2160 0x0004 MagicGraph 128XD +product NEOMAGIC NMMM256AV_VGA 0x0005 MagicMedia 256AV VGA +product NEOMAGIC NMMM256ZX_VGA 0x0006 MagicMedia 256ZX VGA +product NEOMAGIC NMMM256AV_AU 0x8005 MagicMedia 256AV Audio +product NEOMAGIC NMMM256ZX_AU 0x8006 MagicMedia 256ZX Audio + +/* Netgear products */ +product NETGEAR GA620 0x620a GA620 Gigabit Ethernet + +/* NexGen products */ +product NEXGEN NX82C501 0x4e78 NX82C501 Host-PCI Bridge + +/* NKK products */ +product NKK NDR4600 0xA001 NDR4600 Host-PCI Bridge + +/* Number Nine products */ +product NUMBER9 I128 0x2309 Imagine-128 +product NUMBER9 I128_2 0x2339 Imagine-128 II + +/* Nvidia Corporationn products */ +product NVIDIA RIVATNT 0x0020 RIVA TNT +product NVIDIA RIVATNT2 0x0028 RIVA TNT2 +product NVIDIA RIVATNT2U 0x0029 RIVA TNT2 Ultra +product NVIDIA VANTA 0x002C Vanta +product NVIDIA RIVATNT2M64 0x002D RIVA TNT2 Model 64 +product NVIDIA ALADDINTNT2 0x00A0 Aladdin TNT2 +product NVIDIA GEFORCE256 0x0100 GeForce 256 +product NVIDIA GEFORCEDDR 0x0101 GeForce DDR +product NVIDIA QUADRO 0x0103 Quadro +product NVIDIA GEFORCE2 0x0150 GeForce2 GTS +product NVIDIA GEFORCE2DDR 0x0151 GeForce2 GTS (DDR) +product NVIDIA GEFORCE2BR 0x0152 GeForce2 GTS +product NVIDIA QUADRO2 0x0153 Quadro2 + +/* Nvidia Corporation & SGS Thomson Microelectric */ +product NVIDIA_SGS RIVA128 0x0018 Riva 128 + +/* Oak Technologies products */ +product OAKTECH OTI1007 0x0107 OTI107 + +/* Olicom products */ +product OLICOM OC2183 0x0013 Olicom OC-2183/2185 Ethernet +product OLICOM OC2325 0x0012 Olicom OC-2325 Ethernet +product OLICOM OC2326 0x0014 Olicom OC-2326 10/100-TX Ethernet + +/* Opti products */ +product OPTI 82C557 0xc557 82C557 +product OPTI 82C558 0xc558 82C558 +product OPTI 82C568 0xc568 82C568 +product OPTI 82D568 0xd568 82D568 +product OPTI 82C621 0xc621 82C621 +product OPTI 82C822 0xc822 82C822 +product OPTI RM861HA 0xc861 RM861HA +product OPTI 82C700 0xc700 82C700 +product OPTI 82C701 0xc701 82C701 + +/* PC Tech products */ +product PCTECH RZ1000 0x1000 RZ1000 + +/* PLX Technology products */ +product PLX 9060ES 0x906e 9060ES PCI bus controller + +/* ProLAN products - XXX better descriptions */ +product PROLAN NE2KETHER 0x1980 Ethernet + +/* Promise products */ +product PROMISE DC5030 0x5300 DC5030 +product PROMISE ULTRA33 0x4d33 Ultra33/ATA Bus Master IDE Accelerator +product PROMISE ULTRA66 0x4d38 Ultra66/ATA Bus Master IDE Accelerator +product PROMISE ULTRA100 0x4d30 Ultra100/ATA Bus Master IDE Accelerator + +/* QLogic products */ +product QLOGIC ISP1020 0x1020 ISP1020 +product QLOGIC ISP1022 0x1022 ISP1022 +product QLOGIC ISP1080 0x1080 ISP1080 +product QLOGIC ISP1240 0x1240 ISP1240 +product QLOGIC ISP2100 0x2100 ISP2100 + +/* Quantum Designs products */ +product QUANTUMDESIGNS 8500 0x0001 8500 +product QUANTUMDESIGNS 8580 0x0002 8580 + +/* Realtek (Creative Labs?) products */ +product REALTEK RT8029 0x8029 8029 Ethernet +product REALTEK RT8129 0x8129 8129 10/100 Ethernet +product REALTEK RT8139 0x8139 8139 10/100 Ethernet + +/* RICOH products */ +product RICOH Rx5C465 0x0465 5C465 PCI-CardBus bridge +product RICOH Rx5C466 0x0466 5C466 PCI-CardBus bridge +product RICOH Rx5C475 0x0475 5C475 PCI-CardBus bridge +product RICOH RL5C476 0x0476 5C476 PCI-CardBus bridge +product RICOH Rx5C477 0x0477 5C477 PCI-CardBus bridge +product RICOH Rx5C478 0x0478 5C478 PCI-CardBus bridge + +/* RISCom (SDL Communications, Inc?) products */ +product RISCOM N2 0x5568 N2 + +/* RNS products */ +product RNS FDDI 0x2200 2200 FDDI + +/* S3 products */ +product S3 VIRGE 0x5631 ViRGE +product S3 TRIO32 0x8810 Trio32 +product S3 TRIO64 0x8811 Trio32/64 +product S3 AURORA64P 0x8812 Aurora64V+ +product S3 TRIO64UVP 0x8814 Trio64UV+ +product S3 VIRGE_VX 0x883d ViRGE/VX +product S3 868 0x8880 868 +product S3 928 0x88b0 86C928 +product S3 864_0 0x88c0 86C864-0 +product S3 864_1 0x88c1 86C864-1 +product S3 864_2 0x88c2 86C864-2 +product S3 864_3 0x88c3 86C864-3 +product S3 964_0 0x88d0 86C964-0 +product S3 964_1 0x88d1 86C964-1 +product S3 964_2 0x88d2 86C964-2 +product S3 964_3 0x88d3 86C964-3 +product S3 968_0 0x88f0 86C968-0 +product S3 968_1 0x88f1 86C968-1 +product S3 968_2 0x88f2 86C968-2 +product S3 968_3 0x88f3 86C968-3 +product S3 TRIO64V2_DX 0x8901 Trio64V2/DX +product S3 PLATO_PX 0x8901 Plato/PX +product S3 TRIO3D 0x8904 86C365 Trio3D +product S3 VIRGE_DX 0x8a01 ViRGE/DX +product S3 VIRGE_GX2 0x8a10 ViRGE/GX2 +product S3 TRIO3D2X 0x8a13 Trio3D/2X +product S3 SAVAGE3D 0x8a20 Savage3D +product S3 SAVAGE3D_MV 0x8a21 Savage3D+MV +product S3 SAVAGE4 0x8a22 Savage4 +product S3 VIRGE_MX 0x8c01 ViRGE/MX +product S3 VIRGE_MXP 0x8c03 ViRGE/MXP +product S3 SAVAGE_MX_MV 0x8c10 Savage/MX+MV +product S3 SAVAGE_MX 0x8c11 Savage/MX +product S3 SAVAGE_IX_MV 0x8c12 Savage/IX+MV +product S3 SAVAGE_IX 0x8c13 Savage/IX +product S3 SAVAGE2000 0x9102 Savage2000 +product S3 SONICVIBES 0xca00 SonicVibes + +/* Samsung Semiconductor products */ +product SAMSUNGSEMI KS8920 0x8920 KS8920 10/100 Ethernet + +/* SGI products */ +product SGI IOC3 0x0003 IOC3 +product SGI RAD1 0x0005 PsiTech RAD1 +product SGI TIGON 0x0009 Tigon Gigabit Ethernet + +/* SGS Thomson products */ +product SGSTHOMSON 2000 0x0008 STG 2000X +product SGSTHOMSON 1764 0x1746 STG 1764X + +/* SiByte, Inc. products */ +product SIBYTE SB1250_PCI 0x0001 BCM1250 PCI Host Bridge +product SIBYTE SB1250_LDT 0x0002 BCM1250 HyperTransport Host Bridge + +/* Sigma Designs products */ +product SIGMA HOLLYWOODPLUS 0x8300 REALmagic Hollywood-Plus MPEG-2 Decoder + +/* Silicon Integrated System products */ +product SIS 86C201 0x0001 86C201 +product SIS 86C202 0x0002 86C202 +product SIS 86C205 0x0005 86C205 +product SIS 85C503 0x0008 85C503 or 5597/5598 ISA bridge +product SIS 600PMC 0x0009 600 Power Mngmt Controller +product SIS 5597_VGA 0x0200 5597/5598 integrated VGA +product SIS 85C501 0x0406 85C501 +product SIS 85C496 0x0496 85C496 +product SIS 530HB 0x0530 530 Host to PCI Bridge +product SIS 85C601 0x0601 85C601 +product SIS 900 0x0900 SiS 900 10/100 Ethernet +product SIS 5597_IDE 0x5513 5597/5598 IDE controller +product SIS 5597_HB 0x5597 5597/5598 host bridge +product SIS 530VGA 0x6306 530 GUI Accelerator+3D +product SIS 6326 0x6326 6326 AGP VGA +product SIS 5597_USB 0x7001 5597/5598 USB host controller +product SIS 7016 0x7016 SiS 7016 10/100 Ethernet + +/* Silicon Motion products */ +product SILMOTION LYNX_E 0x0810 Lynx E + +/* SMC products */ +product SMC 37C665 0x1000 FDC 37C665 +product SMC 37C922 0x1001 FDC 37C922 +product SMC 83C170 0x0005 83C170 (\"EPIC/100\") Fast Ethernet +product SMC 83C175 0x0006 83C175 (\"EPIC/100\") Fast Ethernet + +/* Solidum Systems Corporation */ +product SOLIDUM AMD971 0x2000 SNP8023: AMD 971 +product SOLIDUM CLASS802 0x8023 SNP8023: Classifier Engine + +/* Sony products */ +product SONY CXD1947A 0x8009 CXD1947A IEEE 1394 Host Controller +product SONY CXD32222 0x8039 CXD3222 OHCI IEEE 1394 Host Controller +product SONY MEMSTICK 0x808a Memory Stick I/F Controller + +/* Sun Microsystems products */ +product SUN EBUS 0x1000 PCIO Ebus2 +product SUN HMENETWORK 0x1001 PCIO Happy Meal Ethernet +product SUN SIMBA 0x5000 Simba PCI bridge +product SUN MS_IIep 0x9000 microSPARC IIep PCI +product SUN US_IIi 0xa000 UltraSPARC IIi PCI + +/* Sundance Technology products */ +product SUNDANCETI ST201 0x0201 ST201 10/100 Ethernet + +/* Surecom Technology products */ +product SURECOM NE34 0x0e34 NE-34 Ethernet + +/* Symphony Labs products */ +product SYMPHONY 82C101 0x0001 82C101 +product SYMPHONY 82C103 0x0103 82C103 +product SYMPHONY 82C105 0x0105 82C105 +product SYMPHONY2 82C101 0x0001 82C101 +product SYMPHONY 83C553 0x0565 83C553 PCI-ISA Bridge + +/* Schneider & Koch (really SysKonnect) products */ +product SCHNEIDERKOCH SKNET_FDDI 0x4000 SK-NET FDDI-xP + +/* Tekram Technology products (1st PCI Vendor ID)*/ +product TEKRAM DC290 0xdc29 DC-290(M) + +/* Tekram Technology products (2nd PCI Vendor ID) */ +product TEKRAM2 DC690C 0x690c DC-690C + +/* Texas Instruments products */ +product TI TLAN 0x0500 TLAN +product TI TVP4020 0x3d07 TVP4020 Permedia 2 +product TI TSB12LV21 0x8000 TSB12LV21 IEEE 1394 Host Controller +product TI TSB12LV22 0x8009 TSB12LV22 OHCI IEEE 1394 Host Controller +product TI TSB12LV23 0x8019 TSB12LV23 OHCI IEEE 1394 Host Controller +product TI TSB12LV26 0x8020 TSB12LV26 OHCI IEEE 1394 Host Controller +product TI PCI1130 0xac12 PCI1130 PCI-CardBus Bridge +product TI PCI1031 0xac13 PCI1031 PCI-PCMCIA Bridge +product TI PCI1131 0xac15 PCI1131 PCI-CardBus Bridge +product TI PCI1250 0xac16 PCI1250 PCI-CardBus Bridge +product TI PCI1220 0xac17 PCI1220 PCI-CardBus Bridge +product TI PCI1221 0xac19 PCI1221 PCI-CardBus Bridge +product TI PCI1450 0xac1b PCI1450 PCI-CardBus Bridge +product TI PCI1225 0xac1c PCI1225 PCI-CardBus Bridge +product TI PCI1251 0xac1d PCI1251 PCI-CardBus Bridge +product TI PCI1211 0xac1e PCI1211 PCI-CardBus Bridge +product TI PCI1251B 0xac1f PCI1251B PCI-CardBus Bridge +product TI PCI2030 0xac20 PCI2030 PCI-PCI Bridge +product TI PCI1420 0xac51 PCI1420 PCI-CardBus Bridge +product TI PCI1451 0xac52 PCI1451 PCI-CardBus Bridge + +/* Toshiba America products */ +product TOSHIBA R4X00 0x0009 R4x00 Host-PCI Bridge +product TOSHIBA TC35856F 0x0020 TC35856F ATM (\"Meteor\") + +/* Toshiba America Info Systems products */ +product TOSHIBA2 HOST 0x0601 Host Bridge/Controller +product TOSHIBA2 ISA 0x0602 ISA Bridge +product TOSHIBA2 ToPIC95 0x0603 ToPIC95 CardBus-PCI Bridge +product TOSHIBA2 ToPIC95B 0x060a ToPIC95B CardBus-PCI Bridge +product TOSHIBA2 ToPIC97 0x060f ToPIC97 CardBus-PCI Bridge +product TOSHIBA2 ToPIC100 0x0617 ToPIC100 CardBus-PCI Bridge +product TOSHIBA2 FIRO 0x0701 Fast Infrared Type O + +/* Trident products */ +product TRIDENT CYBERBLADE_I7 0x8420 CyberBlade i7 +product TRIDENT TGUI_9320 0x9320 TGUI 9320 +product TRIDENT TGUI_9350 0x9350 TGUI 9350 +product TRIDENT TGUI_9360 0x9360 TGUI 9360 +product TRIDENT CYBER_9397 0x9397 CYBER 9397 +product TRIDENT CYBER_9397DVD 0x939a CYBER 9397DVD +product TRIDENT CYBER_9525 0x9525 CYBER 9525 +product TRIDENT TGUI_9420 0x9420 TGUI 9420 +product TRIDENT TGUI_9440 0x9440 TGUI 9440 +product TRIDENT TGUI_9660 0x9660 TGUI 9660 +product TRIDENT TGUI_9680 0x9680 TGUI 9680 +product TRIDENT TGUI_9682 0x9682 TGUI 9682 + +/* Triones Technologies products */ +/* The 366 and 370 controllers have the same product ID */ +product TRIONES HPT366 0x0004 HPT366/370 IDE Controller + +/* TriTech Microelectronics products*/ +product TRITECH TR25202 0xfc02 Pyramid3D TR25202 + +/* Tseng Labs products */ +product TSENG ET4000_W32P_A 0x3202 ET4000w32p rev A +product TSENG ET4000_W32P_B 0x3205 ET4000w32p rev B +product TSENG ET4000_W32P_C 0x3206 ET4000w32p rev C +product TSENG ET4000_W32P_D 0x3207 ET4000w32p rev D +product TSENG ET6000 0x3208 ET6000 + +/* UMC products */ +product UMC UM82C881 0x0001 UM82C881 486 Chipset +product UMC UM82C886 0x0002 UM82C886 ISA Bridge +product UMC UM8673F 0x0101 UM8673F EIDE Controller +product UMC UM8881 0x0881 UM8881 HB4 486 PCI Chipset +product UMC UM82C891 0x0891 UM82C891 +product UMC UM886A 0x1001 UM886A +product UMC UM8886BF 0x673a UM8886BF +product UMC UM8710 0x8710 UM8710 +product UMC UM8886 0x886a UM8886 +product UMC UM8881F 0x8881 UM8881F PCI-Host bridge +product UMC UM8886F 0x8886 UM8886F PCI-ISA bridge +product UMC UM8886A 0x888a UM8886A +product UMC UM8891A 0x8891 UM8891A +product UMC UM9017F 0x9017 UM9017F +product UMC UM8886N 0xe88a UM8886N +product UMC UM8891N 0xe891 UM8891N + +/* ULSI Systems products */ +product ULSI US201 0x0201 US201 + +/* US Robotics products */ +product USR 3CP5609 0x1008 3CP5609 PCI 16550 Modem + +/* V3 Semiconductor products */ +product V3 V292PBC 0x0292 V292PBC AMD290x0 Host-PCI Bridge +product V3 V960PBC 0x0960 V960PBC i960 Host-PCI Bridge +product V3 V96DPC 0xC960 V96DPC i960 (Dual) Host-PCI Bridge + +/* VIA Technologies products, from http://www.via.com.tw/ */ +product VIATECH VT8371_HB 0x0391 VT8371 (Apollo KX133) Host Bridge +product VIATECH VT8501_MVP4 0x0501 VT8501 MVP4 System Controller +product VIATECH VT82C505 0x0505 VT82C505 (Pluto) +product VIATECH VT82C561 0x0561 VT82C561 +product VIATECH VT82C586A_IDE 0x0571 VT82C586A IDE Controller +product VIATECH VT82C576 0x0576 VT82C576 3V +product VIATECH VT82C580VP 0x0585 VT82C580 (Apollo VP) Host-PCI Bridge +product VIATECH VT82C586_ISA 0x0586 VT82C586 (Apollo VP) PCI-ISA Bridge +product VIATECH VT82C595 0x0595 VT82C595 (Apollo VP2) Host-PCI Bridge +product VIATECH VT82C596A 0x0596 VT82C596A (Apollo Pro) PCI-ISA Bridge +product VIATECH VT82C597 0x0597 VT82C597 (Apollo VP3) Host-PCI Bridge +product VIATECH VT82C598PCI 0x0598 VT82C598 (Apollo MVP3) Host-PCI +product VIATECH VT82C686A_ISA 0x0686 VT82C686A (Apollo KX133) PCI-ISA Bridge +product VIATECH VT82C691 0x0691 VT82C691 (Apollo Pro) Host-PCI +product VIATECH VT82C693 0x0693 VT82C693 (Apollo Pro Plus) Host-PCI +product VIATECH VT86C926 0x0926 VT86C926 Amazon PCI-Ethernet Controller +product VIATECH VT82C570M 0x1000 VT82C570M (Apollo) Host-PCI Bridge +product VIATECH VT82C570MV 0x1006 VT82C570M (Apollo) PCI-ISA Bridge +product VIATECH VT82C586_IDE 0x1571 VT82C586 (Apollo VP) IDE Controller +product VIATECH VT82C595_2 0x1595 VT82C595 (Apollo VP2) Host-PCI Bridge +product VIATECH VT83C572 0x3038 VT83C572 USB Controller +product VIATECH VT82C586_PWR 0x3040 VT82C586 (Apollo VP) Power Management Controller +product VIATECH VT3043 0x3043 VT3043 (Rhine) 10/100 Ethernet +product VIATECH VT82C686A_SMB 0x3057 VT82C686A SMBus Controller +product VIATECH VT82C686A_AC97 0x3058 VT82C686A AC-97 Audio Controller +product VIATECH VT82C686A_MC97 0x3068 VT82C686A MC-97 Modem Controller +product VIATECH VT86C100A 0x6100 VT86C100A (Rhine-II) 10/100 Ethernet +product VIATECH VT8371_PPB 0x8391 VT8371 (Apollo KX133) PCI-PCI Bridge +product VIATECH VT8501AGP 0x8501 VT8501 PCI-AGP +product VIATECH VT82C597AGP 0x8597 VT82C597 (Apollo VP3) PCI-AGP +product VIATECH VT82C598AGP 0x8598 VT82C598 (Apollo MVP3) PCI-AGP + +/* Vortex Computer Systems products */ +/* GDT_PCI */ +product VORTEX GDT_60x0 0x0000 GDT6000/6020/6050 +product VORTEX GDT_6000B 0x0001 GDT6000B/6010 +/* GDT_PCINEW */ +product VORTEX GDT_6x10 0x0002 GDT6110/6510 +product VORTEX GDT_6x20 0x0003 GDT6120/6520 +product VORTEX GDT_6530 0x0004 GDT6530 +product VORTEX GDT_6550 0x0005 GDT6550 +/* GDT_PCINEW, wide/ultra SCSI controllers */ +product VORTEX GDT_6x17 0x0006 GDT6117/6517 +product VORTEX GDT_6x27 0x0007 GDT6127/6527 +product VORTEX GDT_6537 0x0008 GDT6537 +product VORTEX GDT_6557 0x0009 GDT6557/6557-ECC +/* GDT_PCINEW, wide SCSI controllers */ +product VORTEX GDT_6x15 0x0010 GDT6115/6515 +product VORTEX GDT_6x25 0x0011 GDT6125/6525 +product VORTEX GDT_6535 0x0012 GDT6535 +product VORTEX GDT_6555 0x0013 GDT6555/6555-ECC +/* GDT_MPR, RP series, wide/ultra SCSI */ +product VORTEX GDT_6x17RP 0x0100 GDT6117RP/GDT6517RP +product VORTEX GDT_6x27RP 0x0101 GDT6127RP/GDT6527RP +product VORTEX GDT_6537RP 0x0102 GDT6537RP +product VORTEX GDT_6557RP 0x0103 GDT6557RP +/* GDT_MPR, RP series, narrow/ultra SCSI */ +product VORTEX GDT_6x11RP 0x0104 GDT6111RP/GDT6511RP +product VORTEX GDT_6x21RP 0x0105 GDT6121RP/GDT6521RP +/* GDT_MPR, RD series, wide/ultra SCSI */ +product VORTEX GDT_6x17RD 0x0110 GDT6117RD/GDT6517RD +product VORTEX GDT_6x27RD 0x0111 GDT6127RD/GDT6527RD +product VORTEX GDT_6537RD 0x0112 GDT6537RD +product VORTEX GDT_6557RD 0x0113 GDT6557RD +/* GDT_MPR, RD series, narrow/ultra SCSI */ +product VORTEX GDT_6x11RD 0x0114 GDT6111RD/GDT6511RD +product VORTEX GDT_6x21RD 0x0115 GDT6121RD/GDT6521RD +/* GDT_MPR, RD series, wide/ultra2 SCSI */ +product VORTEX GDT_6x18RD 0x0118 GDT6118RD/GDT6518RD/GDT6618RD +product VORTEX GDT_6x28RD 0x0119 GDT6128RD/GDT6528RD/GDT6628RD +product VORTEX GDT_6x38RD 0x011A GDT6538RD/GDT6638RD +product VORTEX GDT_6x58RD 0x011B GDT6558RD/GDT6658RD +/* GDT_MPR, RN series (64-bit PCI), wide/ultra2 SCSI */ +product VORTEX GDT_7x18RN 0x0168 GDT7118RN/GDT7518RN/GDT7618RN +product VORTEX GDT_7x28RN 0x0169 GDT7128RN/GDT7528RN/GDT7628RN +product VORTEX GDT_7x38RN 0x016A GDT7538RN/GDT7638RN +product VORTEX GDT_7x58RN 0x016B GDT7558RN/GDT7658RN +/* GDT_MPR, RD series, Fibre Channel */ +product VORTEX GDT_6x19RD 0x0210 GDT6519RD/GDT6619RD +product VORTEX GDT_6x29RD 0x0211 GDT6529RD/GDT6629RD +/* GDT_MPR, RN series (64-bit PCI), Fibre Channel */ +product VORTEX GDT_7x19RN 0x0260 GDT7519RN/GDT7619RN +product VORTEX GDT_7x29RN 0x0261 GDT7529RN/GDT7629RN + +/* VLSI products */ +product VLSI 82C592 0x0005 82C592 CPU Bridge +product VLSI 82C593 0x0006 82C593 ISA Bridge +product VLSI 82C594 0x0007 82C594 Wildcat System Controller +product VLSI 82C596597 0x0008 82C596/597 Wildcat ISA Bridge +product VLSI 82C541 0x000c 82C541 +product VLSI 82C543 0x000d 82C543 +product VLSI 82C532 0x0101 82C532 +product VLSI 82C534 0x0102 82C534 +product VLSI 82C535 0x0104 82C535 +product VLSI 82C147 0x0105 82C147 +product VLSI 82C975 0x0200 82C975 +product VLSI 82C925 0x0280 82C925 + +/* Weitek products */ +product WEITEK P9000 0x9001 P9000 +product WEITEK P9100 0x9100 P9100 + +/* Western Digital products */ +product WD WD33C193A 0x0193 WD33C193A +product WD WD33C196A 0x0196 WD33C196A +product WD WD33C197A 0x0197 WD33C197A +product WD WD7193 0x3193 WD7193 +product WD WD7197 0x3197 WD7197 +product WD WD33C296A 0x3296 WD33C296A +product WD WD34C296 0x4296 WD34C296 +product WD 90C 0xC24A 90C + +/* Winbond Electronics products */ +product WINBOND W83769F 0x0001 W83769F +product WINBOND W89C840F 0x0840 W89C840F 10/100 Ethernet +product WINBOND W89C940F 0x0940 W89C940F Ethernet +product WINBOND W89C940F_1 0x5a5a W89C940F Ethernet + +/* Xircom products */ +/* is the `-3' here just indicating revision 3, or is it really part + of the device name? */ +product XIRCOM X3201_3 0x0002 X3201-3 Fast Ethernet Controller +/* this is the device id `indicating 21143 driver compatibility' */ +product XIRCOM X3201_3_21143 0x0003 X3201-3 Fast Ethernet Controller (21143) + +/* Yamaha products */ +product YAMAHA YMF724 0x0004 724 Audio +product YAMAHA YMF740 0x000A 740 Audio +product YAMAHA YMF740C 0x000C 740C (DS-1) Audio +product YAMAHA YMF724F 0x000D 724F (DS-1) Audio +product YAMAHA YMF744B 0x0010 744 (DS-1S) Audio +product YAMAHA YMF754 0x0012 754 (DS-1E) Audio + +/* Zeinet products */ +product ZEINET 1221 0x0001 1221 + +/* Ziatech products */ +product ZIATECH ZT8905 0x8905 PCI-ST32 Bridge + +/* Zoran products */ +product ZORAN ZR36120 0x6120 Video Controller diff --git a/cfe/cfe/pci/pcidevs.h b/cfe/cfe/pci/pcidevs.h new file mode 100644 index 0000000..214ef45 --- /dev/null +++ b/cfe/cfe/pci/pcidevs.h @@ -0,0 +1,1360 @@ +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * generated from: + * pcidevs 2002/09/03 broadcom + */ + +/* + * Copyright (c) 1995, 1996 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * NOTE: a fairly complete list of PCI codes can be found at: + * + * http://members.hyperlink.net.au/~chart/pci.htm + * + * which replaces the database found at + * + * http://www.yourvote.com/pci/ + * + * (but it doesn't always seem to match vendor documentation) + */ + +/* + * List of known PCI vendors. This list has been trimmed to include + * only vendors with products appearing in the lists below. + */ + +#define PCI_VENDOR_COMPAQ 0x0e11 /* Compaq */ +#define PCI_VENDOR_SYMBIOS 0x1000 /* Symbios Logic */ +#define PCI_VENDOR_ATI 0x1002 /* ATI Technologies */ +#define PCI_VENDOR_ULSI 0x1003 /* ULSI Systems */ +#define PCI_VENDOR_VLSI 0x1004 /* VLSI Technology */ +#define PCI_VENDOR_AVANCE 0x1005 /* Avance Logic */ +#define PCI_VENDOR_NS 0x100b /* National Semiconductor */ +#define PCI_VENDOR_TSENG 0x100c /* Tseng Labs */ +#define PCI_VENDOR_WEITEK 0x100e /* Weitek */ +#define PCI_VENDOR_DEC 0x1011 /* Digital Equipment */ +#define PCI_VENDOR_CIRRUS 0x1013 /* Cirrus Logic */ +#define PCI_VENDOR_IBM 0x1014 /* IBM */ +#define PCI_VENDOR_WD 0x101c /* Western Digital */ +#define PCI_VENDOR_AMD 0x1022 /* Advanced Micro Devices */ +#define PCI_VENDOR_TRIDENT 0x1023 /* Trident Microsystems */ +#define PCI_VENDOR_ACER 0x1025 /* Acer */ +#define PCI_VENDOR_MATROX 0x102b /* Matrox */ +#define PCI_VENDOR_CHIPS 0x102c /* Chips and Technologies */ +#define PCI_VENDOR_TOSHIBA 0x102f /* Toshiba America */ +#define PCI_VENDOR_NEC 0x1033 /* NEC */ +#define PCI_VENDOR_FUTUREDOMAIN 0x1036 /* Future Domain */ +#define PCI_VENDOR_SIS 0x1039 /* Silicon Integrated System */ +#define PCI_VENDOR_HP 0x103c /* Hewlett-Packard */ +#define PCI_VENDOR_PCTECH 0x1042 /* PC Technology */ +#define PCI_VENDOR_DPT 0x1044 /* Distributed Processing Technology */ +#define PCI_VENDOR_OPTI 0x1045 /* Opti */ +#define PCI_VENDOR_ELSA 0x1048 /* Elsa */ +#define PCI_VENDOR_SGSTHOMSON 0x104a /* SGS Thomson Microelectric */ +#define PCI_VENDOR_BUSLOGIC 0x104b /* BusLogic */ +#define PCI_VENDOR_TI 0x104c /* Texas Instruments */ +#define PCI_VENDOR_SONY 0x104d /* Sony */ +#define PCI_VENDOR_OAKTECH 0x104e /* Oak Technology */ +#define PCI_VENDOR_WINBOND 0x1050 /* Winbond Electronics */ +#define PCI_VENDOR_MOT 0x1057 /* Motorola */ +#define PCI_VENDOR_PROMISE 0x105a /* Promise Technology */ +#define PCI_VENDOR_NUMBER9 0x105d /* Number 9 Computer Company */ +#define PCI_VENDOR_UMC 0x1060 /* United Microelectronics */ +#define PCI_VENDOR_ITT 0x1061 /* I. T. T. */ +#define PCI_VENDOR_MYLEX 0x1069 /* Mylex */ +#define PCI_VENDOR_APPLE 0x106b /* Apple Computer */ +#define PCI_VENDOR_YAMAHA 0x1073 /* Yamaha */ +#define PCI_VENDOR_NEXGEN 0x1074 /* NexGen Microsystems */ +#define PCI_VENDOR_QLOGIC 0x1077 /* Q Logic */ +#define PCI_VENDOR_LEADTEK 0x107d /* LeadTek Research */ +#define PCI_VENDOR_CONTAQ 0x1080 /* Contaq Microsystems */ +#define PCI_VENDOR_BIT3 0x108a /* Bit3 Computer Corp. */ +#define PCI_VENDOR_OLICOM 0x108d /* Olicom */ +#define PCI_VENDOR_SUN 0x108e /* Sun Microsystems */ +#define PCI_VENDOR_INTERGRAPH 0x1091 /* Intergraph */ +#define PCI_VENDOR_DIAMOND 0x1092 /* Diamond Computer Systems */ +#define PCI_VENDOR_CMDTECH 0x1095 /* CMD Technology */ +#define PCI_VENDOR_QUANTUMDESIGNS 0x1098 /* Quantum Designs */ +#define PCI_VENDOR_BROOKTREE 0x109e /* Brooktree */ +#define PCI_VENDOR_SGI 0x10a9 /* Silicon Graphics */ +#define PCI_VENDOR_ACC 0x10aa /* ACC Microelectronics */ +#define PCI_VENDOR_SYMPHONY 0x10ad /* Symphony Labs */ +#define PCI_VENDOR_PLX 0x10b5 /* PLX Technology */ +#define PCI_VENDOR_MADGE 0x10b6 /* Madge Networks */ +#define PCI_VENDOR_3COM 0x10B7 /* 3Com */ +#define PCI_VENDOR_SMC 0x10b8 /* Standard Microsystems */ +#define PCI_VENDOR_ALI 0x10b9 /* Acer Labs */ +#define PCI_VENDOR_SURECOM 0x10bd /* Surecom Technology */ +#define PCI_VENDOR_SAMSUNGSEMI 0x10c3 /* Samsung Semiconductors */ +#define PCI_VENDOR_NEOMAGIC 0x10c8 /* Neomagic */ +#define PCI_VENDOR_ADVSYS 0x10cd /* Advanced System Products */ +#define PCI_VENDOR_MACRONIX 0x10d9 /* Macronix */ +#define PCI_VENDOR_ES 0x10dd /* Evans & Sutherland */ +#define PCI_VENDOR_NVIDIA 0x10de /* Nvidia Corporation */ +#define PCI_VENDOR_EMULEX 0x10df /* Emulex */ +#define PCI_VENDOR_IMS 0x10e0 /* Integrated Micro Solutions */ +#define PCI_VENDOR_TEKRAM 0x10e1 /* Tekram Technology (1st PCI Vendor ID) */ +#define PCI_VENDOR_NEWBRIDGE 0x10e3 /* Newbridge Microsystems / Tundra Semiconductor */ +#define PCI_VENDOR_AMCIRCUITS 0x10e8 /* Applied Micro Circuits */ +#define PCI_VENDOR_REALTEK 0x10ec /* Realtek Semiconductor */ +#define PCI_VENDOR_NKK 0x10f5 /* NKK Corporation */ +#define PCI_VENDOR_INITIO 0x1101 /* Initio */ +#define PCI_VENDOR_CREATIVELABS 0x1102 /* Creative Labs */ +#define PCI_VENDOR_TRIONES 0x1103 /* Triones Technologies */ +#define PCI_VENDOR_SIGMA 0x1105 /* Sigma Designs */ +#define PCI_VENDOR_VIATECH 0x1106 /* VIA Technologies */ +#define PCI_VENDOR_COGENT 0x1109 /* Cogent Data Technologies */ +#define PCI_VENDOR_RNS 0x1112 /* RNS */ +#define PCI_VENDOR_ACCTON 0x1113 /* Accton Technology */ +#define PCI_VENDOR_VORTEX 0x1119 /* Vortex Computer Systems */ +#define PCI_VENDOR_EFFICIENTNETS 0x111a /* Efficent Networks */ +#define PCI_VENDOR_IDT 0x111d /* IDT */ +#define PCI_VENDOR_FORE 0x1127 /* FORE Systems */ +#define PCI_VENDOR_ZIATECH 0x1138 /* Ziatech */ +#define PCI_VENDOR_ALLIANCE 0x1142 /* Alliance Semiconductor */ +#define PCI_VENDOR_SCHNEIDERKOCH 0x1148 /* Schneider & Koch */ +#define PCI_VENDOR_MUTECH 0x1159 /* Mutech */ +#define PCI_VENDOR_XIRCOM 0x115d /* Xircom */ +#define PCI_VENDOR_ALTERA 0x1172 /* Altera Corporation */ +#define PCI_VENDOR_TOSHIBA2 0x1179 /* Toshiba America Info Systems */ +#define PCI_VENDOR_RICOH 0x1180 /* Ricoh */ +#define PCI_VENDOR_DLINK 0x1186 /* D-Link Systems */ +#define PCI_VENDOR_COROLLARY 0x118c /* Corrollary */ +#define PCI_VENDOR_ACARD 0x1191 /* Acard */ +#define PCI_VENDOR_ZEINET 0x1193 /* Zeinet */ +#define PCI_VENDOR_GALILEO 0x11ab /* Galileo Technology */ +#define PCI_VENDOR_LITEON 0x11ad /* Lite-On Communications */ +#define PCI_VENDOR_V3 0x11b0 /* V3 Semiconductor */ +#define PCI_VENDOR_LUCENT 0x11c1 /* AT&T Microelectronics */ +#define PCI_VENDOR_DOLPHIN 0x11c8 /* Dolphin Interconnect Solutions */ +#define PCI_VENDOR_AURAVISION 0x11d1 /* Auravision */ +#define PCI_VENDOR_ZORAN 0x11de /* Zoran Corporation */ +#define PCI_VENDOR_COMPEX 0x11f6 /* Compex */ +#define PCI_VENDOR_PMCSIERRA 0x11f8 /* PMC-Sierra */ +#define PCI_VENDOR_CYCLADES 0x120e /* Cyclades */ +#define PCI_VENDOR_ESSENTIAL 0x120f /* Essential Communications */ +#define PCI_VENDOR_O2MICRO 0x1217 /* O2 Micro Inc */ +#define PCI_VENDOR_3DFX 0x121a /* 3Dfx Interactive */ +#define PCI_VENDOR_CCUBE 0x123f /* C-Cube Microsystems */ +#define PCI_VENDOR_AVM 0x1244 /* AVM */ +#define PCI_VENDOR_LINEARSYS 0x1254 /* Linear Systems */ +#define PCI_VENDOR_ASIX 0x125b /* ASIX Electronics */ +#define PCI_VENDOR_ESSTECH 0x125d /* ESS Technology Inc */ +#define PCI_VENDOR_SILMOTION 0x126f /* Silicon Motion */ +#define PCI_VENDOR_ENSONIQ 0x1274 /* Ensoniq */ +#define PCI_VENDOR_DAVICOM 0x1282 /* Davicom Semiconductor */ +#define PCI_VENDOR_ESSTECH2 0x1285 /* ESS Technology Inc */ +#define PCI_VENDOR_TRITECH 0x1292 /* TriTech Microelectronics */ +#define PCI_VENDOR_ALTEON 0x12ae /* Alteon */ +#define PCI_VENDOR_RISCOM 0x12aa /* RISCom */ +#define PCI_VENDOR_USR 0x12b9 /* US Robotics (3Com) */ +#define PCI_VENDOR_NVIDIA_SGS 0x12d2 /* Nvidia Corporation & SGS Thomson Microelectric */ +#define PCI_VENDOR_AUREAL 0x12eb /* Aureal Semiconductor */ +#define PCI_VENDOR_ADMTEK 0x1317 /* ADMtek */ +#define PCI_VENDOR_FORTEMEDIA 0x1319 /* Forte Media */ +#define PCI_VENDOR_DOMEX 0x134a /* Domex */ +#define PCI_VENDOR_LMC 0x1376 /* LAN Media Corporation */ +#define PCI_VENDOR_API 0x14d9 /* API Networks */ +#define PCI_VENDOR_CONEXANT 0x14f1 /* Conexant Systems */ +#define PCI_VENDOR_NETGEAR 0x1385 /* Netgear */ +#define PCI_VENDOR_3WARE 0x13c1 /* 3ware */ +#define PCI_VENDOR_SUNDANCETI 0x13f0 /* Sundance Technology */ +#define PCI_VENDOR_CMEDIA 0x13f6 /* C-Media Electronics Inc */ +#define PCI_VENDOR_DELTA 0x1500 /* Delta Electronics */ +#define PCI_VENDOR_SOLIDUM 0x1588 /* Solidum Systems Corp. */ +#define PCI_VENDOR_SIBYTE 0x166d /* SiByte, Inc. */ +#define PCI_VENDOR_SYMPHONY2 0x1c1c /* Symphony Labs (2nd PCI Vendor ID) */ +#define PCI_VENDOR_TEKRAM2 0x1de1 /* Tekram Technology (2nd PCI Vendor ID) */ +#define PCI_VENDOR_BROADCOM 0x14e4 /* Broadcom */ +#define PCI_VENDOR_3DLABS 0x3d3d /* 3D Labs */ +#define PCI_VENDOR_AVANCE2 0x4005 /* Avance Logic (2nd PCI Vendor ID) */ +#define PCI_VENDOR_ADDTRON 0x4033 /* Addtron Technology */ +#define PCI_VENDOR_NETVIN 0x4a14 /* NetVin */ +#define PCI_VENDOR_S3 0x5333 /* S3 */ +#define PCI_VENDOR_C4T 0x6374 /* c't Magazin */ +#define PCI_VENDOR_INTEL 0x8086 /* Intel */ +#define PCI_VENDOR_PROLAN 0x8c4a /* ProLAN */ +#define PCI_VENDOR_KTI 0x8e2e /* KTI */ +#define PCI_VENDOR_ADP 0x9004 /* Adaptec */ +#define PCI_VENDOR_ADP2 0x9005 /* Adaptec (2nd PCI Vendor ID) */ +#define PCI_VENDOR_ATRONICS 0x907f /* Atronics */ +#define PCI_VENDOR_ARC 0xedd8 /* ARC Logic */ +#define PCI_VENDOR_EPIGRAM 0xfeda /* Epigram */ +#define PCI_VENDOR_INVALID 0xffff /* INVALID VENDOR ID */ + +/* + * List of known products. Grouped by vendor. + */ + +/* 3COM Products */ +#define PCI_PRODUCT_3COM_3C985 0x0001 /* 3c985 Gigabit Ethernet */ +#define PCI_PRODUCT_3COM_3C590 0x5900 /* 3c590 Ethernet */ +#define PCI_PRODUCT_3COM_3C595TX 0x5950 /* 3c595-TX 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C595T4 0x5951 /* 3c595-T4 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C595MII 0x5952 /* 3c595-MII 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C900TPO 0x9000 /* 3c900-TPO Ethernet */ +#define PCI_PRODUCT_3COM_3C900COMBO 0x9001 /* 3c900-COMBO Ethernet */ +#define PCI_PRODUCT_3COM_3C905TX 0x9050 /* 3c905-TX 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C905T4 0x9051 /* 3c905-T4 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C900BTPO 0x9004 /* 3c900B-TPO Ethernet */ +#define PCI_PRODUCT_3COM_3C900BCOMBO 0x9005 /* 3c900B-COMBO Ethernet */ +#define PCI_PRODUCT_3COM_3C900BTPC 0x9006 /* 3c900B-TPC Ethernet */ +#define PCI_PRODUCT_3COM_3C905BTX 0x9055 /* 3c905B-TX 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C905BT4 0x9056 /* 3c905B-T4 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C905BCOMBO 0x9058 /* 3c905B-COMBO 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C905BFX 0x905a /* 3c905B-FX 100 Ethernet */ +#define PCI_PRODUCT_3COM_3C905CTX 0x9200 /* 3c905C-TX 10/100 Ethernet with mngmt */ +#define PCI_PRODUCT_3COM_3C980SRV 0x9800 /* 3c980 Server Adapter 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3C980CTXM 0x9805 /* 3c980C-TXM 10/100 Ethernet */ +#define PCI_PRODUCT_3COM_3CR990TX97 0x9903 /* 3CR990-TX-97 10/100 Ethernet */ + +/* 3Dfx Interactive producs */ +#define PCI_PRODUCT_3DFX_VOODOO 0x0001 /* Voodoo */ +#define PCI_PRODUCT_3DFX_VOODOO2 0x0002 /* Voodoo2 */ +#define PCI_PRODUCT_3DFX_BANSHEE 0x0003 /* Banshee */ +#define PCI_PRODUCT_3DFX_VOODOO3 0x0005 /* Voodoo3 */ + +/* 3D Labs products */ +#define PCI_PRODUCT_3DLABS_300SX 0x0001 /* GLINT 300SX */ +#define PCI_PRODUCT_3DLABS_500TX 0x0002 /* GLINT 500TX */ +#define PCI_PRODUCT_3DLABS_DELTA 0x0003 /* GLINT DELTA */ +#define PCI_PRODUCT_3DLABS_PERMEDIA 0x0004 /* GLINT Permedia */ +#define PCI_PRODUCT_3DLABS_500MX 0x0006 /* GLINT 500MX */ +#define PCI_PRODUCT_3DLABS_PERMEDI2 0x0007 /* GLINT Permedia 2 */ + +/* 3ware products */ +#define PCI_PRODUCT_3WARE_ESCALADE 0x1000 /* Escalade IDE RAID */ + +/* ACC Products */ +#define PCI_PRODUCT_ACC_2188 0x0000 /* ACCM 2188 VL-PCI Bridge */ +#define PCI_PRODUCT_ACC_2051_HB 0x2051 /* 2051 PCI Single Chip Solution (host bridge) */ +#define PCI_PRODUCT_ACC_2051_ISA 0x5842 /* 2051 PCI Single Chip Solution (ISA bridge) */ + +/* Acard products */ +#define PCI_PRODUCT_ACARD_AEC6710 0x8002 /* AEC6710 SCSI */ +#define PCI_PRODUCT_ACARD_AEC6712UW 0x8010 /* AEC6712UW SCSI */ +#define PCI_PRODUCT_ACARD_AEC6712U 0x8020 /* AEC6712U SCSI */ +#define PCI_PRODUCT_ACARD_AEC6712S 0x8030 /* AEC6712S SCSI */ +#define PCI_PRODUCT_ACARD_AEC6710D 0x8040 /* AEC6710D SCSI */ +#define PCI_PRODUCT_ACARD_AEC6715UW 0x8050 /* AEC6715UW SCSI */ + +/* Accton products */ +#define PCI_PRODUCT_ACCTON_MPX5030 0x1211 /* MPX 5030/5038 Ethernet */ + +/* Acer products */ +#define PCI_PRODUCT_ACER_M1435 0x1435 /* M1435 VL-PCI Bridge */ + +/* Acer Labs products */ +#define PCI_PRODUCT_ALI_M1445 0x1445 /* M1445 VL-PCI Bridge */ +#define PCI_PRODUCT_ALI_M1449 0x1449 /* M1449 PCI-ISA Bridge */ +#define PCI_PRODUCT_ALI_M1451 0x1451 /* M1451 Host-PCI Bridge */ +#define PCI_PRODUCT_ALI_M1461 0x1461 /* M1461 Host-PCI Bridge */ +#define PCI_PRODUCT_ALI_M1531 0x1531 /* M1531 Host-PCI Bridge */ +#define PCI_PRODUCT_ALI_M1541 0x1541 /* M1541 Host-PCI Bridge */ +#define PCI_PRODUCT_ALI_M1543 0x1533 /* M1543 PCI-ISA Bridge */ +#define PCI_PRODUCT_ALI_M3309 0x3309 /* M3309 MPEG Decoder */ +#define PCI_PRODUCT_ALI_M4803 0x5215 /* M4803 */ +#define PCI_PRODUCT_ALI_M5229 0x5229 /* M5229 UDMA IDE Controller */ +#define PCI_PRODUCT_ALI_M5237 0x5237 /* M5237 USB Host Controller */ +#define PCI_PRODUCT_ALI_M7101 0x7101 /* M7101 Power Management Controller */ + +/* Adaptec products */ +#define PCI_PRODUCT_ADP_AIC7850 0x5078 /* AIC-7850 */ +#define PCI_PRODUCT_ADP_AIC7855 0x5578 /* AIC-7855 */ +#define PCI_PRODUCT_ADP_AIC5900 0x5900 /* AIC-5900 ATM */ +#define PCI_PRODUCT_ADP_AIC5905 0x5905 /* AIC-5905 ATM */ +#define PCI_PRODUCT_ADP_AIC6915 0x6915 /* AIC-6915 10/100 Ethernet */ +#define PCI_PRODUCT_ADP_AIC7860 0x6078 /* AIC-7860 */ +#define PCI_PRODUCT_ADP_APA1480 0x6075 /* APA-1480 Ultra */ +#define PCI_PRODUCT_ADP_2940AU 0x6178 /* AHA-2940A Ultra */ +#define PCI_PRODUCT_ADP_AIC7870 0x7078 /* AIC-7870 */ +#define PCI_PRODUCT_ADP_2940 0x7178 /* AHA-2940 */ +#define PCI_PRODUCT_ADP_3940 0x7278 /* AHA-3940 */ +#define PCI_PRODUCT_ADP_3985 0x7378 /* AHA-3985 */ +#define PCI_PRODUCT_ADP_2944 0x7478 /* AHA-2944 */ +#define PCI_PRODUCT_ADP_AIC7895 0x7895 /* AIC-7895 Ultra */ +#define PCI_PRODUCT_ADP_AIC7880 0x8078 /* AIC-7880 Ultra */ +#define PCI_PRODUCT_ADP_2940U 0x8178 /* AHA-2940 Ultra */ +#define PCI_PRODUCT_ADP_3940U 0x8278 /* AHA-3940 Ultra */ +#define PCI_PRODUCT_ADP_389XU 0x8378 /* AHA-389X Ultra */ +#define PCI_PRODUCT_ADP_2944U 0x8478 /* AHA-2944 Ultra */ +#define PCI_PRODUCT_ADP_2940UP 0x8778 /* AHA-2940 Ultra Pro */ + +#define PCI_PRODUCT_ADP2_2940U2 0x0010 /* AHA-2940 Ultra2 */ +#define PCI_PRODUCT_ADP2_2930U2 0x0011 /* AHA-2930 Ultra2 */ +#define PCI_PRODUCT_ADP2_AIC7890 0x001f /* AIC-7890/1 */ +#define PCI_PRODUCT_ADP2_3950U2B 0x0050 /* AHA-3950 Ultra2 */ +#define PCI_PRODUCT_ADP2_3950U2D 0x0051 /* AHA-3950 Ultra2 */ +#define PCI_PRODUCT_ADP2_AIC7896 0x005f /* AIC-7896/7 */ + +/* Addtron Products */ +#define PCI_PRODUCT_ADDTRON_8139 0x1360 /* 8139 Ethernet */ + +/* ADMtek products */ +#define PCI_PRODUCT_ADMTEK_AL981 0x0981 /* ADMtek AL981 10/100 Ethernet */ + +/* Advanced System Products */ +#define PCI_PRODUCT_ADVSYS_1200A 0x1100 +#define PCI_PRODUCT_ADVSYS_1200B 0x1200 +#define PCI_PRODUCT_ADVSYS_ULTRA 0x1300 /* ABP-930/40UA */ +#define PCI_PRODUCT_ADVSYS_WIDE 0x2300 /* ABP-940UW */ +#define PCI_PRODUCT_ADVSYS_U2W 0x2500 /* ASB-3940U2W */ +#define PCI_PRODUCT_ADVSYS_U3W 0x2700 /* ASB-3940U3W */ + +/* Alliance products */ +#define PCI_PRODUCT_ALLIANCE_AT24 0x6424 /* AT24 */ +#define PCI_PRODUCT_ALLIANCE_AT25 0x643d /* AT25 */ + +/* Alteon products */ +#define PCI_PRODUCT_ALTEON_ACENIC 0x0001 /* ACEnic Gigabit Ethernet */ + +/* AMD products */ +#define PCI_PRODUCT_AMD_PCNET_PCI 0x2000 /* 79c970 PCnet-PCI LANCE Ethernet */ +#define PCI_PRODUCT_AMD_PCNET_HOME 0x2001 /* 79c978 PCnet-PCI Home */ +#define PCI_PRODUCT_AMD_PCSCSI_PCI 0x2020 /* 53c974 PCscsi-PCI SCSI */ +#define PCI_PRODUCT_AMD_PCNETS_PCI 0x2040 /* 79C974 PCnet-PCI Ethernet & SCSI */ +#define PCI_PRODUCT_AMD_SC751_SC 0x7006 /* AMD751 System Controller */ +#define PCI_PRODUCT_AMD_SC751_PPB 0x7007 /* AMD751 PCI-to-PCI Bridge */ +#define PCI_PRODUCT_AMD_PBC756_ISA 0x7408 /* AMD756 PCI-to-ISA Bridge */ +#define PCI_PRODUCT_AMD_PBC756_IDE 0x7409 /* AMD756 IDE controller */ +#define PCI_PRODUCT_AMD_PBC756_PMC 0x740B /* AMD756 Power Management Controller */ +#define PCI_PRODUCT_AMD_PBC756_USB 0x740C /* AMD756 USB Host Controller */ +#define PCI_PRODUCT_AMD_HT7520 0x7450 /* (PLX) HT7520 PCIX Tunnel */ +#define PCI_PRODUCT_AMD_HT7520_PIC 0x7451 /* (PLX) HT7520 PCIX IOAPIC */ +#define PCI_PRODUCT_AMD_AMD8151_AGP 0x7454 /* AMD8151 AGP Device */ +#define PCI_PRODUCT_AMD_AMD8151 0x7455 /* AMD8151 HyperTransport-AGP Bridge */ + +/* API Networks products */ +#define PCI_PRODUCT_API_STURGEON 0x0010 /* AP1011 HyperTransport-PCI Bridge */ + +/* Apple products */ +#define PCI_PRODUCT_APPLE_BANDIT 0x0001 /* Bandit Host-PCI Bridge */ +#define PCI_PRODUCT_APPLE_GC 0x0002 /* Grand Central I/O Controller */ +#define PCI_PRODUCT_APPLE_CONTROL 0x0003 /* Control */ +#define PCI_PRODUCT_APPLE_PLANB 0x0004 /* PlanB */ +#define PCI_PRODUCT_APPLE_OHARE 0x0007 /* OHare I/O Controller */ +#define PCI_PRODUCT_APPLE_BANDIT2 0x0008 /* Bandit Host-PCI Bridge */ +#define PCI_PRODUCT_APPLE_HEATHROW 0x0010 /* MAC-IO I/O Controller (Heathrow) */ +#define PCI_PRODUCT_APPLE_PADDINGTON 0x0017 /* MAC-IO I/O Controller (Paddington) */ +#define PCI_PRODUCT_APPLE_KEYLARGO_USB 0x0019 /* KeyLargo USB Controller */ +#define PCI_PRODUCT_APPLE_UNINORTH1 0x001e /* UniNorth Host-PCI Bridge */ +#define PCI_PRODUCT_APPLE_UNINORTH2 0x001f /* UniNorth Host-PCI Bridge */ +#define PCI_PRODUCT_APPLE_UNINORTH_AGP 0x0020 /* UniNorth AGP Interface */ +#define PCI_PRODUCT_APPLE_GMAC 0x0021 /* GMAC Ethernet */ +#define PCI_PRODUCT_APPLE_KEYLARGO 0x0022 /* MAC-IO I/O Controller (KeyLargo) */ + +/* ARC Logic products */ +#define PCI_PRODUCT_ARC_1000PV 0xa091 /* 1000PV */ +#define PCI_PRODUCT_ARC_2000PV 0xa099 /* 2000PV */ +#define PCI_PRODUCT_ARC_2000MT 0xa0a1 /* 2000MT */ + +/* ASIX Electronics products */ +#define PCI_PRODUCT_ASIX_AX88140A 0x1400 /* AX88140A 10/100 Ethernet */ + +/* ATI products */ +#define PCI_PRODUCT_ATI_MACH32 0x4158 /* Mach32 */ +#define PCI_PRODUCT_ATI_MACH64_CT 0x4354 /* Mach64 CT */ +#define PCI_PRODUCT_ATI_MACH64_CX 0x4358 /* Mach64 CX */ +#define PCI_PRODUCT_ATI_MACH64_ET 0x4554 /* Mach64 ET */ +#define PCI_PRODUCT_ATI_MACH64_VT 0x4654 /* Mach64 VT */ +#define PCI_PRODUCT_ATI_MACH64_B 0x4750 /* Mach64 B */ +#define PCI_PRODUCT_ATI_MACH64_GB 0x4742 /* Mach64 GB */ +#define PCI_PRODUCT_ATI_MACH64_GD 0x4744 /* Mach64 GD */ +#define PCI_PRODUCT_ATI_MACH64_GI 0x4749 /* Mach64 GI */ +#define PCI_PRODUCT_ATI_MACH64_GP 0x4750 /* Mach64 GP */ +#define PCI_PRODUCT_ATI_MACH64_GQ 0x4751 /* Mach64 GQ */ +#define PCI_PRODUCT_ATI_MACH64_GT 0x4754 /* Mach64 GT */ +#define PCI_PRODUCT_ATI_MACH64_GU 0x4755 /* Mach64 GU */ +#define PCI_PRODUCT_ATI_MACH64_GV 0x4756 /* Mach64 GV */ +#define PCI_PRODUCT_ATI_MACH64_GW 0x4757 /* Mach64 GW */ +#define PCI_PRODUCT_ATI_MACH64_GX 0x4758 /* Mach64 GX */ +#define PCI_PRODUCT_ATI_MACH64_GZ 0x475a /* Mach64 GZ */ +#define PCI_PRODUCT_ATI_MACH64_LB 0x4c42 /* Mach64 LB */ +#define PCI_PRODUCT_ATI_MACH64_LD 0x4c44 /* Mach64 LD */ +#define PCI_PRODUCT_ATI_MACH64_LG 0x4c47 /* Mach64 LG */ +#define PCI_PRODUCT_ATI_MACH64_LI 0x4c49 /* Mach64 LI */ +#define PCI_PRODUCT_ATI_MACH64_LM 0x4c4d /* Mach64 LM */ +#define PCI_PRODUCT_ATI_MACH64_LP 0x4c50 /* Mach64 LP */ +#define PCI_PRODUCT_ATI_MACH64_LR 0x4c52 /* Mach64 LR */ + +/* Auravision products */ +#define PCI_PRODUCT_AURAVISION_VXP524 0x01f7 /* VxP524 PCI Video Processor */ + +/* Aureal Semiconductor */ +#define PCI_PRODUCT_AUREAL_AU8820 0x0001 /* AU8820 Vortex Digital Audio Processor */ + +/* Applied Micro Circuts products */ +#define PCI_PRODUCT_AMCIRCUITS_S5933 0x4750 /* S5933 PCI Matchmaker */ +#define PCI_PRODUCT_AMCIRCUITS_LANAI 0x8043 /* Myrinet LANai Interface */ +#define PCI_PRODUCT_AMCIRCUITS_S5920 0x5920 /* S5920 PCI Target */ + +/* Atronics products */ +#define PCI_PRODUCT_ATRONICS_IDE_2015PL 0x2015 /* IDE-2015PL */ + +/* Avance Logic products */ +#define PCI_PRODUCT_AVANCE_AVL2301 0x2301 /* AVL2301 */ +#define PCI_PRODUCT_AVANCE_AVG2302 0x2302 /* AVG2302 */ +#define PCI_PRODUCT_AVANCE2_ALG2301 0x2301 /* ALG2301 */ +#define PCI_PRODUCT_AVANCE2_ALG2302 0x2302 /* ALG2302 */ + +/* CCUBE products */ +#define PCI_PRODUCT_CCUBE_CINEMASTER 0x8888 /* Cinemaster C 3.0 DVD Decoder */ + +/* AVM products */ +#define PCI_PRODUCT_AVM_FRITZ_CARD 0x0a00 /* Fritz! Card ISDN Interface */ + +/* Bit3 products */ +#define PCI_PRODUCT_BIT3_PCIVME617 0x0001 /* PCI-VME Interface Mod. 617 */ +#define PCI_PRODUCT_BIT3_PCIVME618 0x0010 /* PCI-VME Interface Mod. 618 */ +#define PCI_PRODUCT_BIT3_PCIVME2706 0x0300 /* PCI-VME Interface Mod. 2706 */ + +/* Broadcom products */ +#define PCI_PRODUCT_BROADCOM_BCM4211 0x4211 /* BCM4211 iLine10 Controller */ +#define PCI_PRODUCT_BROADCOM_BCM4212 0x4212 /* BCM4212 V.90 Modem */ +#define PCI_PRODUCT_BROADCOM_BCM5700 0x1644 /* BCM5700 10/100/1000 Ethernet */ +#define PCI_PRODUCT_BROADCOM_BCM5701 0x1645 /* BCM5701 10/100/1000 Ethernet */ +#define PCI_PRODUCT_BROADCOM_BCM5702 0x16a6 /* BCM5702 10/100/1000 Ethernet */ +#define PCI_PRODUCT_BROADCOM_BCM5703 0x16a7 /* BCM5703 10/100/1000 Ethernet */ +#define PCI_PRODUCT_BROADCOM_BCM5705 0x1653 /* BCM5705 10/100/1000 Ethernet */ +#define PCI_PRODUCT_BROADCOM_BCM5820 0x5820 /* BCM5820 eCommerce Processor */ +#define PCI_PRODUCT_BROADCOM_BCM5821 0x5821 /* BCM5821 Super-eCommerce Processor */ +#define PCI_PRODUCT_BROADCOM_BCM5850 0x5850 /* BCM5850 SSL/TLS Protocol Processor */ + +/* Brooktree products */ +#define PCI_PRODUCT_BROOKTREE_BT848 0x0350 /* Bt848 Video Capture */ +#define PCI_PRODUCT_BROOKTREE_BT849 0x0351 /* Bt849 Video Capture */ +#define PCI_PRODUCT_BROOKTREE_BT878 0x036e /* Bt878 Video Capture */ +#define PCI_PRODUCT_BROOKTREE_BT879 0x036f /* Bt879 Video Capture */ + +/* BusLogic products */ +#define PCI_PRODUCT_BUSLOGIC_MULTIMASTER_NC 0x0140 /* MultiMaster NC */ +#define PCI_PRODUCT_BUSLOGIC_MULTIMASTER 0x1040 /* MultiMaster */ +#define PCI_PRODUCT_BUSLOGIC_FLASHPOINT 0x8130 /* FlashPoint */ + +/* c't Magazin products */ +#define PCI_PRODUCT_C4T_GPPCI 0x6773 /* GPPCI */ + +/* Chips and Technologies products */ +#define PCI_PRODUCT_CHIPS_64310 0x00b8 /* 64310 */ +#define PCI_PRODUCT_CHIPS_65545 0x00d8 /* 65545 */ +#define PCI_PRODUCT_CHIPS_65548 0x00dc /* 65548 */ +#define PCI_PRODUCT_CHIPS_65550 0x00e0 /* 65550 */ +#define PCI_PRODUCT_CHIPS_65554 0x00e4 /* 65554 */ + +/* Cirrus Logic products */ +#define PCI_PRODUCT_CIRRUS_CL_GD7548 0x0038 /* CL-GD7548 */ +#define PCI_PRODUCT_CIRRUS_CL_GD5430 0x00a0 /* CL-GD5430 */ +#define PCI_PRODUCT_CIRRUS_CL_GD5434_4 0x00a4 /* CL-GD5434-4 */ +#define PCI_PRODUCT_CIRRUS_CL_GD5434_8 0x00a8 /* CL-GD5434-8 */ +#define PCI_PRODUCT_CIRRUS_CL_GD5436 0x00ac /* CL-GD5436 */ +#define PCI_PRODUCT_CIRRUS_CL_GD5446 0x00b8 /* CL-GD5446 */ +#define PCI_PRODUCT_CIRRUS_CL_GD5480 0x00bc /* CL-GD5480 */ +#define PCI_PRODUCT_CIRRUS_CL_PD6729 0x1100 /* CL-PD6729 */ +#define PCI_PRODUCT_CIRRUS_CL_PD6832 0x1110 /* CL-PD6832 PCI-CardBus Bridge */ +#define PCI_PRODUCT_CIRRUS_CL_PD6833 0x1113 /* CL-PD6833 PCI-CardBus Bridge */ +#define PCI_PRODUCT_CIRRUS_CL_GD7542 0x1200 /* CL-GD7542 */ +#define PCI_PRODUCT_CIRRUS_CL_GD7543 0x1202 /* CL-GD7543 */ +#define PCI_PRODUCT_CIRRUS_CL_GD7541 0x1204 /* CL-GD7541 */ +#define PCI_PRODUCT_CIRRUS_CL_CD4400 0x4400 /* CL-CD4400 Communications Controller */ +#define PCI_PRODUCT_CIRRUS_CS4610 0x6001 /* CS4610 SoundFusion Audio Accelerator */ +#define PCI_PRODUCT_CIRRUS_CS4280 0x6003 /* CS4280 CrystalClear Audio Interface */ + +/* CMD Technology products -- info gleaned from their web site */ +#define PCI_PRODUCT_CMDTECH_640 0x0640 /* PCI0640 */ +/* No data on the CMD Tech. web site for the following as of Mar. 3 '98 */ +#define PCI_PRODUCT_CMDTECH_642 0x0642 /* PCI0642 */ +/* datasheets available from www.cmd.com for the followings */ +#define PCI_PRODUCT_CMDTECH_643 0x0643 /* PCI0643 */ +#define PCI_PRODUCT_CMDTECH_646 0x0646 /* PCI0646 */ +#define PCI_PRODUCT_CMDTECH_647 0x0647 /* PCI0647 */ +#define PCI_PRODUCT_CMDTECH_648 0x0648 /* PCI0648 */ +#define PCI_PRODUCT_CMDTECH_649 0x0649 /* PCI0649 */ + +/* Inclusion of 'A' in the following entry is probably wrong. */ +/* No data on the CMD Tech. web site for the following as of Mar. 3 '98 */ +#define PCI_PRODUCT_CMDTECH_650A 0x0650 /* PCI0650A */ +#define PCI_PRODUCT_CMDTECH_670 0x0670 /* USB0670 */ +#define PCI_PRODUCT_CMDTECH_673 0x0673 /* USB0673 */ + +/* C-Media products */ +#define PCI_PRODUCT_CMEDIA_CMI8338A 0x0100 /* CMI8338A PCI Audio Device */ +#define PCI_PRODUCT_CMEDIA_CMI8338B 0x0101 /* CMI8338B PCI Audio Device */ +#define PCI_PRODUCT_CMEDIA_CMI8738 0x0111 /* CMI8738/C3DX PCI Audio Device */ +#define PCI_PRODUCT_CMEDIA_HSP56 0x0211 /* HSP56 Audiomodem Riser */ + +/* Cogent Data Technologies products */ +#define PCI_PRODUCT_COGENT_EM110TX 0x1400 /* EX110TX PCI Fast Ethernet Adapter */ + +/* Compaq products */ +#define PCI_PRODUCT_COMPAQ_PCI_EISA_BRIDGE 0x0001 /* PCI-EISA Bridge */ +#define PCI_PRODUCT_COMPAQ_PCI_ISA_BRIDGE 0x0002 /* PCI-ISA Bridge */ +#define PCI_PRODUCT_COMPAQ_TRIFLEX1 0x1000 /* Triflex Host-PCI Bridge */ +#define PCI_PRODUCT_COMPAQ_TRIFLEX2 0x2000 /* Triflex Host-PCI Bridge */ +#define PCI_PRODUCT_COMPAQ_QVISION_V0 0x3032 /* QVision */ +#define PCI_PRODUCT_COMPAQ_QVISION_1280P 0x3033 /* QVision 1280/p */ +#define PCI_PRODUCT_COMPAQ_QVISION_V2 0x3034 /* QVision */ +#define PCI_PRODUCT_COMPAQ_TRIFLEX4 0x4000 /* Triflex Host-PCI Bridge */ +#define PCI_PRODUCT_COMPAQ_USB 0x7020 /* USB Controller */ +#define PCI_PRODUCT_COMPAQ_SMART2P 0xae10 /* SMART2P RAID */ +#define PCI_PRODUCT_COMPAQ_N100TX 0xae32 /* Netelligent 10/100 TX */ +#define PCI_PRODUCT_COMPAQ_N10T 0xae34 /* Netelligent 10 T */ +#define PCI_PRODUCT_COMPAQ_IntNF3P 0xae35 /* Integrated NetFlex 3/P */ +#define PCI_PRODUCT_COMPAQ_DPNet100TX 0xae40 /* Dual Port Netelligent 10/100 TX */ +#define PCI_PRODUCT_COMPAQ_IntPL100TX 0xae43 /* ProLiant Integrated Netelligent 10/100 TX */ +#define PCI_PRODUCT_COMPAQ_DP4000 0xb011 /* Deskpro 4000 5233MMX */ +#define PCI_PRODUCT_COMPAQ_NF3P_BNC 0xf150 /* NetFlex 3/P w/ BNC */ +#define PCI_PRODUCT_COMPAQ_NF3P 0xf130 /* NetFlex 3/P */ + +/* Compex products - XXX better descriptions */ +#define PCI_PRODUCT_COMPEX_NE2KETHER 0x1401 /* Ethernet */ +#define PCI_PRODUCT_COMPEX_RL100ATX 0x2011 /* RL100-ATX 10/100 Ethernet */ +#define PCI_PRODUCT_COMPEX_RL100TX 0x9881 /* RL100-TX 10/100 Ethernet */ + +/* Conexant Systems products */ +#define PCI_PRODUCT_CONEXANT_SOFTK56 0x2443 /* SoftK56 PCI Software Modem */ + +/* Contaq Microsystems products */ +#define PCI_PRODUCT_CONTAQ_82C599 0x0600 /* 82C599 PCI-VLB Bridge */ +#define PCI_PRODUCT_CONTAQ_82C693 0xc693 /* 82C693 PCI-ISA Bridge */ + +/* Corollary Products */ +#define PCI_PRODUCT_COROLLARY_CBUSII_PCIB 0x0014 /* \"C-Bus II\"-PCI Bridge */ + +/* Creative Labs products */ +#define PCI_PRODUCT_CREATIVELABS_SBLIVE 0x0002 /* SBLive! EMU 10000 */ +#define PCI_PRODUCT_CREATIVELABS_SBJOY 0x7002 /* PCI Gameport Joystick */ +#define PCI_PRODUCT_CREATIVELABS_EV1938 0x8938 /* Ectiva 1938 */ + +/* Cyclades products */ +#define PCI_PRODUCT_CYCLADES_CYCLOMY_1 0x0100 /* Cyclom-Y below 1M */ +#define PCI_PRODUCT_CYCLADES_CYCLOMY_2 0x0101 /* Cyclom-Y above 1M */ +#define PCI_PRODUCT_CYCLADES_CYCLOM4Y_1 0x0102 /* Cyclom-4Y below 1M */ +#define PCI_PRODUCT_CYCLADES_CYCLOM4Y_2 0x0103 /* Cyclom-4Y above 1M */ +#define PCI_PRODUCT_CYCLADES_CYCLOM8Y_1 0x0104 /* Cyclom-8Y below 1M */ +#define PCI_PRODUCT_CYCLADES_CYCLOM8Y_2 0x0105 /* Cyclom-8Y above 1M */ +#define PCI_PRODUCT_CYCLADES_CYCLOMZ_1 0x0200 /* Cyclom-Z below 1M */ +#define PCI_PRODUCT_CYCLADES_CYCLOMZ_2 0x0201 /* Cyclom-Z above 1M */ + +/* Davicom Semiconductor products */ +#define PCI_PRODUCT_DAVICOM_DM9102 0x9102 /* Davicom DM9102 10/100 Ethernet */ + +/* DEC products */ +#define PCI_PRODUCT_DEC_21050 0x0001 /* DECchip 21050 PCI-PCI Bridge */ +#define PCI_PRODUCT_DEC_21040 0x0002 /* DECchip 21040 Ethernet */ +#define PCI_PRODUCT_DEC_21030 0x0004 /* DECchip 21030 (\"TGA\") */ +#define PCI_PRODUCT_DEC_NVRAM 0x0007 /* Zephyr NV-RAM */ +#define PCI_PRODUCT_DEC_KZPSA 0x0008 /* KZPSA */ +#define PCI_PRODUCT_DEC_21140 0x0009 /* DECchip 21140 10/100 Ethernet */ +#define PCI_PRODUCT_DEC_PBXGB 0x000d /* TGA2 */ +#define PCI_PRODUCT_DEC_DEFPA 0x000f /* DEFPA */ +/* product DEC ??? 0x0010 ??? VME Interface */ +#define PCI_PRODUCT_DEC_21041 0x0014 /* DECchip 21041 Ethernet */ +#define PCI_PRODUCT_DEC_DGLPB 0x0016 /* DGLPB (\"OPPO\") */ +#define PCI_PRODUCT_DEC_21142 0x0019 /* DECchip 21142/21143 10/100 Ethernet */ +#define PCI_PRODUCT_DEC_21052 0x0021 /* DECchip 21052 PCI-PCI Bridge */ +#define PCI_PRODUCT_DEC_21150 0x0022 /* DECchip 21150 PCI-PCI Bridge */ +#define PCI_PRODUCT_DEC_21152 0x0024 /* DECchip 21152 PCI-PCI Bridge */ +#define PCI_PRODUCT_DEC_21153 0x0025 /* DECchip 21153 PCI-PCI Bridge */ +#define PCI_PRODUCT_DEC_21154 0x0026 /* DECchip 21154 PCI-PCI Bridge */ +#define PCI_PRODUCT_DEC_CPQ42XX 0x0046 /* Compaq SMART RAID 42xx */ + +/* Delta products */ +#define PCI_PRODUCT_DELTA_8139 0x1360 /* 8139 Ethernet */ + +/* Diamond products */ +#define PCI_PRODUCT_DIAMOND_VIPER 0x9001 /* Viper/PCI */ + +/* D-Link Systems products */ +#define PCI_PRODUCT_DLINK_DFE550TX 0x1002 /* DFE-550TX 10/100 Ethernet */ + +/* Distributed Processing Technology products */ +#define PCI_PRODUCT_DPT_SC_RAID 0xa400 /* SmartCache/SmartRAID */ +#define PCI_PRODUCT_DPT_RAID_I2O 0xa501 /* SmartRAID (I2O) */ +#define PCI_PRODUCT_DPT_MEMCTLR 0x1012 /* Memory Controller */ + +/* Dolphin products */ +#define PCI_PRODUCT_DOLPHIN_PCISCI 0x0658 /* PCI-SCI Bridge */ + +/* Domex products */ +#define PCI_PRODUCT_DOMEX_PCISCSI 0x0001 /* DMX-3191D */ + +/* ELSA products */ +#define PCI_PRODUCT_ELSA_QS1PCI 0x1000 /* QuickStep 1000 ISDN card */ + +/* Emulex products */ +#define PCI_PRODUCT_EMULEX_LPPFC 0x10df /* \"Light Pulse\" FibreChannel adapter */ + +/* Ensoniq products */ +#define PCI_PRODUCT_ENSONIQ_AUDIOPCI 0x5000 /* AudioPCI */ +#define PCI_PRODUCT_ENSONIQ_AUDIOPCI97 0x1371 /* AudioPCI 97 */ +#define PCI_PRODUCT_ENSONIQ_CT5880 0x5880 /* CT5880 */ + +/* Epigram (now Broadcom) products */ +#define PCI_PRODUCT_EPIGRAM_BCM4210 0xa0fa /* BCM4210 iLine10 Controller */ + +/* Essential Communications products */ +#define PCI_PRODUCT_ESSENTIAL_RR_HIPPI 0x0001 /* RoadRunner HIPPI Interface */ +#define PCI_PRODUCT_ESSENTIAL_RR_GIGE 0x0005 /* RoadRunner Gig-E Interface */ + +/* ESS Technology Inc products */ +#define PCI_PRODUCT_ESSTECH_MAESTRO1 0x0100 /* Maestro 1 PCI Audio Accelerator */ +#define PCI_PRODUCT_ESSTECH_MAESTRO2 0x1968 /* Maestro 2 PCI Audio Accelerator */ +#define PCI_PRODUCT_ESSTECH_SOLO1 0x1969 /* Solo-1 PCI AudioDrive */ +#define PCI_PRODUCT_ESSTECH_MAESTRO2E 0x1978 /* Maestro 2E PCI Audio Accelerator */ +#define PCI_PRODUCT_ESSTECH_MAESTRO3 0x1998 /* Maestro 3 PCI Audio Accelerator */ +#define PCI_PRODUCT_ESSTECH_MAESTRO3MODEM 0x1999 /* Maestro 3 Modem */ + +/* ESS Technology Inc products */ +#define PCI_PRODUCT_ESSTECH2_MAESTRO1 0x0100 /* Maestro 1 PCI Audio Accelerator */ + +/* O2 Micro Inc */ +#define PCI_PRODUCT_O2MICRO_OZ6832 0x6832 /* OZ6832 CardBus Controller */ + +/* Evans & Sutherland products */ +#define PCI_PRODUCT_ES_FREEDOM 0x0001 /* Freedom PCI-GBus Interface */ + +/* FORE products */ +#define PCI_PRODUCT_FORE_PCA200 0x0210 /* ATM PCA-200 */ +#define PCI_PRODUCT_FORE_PCA200E 0x0300 /* ATM PCA-200e */ + +/* Forte Media products */ +#define PCI_PRODUCT_FORTEMEDIA_FM801 0x0801 /* Forte Media 801 Sound */ + +/* Future Domain products */ +#define PCI_PRODUCT_FUTUREDOMAIN_TMC_18C30 0x0000 /* TMC-18C30 (36C70) */ + +/* Efficient Networks products */ +#define PCI_PRODUCT_EFFICIENTNETS_ENI155PF 0x0000 /* 155P-MF1 ATM (FPGA) */ +#define PCI_PRODUCT_EFFICIENTNETS_ENI155PA 0x0002 /* 155P-MF1 ATM (ASIC) */ +#define PCI_PRODUCT_EFFICIENTNETS_ENI25P 0x0003 /* SpeedStream ENI-25p */ +#define PCI_PRODUCT_EFFICIENTNETS_SS3000 0x0005 /* SpeedStream 3000 */ + +/* Galileo Technology products */ +#define PCI_PRODUCT_GALILEO_GT64010A 0x0146 /* GT-64010A System Controller */ +#define PCI_PRODUCT_GALILEO_GT64115 0x4111 /* GT-64115 System Controller */ +#define PCI_PRODUCT_GALILEO_GT64011 0x4146 /* GT-64011 System Controller */ +#define PCI_PRODUCT_GALILEO_GT64120 0x4620 /* GT-64120 System Controller */ +#define PCI_PRODUCT_GALILEO_GT64130 0x6320 /* GT-64130 System Controller */ + +/* Hewlett-Packard products */ +#define PCI_PRODUCT_HP_J2585A 0x1030 /* J2585A */ + +/* IBM products */ +#define PCI_PRODUCT_IBM_MCABRIDGE 0x0002 /* MCA Bridge */ +#define PCI_PRODUCT_IBM_ALTALITE 0x0005 /* CPU Bridge - Alta Lite */ +#define PCI_PRODUCT_IBM_ALTAMP 0x0007 /* CPU Bridge - Alta MP */ +#define PCI_PRODUCT_IBM_ISABRIDGE 0x000a /* ISA Bridge w/PnP */ +#define PCI_PRODUCT_IBM_CPUBRIDGE 0x0017 /* CPU Bridge */ +#define PCI_PRODUCT_IBM_LANSTREAMER 0x0018 /* Auto LANStreamer */ +#define PCI_PRODUCT_IBM_GXT150P 0x001b /* GXT-150P 2D Accelerator */ +#define PCI_PRODUCT_IBM_MCABRIDGE2 0x0020 /* MCA Bridge */ +#define PCI_PRODUCT_IBM_82351 0x0022 /* 82351 PCI-PCI Bridge */ +#define PCI_PRODUCT_IBM_SERVERAID 0x002e /* ServeRAID */ +#define PCI_PRODUCT_IBM_OLYMPIC 0x003e /* Token Ring */ +#define PCI_PRODUCT_IBM_MIAMI 0x0036 /* Miami/PCI */ +#define PCI_PRODUCT_IBM_TURBOWAYS25 0x0053 /* Turboways 25 ATM */ +#define PCI_PRODUCT_IBM_MPIC2 0xffff /* MPIC-II */ + +/* IDT products */ +#define PCI_PRODUCT_IDT_77201 0x0001 /* 77201/77211 ATM (\"NICStAR\") */ + +/* Initio products */ +#define PCI_PRODUCT_INITIO_I920 0x0002 /* INIC-920 SCSI */ +#define PCI_PRODUCT_INITIO_I940 0x9400 /* INIC-940 SCSI */ +#define PCI_PRODUCT_INITIO_I935 0x9401 /* INIC-935 SCSI */ +#define PCI_PRODUCT_INITIO_I950 0x9500 /* INIC-950 SCSI */ + +/* Integrated Micro Solutions products */ +#define PCI_PRODUCT_IMS_8849 0x8849 /* 8849 */ +#define PCI_PRODUCT_IMS_TT128M 0x9128 /* TwinTurbo 128M */ + +/* Intel products */ +#define PCI_PRODUCT_INTEL_PCEB 0x0482 /* 82375EB/SB PCI-EISA Bridge (PCEB) */ +#define PCI_PRODUCT_INTEL_CDC 0x0483 /* 82424ZX Cache and DRAM controller (CDC) */ +#define PCI_PRODUCT_INTEL_SIO 0x0484 /* 82378ZB System I/O (SIO) */ +#define PCI_PRODUCT_INTEL_82426EX 0x0486 /* 82426EX PCI-to-ISA Bridge (PCIB) */ +#define PCI_PRODUCT_INTEL_PCMC 0x04a3 /* 82434LX/NX PCI, Cache and Memory Controller (PCMC) */ +#define PCI_PRODUCT_INTEL_IN_BUSINESS 0x1030 /* InBusiness Fast Ethernet LAN Controller */ +#define PCI_PRODUCT_INTEL_82559ER 0x1209 /* 82559ER Fast Ethernet LAN Controller */ +#define PCI_PRODUCT_INTEL_82092AA 0x1222 /* 82092AA IDE controller */ +#define PCI_PRODUCT_INTEL_SAA7116 0x1223 /* SAA7116 */ +#define PCI_PRODUCT_INTEL_82596 0x1226 /* 82596 LAN Controller */ +#define PCI_PRODUCT_INTEL_EEPRO100 0x1227 /* EE Pro 100 10/100 Fast Ethernet */ +#define PCI_PRODUCT_INTEL_EEPRO100S 0x1228 /* EE Pro 100 Smart 10/100 Fast Ethernet */ +#define PCI_PRODUCT_INTEL_82557 0x1229 /* 82557 Fast Ethernet LAN Controller */ +#define PCI_PRODUCT_INTEL_82437FX 0x122d /* 82437FX System Controller (TSC) */ +#define PCI_PRODUCT_INTEL_82371FB_ISA 0x122e /* 82371FB PCI-to-ISA Bridge (PIIX) */ +#define PCI_PRODUCT_INTEL_82371FB_IDE 0x1230 /* 82371FB IDE controller (PIIX) */ +#define PCI_PRODUCT_INTEL_82371MX 0x1234 /* 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX) */ +#define PCI_PRODUCT_INTEL_82437MX 0x1235 /* 82437MX Mobile System Controller (MTSC) */ +#define PCI_PRODUCT_INTEL_82441FX 0x1237 /* 82441FX PCI and Memory Controller (PMC) */ +#define PCI_PRODUCT_INTEL_82380AB 0x123c /* 82380AB Mobile PCI-to-ISA Bridge (MISA) */ +#define PCI_PRODUCT_INTEL_82380FB 0x124b /* 82380FB Mobile PCI-to-PCI Bridge (MPCI2) */ +#define PCI_PRODUCT_INTEL_82439HX 0x1250 /* 82439HX System Controller (TXC) */ +#define PCI_PRODUCT_INTEL_82801AA_LPC 0x2410 /* 82801AA LPC Interface Bridge */ +#define PCI_PRODUCT_INTEL_82801AA_IDE 0x2411 /* 82801AA IDE Controller */ +#define PCI_PRODUCT_INTEL_82801AA_USB 0x2412 /* 82801AA USB Controller */ +#define PCI_PRODUCT_INTEL_82801AA_SMB 0x2413 /* 82801AA SMBus Controller */ +#define PCI_PRODUCT_INTEL_82801AA_ACA 0x2415 /* 82801AA AC-97 Audio Controller */ +#define PCI_PRODUCT_INTEL_82801AA_ACM 0x2416 /* 82801AA AC-97 PCI Modem */ +#define PCI_PRODUCT_INTEL_82801AA_HPB 0x2418 /* 82801AA Hub-to-PCI Bridge */ +#define PCI_PRODUCT_INTEL_82801AB_LPC 0x2420 /* 82801AB LPC Interface Bridge */ +#define PCI_PRODUCT_INTEL_82801AB_IDE 0x2421 /* 82801AB IDE Controller */ +#define PCI_PRODUCT_INTEL_82801AB_USB 0x2422 /* 82801AB USB Controller */ +#define PCI_PRODUCT_INTEL_82801AB_SMB 0x2423 /* 82801AB SMBus Controller */ +#define PCI_PRODUCT_INTEL_82801AB_ACA 0x2425 /* 82801AB AC-97 Audio Controller */ +#define PCI_PRODUCT_INTEL_82801AB_ACM 0x2426 /* 82801AB AC-97 PCI Modem */ +#define PCI_PRODUCT_INTEL_82801AB_HPB 0x2428 /* 82801AB Hub-to-PCI Bridge */ +#define PCI_PRODUCT_INTEL_82801BA_LPC 0x2440 /* 82801BA LPC Interface Bridge */ +#define PCI_PRODUCT_INTEL_82801BA_USB1 0x2442 /* 82801BA USB Controller */ +#define PCI_PRODUCT_INTEL_82801BA_SMB 0x2443 /* 82801BA SMBus Controller */ +#define PCI_PRODUCT_INTEL_82801BA_USB2 0x2444 /* 82801BA USB Controller */ +#define PCI_PRODUCT_INTEL_82801BA_ACA 0x2445 /* 82801BA AC-97 Audio Controller */ +#define PCI_PRODUCT_INTEL_82801BA_ACM 0x2446 /* 82801BA AC-97 PCI Modem */ +#define PCI_PRODUCT_INTEL_82801BA_LAN 0x2449 /* 82801BA LAN Controller */ +#define PCI_PRODUCT_INTEL_82801BA_IDE 0x244B /* 82801BA IDE Controller */ +#define PCI_PRODUCT_INTEL_82801BA_HPB 0x244E /* 82801BA Hub-to-PCI Bridge */ +#define PCI_PRODUCT_INTEL_82371SB_ISA 0x7000 /* 82371SB PCI-to-ISA Bridge (PIIX3) */ +#define PCI_PRODUCT_INTEL_82371SB_IDE 0x7010 /* 82371SB IDE Interface (PIIX3) */ +#define PCI_PRODUCT_INTEL_82371SB_USB 0x7020 /* 82371SB USB Host Controller (PIIX3) */ +#define PCI_PRODUCT_INTEL_82437VX 0x7030 /* 82437VX System Controller (TVX) */ +#define PCI_PRODUCT_INTEL_82439TX 0x7100 /* 82439TX System Controller (MTXC) */ +#define PCI_PRODUCT_INTEL_82371AB_ISA 0x7110 /* 82371AB PCI-to-ISA Bridge (PIIX4) */ +#define PCI_PRODUCT_INTEL_82371AB_IDE 0x7111 /* 82371AB IDE controller (PIIX4) */ +#define PCI_PRODUCT_INTEL_82371AB_USB 0x7112 /* 82371AB USB Host Controller (PIIX4) */ +#define PCI_PRODUCT_INTEL_82371AB_PMC 0x7113 /* 82371AB Power Management Controller (PIIX4) */ +#define PCI_PRODUCT_INTEL_82810_MCH 0x7120 /* 82810 Memory Controller Hub */ +#define PCI_PRODUCT_INTEL_82810_GC 0x7121 /* 82810 Graphics Controller */ +#define PCI_PRODUCT_INTEL_82810_DC100_MCH 0x7122 /* 82810-DC100 Memory Controller Hub */ +#define PCI_PRODUCT_INTEL_82810_DC100_GC 0x7123 /* 82810-DC100 Graphics Controller */ +#define PCI_PRODUCT_INTEL_82810E_MCH 0x7124 /* 82810E Memory Controller Hub */ +#define PCI_PRODUCT_INTEL_82810E_GC 0x7125 /* 82810E Graphics Controller */ +#define PCI_PRODUCT_INTEL_82443LX 0x7180 /* 82443LX PCI AGP Controller (PAC) */ +#define PCI_PRODUCT_INTEL_82443LX_AGP 0x7181 /* 82443LX AGP Interface (PAC) */ +#define PCI_PRODUCT_INTEL_82443BX 0x7190 /* 82443BX Host Bridge/Controller */ +#define PCI_PRODUCT_INTEL_82443BX_AGP 0x7191 /* 82443BX AGP Interface */ +#define PCI_PRODUCT_INTEL_82443BX_NOAGP 0x7192 /* 82443BX Host Bridge/Controller (AGP disabled) */ +#define PCI_PRODUCT_INTEL_82440MX 0x7194 /* 82440MX Host Bridge/Controller */ +#define PCI_PRODUCT_INTEL_82440MX_ACA 0x7195 /* 82440MX AC-97 Audio Controller */ +#define PCI_PRODUCT_INTEL_82440MX_ISA 0x7198 /* 82440MX PCI-to-ISA Bridge */ +#define PCI_PRODUCT_INTEL_82440MX_IDE 0x7199 /* 82440MX IDE Controller */ +#define PCI_PRODUCT_INTEL_82440MX_USB 0x719a /* 82440MX USB Host Controller */ +#define PCI_PRODUCT_INTEL_82440MX_PMC 0x719b /* 82440MX Power Management Controller */ +#define PCI_PRODUCT_INTEL_I740 0x7800 /* i740 Graphics Accelerator */ +#define PCI_PRODUCT_INTEL_PCI450_PB 0x84c4 /* 82454KX/GX PCI Bridge (PB) */ +#define PCI_PRODUCT_INTEL_PCI450_MC 0x84c5 /* 82451KX/GX Memory Controller (MC) */ +#define PCI_PRODUCT_INTEL_82451NX_MIOC 0x84ca /* 82451NX Memory & I/O Controller (MIOC) */ +#define PCI_PRODUCT_INTEL_82451NX_PXB 0x84cb /* 82451NX PCI Expander Bridge (PXB) */ + +/* Intergraph products */ +#define PCI_PRODUCT_INTERGRAPH_4D50T 0x00e4 /* Powerstorm 4D50T */ + +/* I. T. T. products */ +#define PCI_PRODUCT_ITT_AGX016 0x0001 /* AGX016 */ +#define PCI_PRODUCT_ITT_ITT3204 0x0002 /* ITT3204 MPEG Decoder */ + +/* KTI products - XXX better descriptions */ +#define PCI_PRODUCT_KTI_NE2KETHER 0x3000 /* Ethernet */ + +/* LAN Media Corporation */ +#define PCI_PRODUCT_LMC_HSSI 0x0003 /* HSSI Interface */ +#define PCI_PRODUCT_LMC_DS3 0x0004 /* DS3 Interface */ +#define PCI_PRODUCT_LMC_SSI 0x0005 /* SSI */ + +/* LeadTek Research */ +#define PCI_PRODUCT_LEADTEK_S3_805 0x0000 /* S3 805 */ + +/* Linear Systems / CompuModules */ +#define PCI_PRODUCT_LINEARSYS_DVB_TX 0x7629 /* DVB Transmitter */ +#define PCI_PRODUCT_LINEARSYS_DVB_RX 0x7630 /* DVB Receiver */ + +/* Lite-On products */ +#define PCI_PRODUCT_LITEON_82C168 0x0002 /* 82C168/82C169 (PNIC) 10/100 Ethernet */ +#define PCI_PRODUCT_LITEON_82C115 0xc115 /* 82C115 (PNIC II) 10/100 Ethernet */ + +/* Lucent products */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0440 0x0440 /* K56flex DSVD LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0441 0x0441 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0442 0x0442 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0443 0x0443 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0444 0x0444 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0445 0x0445 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0446 0x0446 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0447 0x0447 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0448 0x0448 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0449 0x0449 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_044A 0x044A /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_044B 0x044B /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_044C 0x044C /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_044D 0x044D /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_044E 0x044E /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0450 0x0450 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0451 0x0451 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0452 0x0452 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0453 0x0453 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0454 0x0454 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0455 0x0455 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0456 0x0456 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0457 0x0457 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0458 0x0458 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_0459 0x0459 /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_LTMODEM_045A 0x045A /* LTMODEM */ +#define PCI_PRODUCT_LUCENT_USBHC 0x5801 /* USB Host Controller */ + +/* Macronix */ +#define PCI_PRODUCT_MACRONIX_MX98713 0x0512 /* MX98713 (PMAC) 10/100 Ethernet */ +#define PCI_PRODUCT_MACRONIX_MX987x5 0x0531 /* MX987x5 (PMAC) 10/100 Ethernet */ + +/* Madge Networks products */ +#define PCI_PRODUCT_MADGE_COLLAGE25 0x1000 /* Collage 25 ATM adapter */ +#define PCI_PRODUCT_MADGE_COLLAGE155 0x1001 /* Collage 155 ATM adapter */ + +/* Matrox products */ +#define PCI_PRODUCT_MATROX_ATLAS 0x0518 /* MGA PX2085 (\"Atlas\") */ +#define PCI_PRODUCT_MATROX_MILLENNIUM 0x0519 /* MGA Millennium 2064W */ +#define PCI_PRODUCT_MATROX_MYSTIQUE 0x051a /* MGA Mystique 1064SG */ +#define PCI_PRODUCT_MATROX_MILLENNIUM2 0x051b /* MGA Millennium II 2164W */ +#define PCI_PRODUCT_MATROX_MILLENNIUM2_AGP 0x051f /* MGA Millennium II 2164WA-B AG */ +#define PCI_PRODUCT_MATROX_G200_PCI 0x0520 /* MGA G200 PCI */ +#define PCI_PRODUCT_MATROX_G200_AGP 0x0521 /* MGA G200 AGP */ +#define PCI_PRODUCT_MATROX_G400_AGP 0x0525 /* MGA G400 AGP */ +#define PCI_PRODUCT_MATROX_IMPRESSION 0x0d10 /* MGA Impression */ +#define PCI_PRODUCT_MATROX_G100_PCI 0x1000 /* MGA G100 PCI */ +#define PCI_PRODUCT_MATROX_G100_AGP 0x1001 /* MGA G100 AGP */ + +/* Motorola products */ +#define PCI_PRODUCT_MOT_MPC105 0x0001 /* MPC105 \"Eagle\" Host Bridge */ +#define PCI_PRODUCT_MOT_MPC106 0x0002 /* MPC106 \"Grackle\" Host Bridge */ + +/* Mylex products */ +#define PCI_PRODUCT_MYLEX_960P 0x0001 /* DAC960P RAID controller */ + +/* Mutech products */ +#define PCI_PRODUCT_MUTECH_MV1000 0x0001 /* MV1000 */ + +/* NetVin products - XXX better descriptions */ +#define PCI_PRODUCT_NETVIN_5000 0x5000 /* 5000 Ethernet */ + +/* Newbridge / Tundra products */ +#define PCI_PRODUCT_NEWBRIDGE_CA91CX42 0x0000 /* Universe VME bridge */ + +/* National Semiconductor products */ +#define PCI_PRODUCT_NS_DP83810 0x0001 /* DP83810 10/100 Ethernet */ +#define PCI_PRODUCT_NS_DP83815 0x0020 /* DP83815 10/100 Ethernet */ +#define PCI_PRODUCT_NS_NS87410 0xd001 /* NS87410 */ + +/* NCR/Symbios Logic products */ +#define PCI_PRODUCT_SYMBIOS_810 0x0001 /* 53c810 */ +#define PCI_PRODUCT_SYMBIOS_820 0x0002 /* 53c820 */ +#define PCI_PRODUCT_SYMBIOS_825 0x0003 /* 53c825 */ +#define PCI_PRODUCT_SYMBIOS_815 0x0004 /* 53c815 */ +#define PCI_PRODUCT_SYMBIOS_810AP 0x0005 /* 53c810AP */ +#define PCI_PRODUCT_SYMBIOS_860 0x0006 /* 53c860 */ +#define PCI_PRODUCT_SYMBIOS_896 0x000b /* 53c896 */ +#define PCI_PRODUCT_SYMBIOS_895 0x000c /* 53c895 */ +#define PCI_PRODUCT_SYMBIOS_885 0x000d /* 53c885 */ +#define PCI_PRODUCT_SYMBIOS_875 0x000f /* 53c875 */ +#define PCI_PRODUCT_SYMBIOS_1510 0x0010 /* 53c1510 */ +#define PCI_PRODUCT_SYMBIOS_875J 0x008f /* 53c875J */ + +/* Packet Engines products */ +#define PCI_PRODUCT_SYMBIOS_PE_GNIC 0x0702 /* Packet Engines G-NIC Ethernet */ + +/* NEC products */ +#define PCI_PRODUCT_NEC_USB 0x0035 /* USB Host Controller */ +#define PCI_PRODUCT_NEC_POWERVR2 0x0046 /* PowerVR PCX2 */ +#define PCI_PRODUCT_NEC_PD72872 0x0063 /* uPD72872 IEEE 1394 OHCI Host Controller */ +#define PCI_PRODUCT_NEC_PD72870 0x00cd /* uPD72870 IEEE 1394 OHCI Host Controller */ +#define PCI_PRODUCT_NEC_PD72871 0x00ce /* uPD72871 IEEE 1394 OHCI Host Controller */ + +/* Neomagic products */ +#define PCI_PRODUCT_NEOMAGIC_NMMG128ZV 0x0003 /* MagicGraph 128ZV */ +#define PCI_PRODUCT_NEOMAGIC_NMMG2160 0x0004 /* MagicGraph 128XD */ +#define PCI_PRODUCT_NEOMAGIC_NMMM256AV_VGA 0x0005 /* MagicMedia 256AV VGA */ +#define PCI_PRODUCT_NEOMAGIC_NMMM256ZX_VGA 0x0006 /* MagicMedia 256ZX VGA */ +#define PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU 0x8005 /* MagicMedia 256AV Audio */ +#define PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU 0x8006 /* MagicMedia 256ZX Audio */ + +/* Netgear products */ +#define PCI_PRODUCT_NETGEAR_GA620 0x620a /* GA620 Gigabit Ethernet */ + +/* NexGen products */ +#define PCI_PRODUCT_NEXGEN_NX82C501 0x4e78 /* NX82C501 Host-PCI Bridge */ + +/* NKK products */ +#define PCI_PRODUCT_NKK_NDR4600 0xA001 /* NDR4600 Host-PCI Bridge */ + +/* Number Nine products */ +#define PCI_PRODUCT_NUMBER9_I128 0x2309 /* Imagine-128 */ +#define PCI_PRODUCT_NUMBER9_I128_2 0x2339 /* Imagine-128 II */ + +/* Nvidia Corporationn products */ +#define PCI_PRODUCT_NVIDIA_RIVATNT 0x0020 /* RIVA TNT */ +#define PCI_PRODUCT_NVIDIA_RIVATNT2 0x0028 /* RIVA TNT2 */ +#define PCI_PRODUCT_NVIDIA_RIVATNT2U 0x0029 /* RIVA TNT2 Ultra */ +#define PCI_PRODUCT_NVIDIA_VANTA 0x002C /* Vanta */ +#define PCI_PRODUCT_NVIDIA_RIVATNT2M64 0x002D /* RIVA TNT2 Model 64 */ +#define PCI_PRODUCT_NVIDIA_ALADDINTNT2 0x00A0 /* Aladdin TNT2 */ +#define PCI_PRODUCT_NVIDIA_GEFORCE256 0x0100 /* GeForce 256 */ +#define PCI_PRODUCT_NVIDIA_GEFORCEDDR 0x0101 /* GeForce DDR */ +#define PCI_PRODUCT_NVIDIA_QUADRO 0x0103 /* Quadro */ +#define PCI_PRODUCT_NVIDIA_GEFORCE2 0x0150 /* GeForce2 GTS */ +#define PCI_PRODUCT_NVIDIA_GEFORCE2DDR 0x0151 /* GeForce2 GTS (DDR) */ +#define PCI_PRODUCT_NVIDIA_GEFORCE2BR 0x0152 /* GeForce2 GTS */ +#define PCI_PRODUCT_NVIDIA_QUADRO2 0x0153 /* Quadro2 */ + +/* Nvidia Corporation & SGS Thomson Microelectric */ +#define PCI_PRODUCT_NVIDIA_SGS_RIVA128 0x0018 /* Riva 128 */ + +/* Oak Technologies products */ +#define PCI_PRODUCT_OAKTECH_OTI1007 0x0107 /* OTI107 */ + +/* Olicom products */ +#define PCI_PRODUCT_OLICOM_OC2183 0x0013 /* Olicom OC-2183/2185 Ethernet */ +#define PCI_PRODUCT_OLICOM_OC2325 0x0012 /* Olicom OC-2325 Ethernet */ +#define PCI_PRODUCT_OLICOM_OC2326 0x0014 /* Olicom OC-2326 10/100-TX Ethernet */ + +/* Opti products */ +#define PCI_PRODUCT_OPTI_82C557 0xc557 /* 82C557 */ +#define PCI_PRODUCT_OPTI_82C558 0xc558 /* 82C558 */ +#define PCI_PRODUCT_OPTI_82C568 0xc568 /* 82C568 */ +#define PCI_PRODUCT_OPTI_82D568 0xd568 /* 82D568 */ +#define PCI_PRODUCT_OPTI_82C621 0xc621 /* 82C621 */ +#define PCI_PRODUCT_OPTI_82C822 0xc822 /* 82C822 */ +#define PCI_PRODUCT_OPTI_RM861HA 0xc861 /* RM861HA */ +#define PCI_PRODUCT_OPTI_82C700 0xc700 /* 82C700 */ +#define PCI_PRODUCT_OPTI_82C701 0xc701 /* 82C701 */ + +/* PC Tech products */ +#define PCI_PRODUCT_PCTECH_RZ1000 0x1000 /* RZ1000 */ + +/* PLX Technology products */ +#define PCI_PRODUCT_PLX_9060ES 0x906e /* 9060ES PCI bus controller */ + +/* ProLAN products - XXX better descriptions */ +#define PCI_PRODUCT_PROLAN_NE2KETHER 0x1980 /* Ethernet */ + +/* Promise products */ +#define PCI_PRODUCT_PROMISE_DC5030 0x5300 /* DC5030 */ +#define PCI_PRODUCT_PROMISE_ULTRA33 0x4d33 /* Ultra33/ATA Bus Master IDE Accelerator */ +#define PCI_PRODUCT_PROMISE_ULTRA66 0x4d38 /* Ultra66/ATA Bus Master IDE Accelerator */ +#define PCI_PRODUCT_PROMISE_ULTRA100 0x4d30 /* Ultra100/ATA Bus Master IDE Accelerator */ + +/* QLogic products */ +#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 /* ISP1020 */ +#define PCI_PRODUCT_QLOGIC_ISP1022 0x1022 /* ISP1022 */ +#define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 /* ISP1080 */ +#define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 /* ISP1240 */ +#define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 /* ISP2100 */ + +/* Quantum Designs products */ +#define PCI_PRODUCT_QUANTUMDESIGNS_8500 0x0001 /* 8500 */ +#define PCI_PRODUCT_QUANTUMDESIGNS_8580 0x0002 /* 8580 */ + +/* Realtek (Creative Labs?) products */ +#define PCI_PRODUCT_REALTEK_RT8029 0x8029 /* 8029 Ethernet */ +#define PCI_PRODUCT_REALTEK_RT8129 0x8129 /* 8129 10/100 Ethernet */ +#define PCI_PRODUCT_REALTEK_RT8139 0x8139 /* 8139 10/100 Ethernet */ + +/* RICOH products */ +#define PCI_PRODUCT_RICOH_Rx5C465 0x0465 /* 5C465 PCI-CardBus bridge */ +#define PCI_PRODUCT_RICOH_Rx5C466 0x0466 /* 5C466 PCI-CardBus bridge */ +#define PCI_PRODUCT_RICOH_Rx5C475 0x0475 /* 5C475 PCI-CardBus bridge */ +#define PCI_PRODUCT_RICOH_RL5C476 0x0476 /* 5C476 PCI-CardBus bridge */ +#define PCI_PRODUCT_RICOH_Rx5C477 0x0477 /* 5C477 PCI-CardBus bridge */ +#define PCI_PRODUCT_RICOH_Rx5C478 0x0478 /* 5C478 PCI-CardBus bridge */ + +/* RISCom (SDL Communications, Inc?) products */ +#define PCI_PRODUCT_RISCOM_N2 0x5568 /* N2 */ + +/* RNS products */ +#define PCI_PRODUCT_RNS_FDDI 0x2200 /* 2200 FDDI */ + +/* S3 products */ +#define PCI_PRODUCT_S3_VIRGE 0x5631 /* ViRGE */ +#define PCI_PRODUCT_S3_TRIO32 0x8810 /* Trio32 */ +#define PCI_PRODUCT_S3_TRIO64 0x8811 /* Trio32/64 */ +#define PCI_PRODUCT_S3_AURORA64P 0x8812 /* Aurora64V+ */ +#define PCI_PRODUCT_S3_TRIO64UVP 0x8814 /* Trio64UV+ */ +#define PCI_PRODUCT_S3_VIRGE_VX 0x883d /* ViRGE/VX */ +#define PCI_PRODUCT_S3_868 0x8880 /* 868 */ +#define PCI_PRODUCT_S3_928 0x88b0 /* 86C928 */ +#define PCI_PRODUCT_S3_864_0 0x88c0 /* 86C864-0 */ +#define PCI_PRODUCT_S3_864_1 0x88c1 /* 86C864-1 */ +#define PCI_PRODUCT_S3_864_2 0x88c2 /* 86C864-2 */ +#define PCI_PRODUCT_S3_864_3 0x88c3 /* 86C864-3 */ +#define PCI_PRODUCT_S3_964_0 0x88d0 /* 86C964-0 */ +#define PCI_PRODUCT_S3_964_1 0x88d1 /* 86C964-1 */ +#define PCI_PRODUCT_S3_964_2 0x88d2 /* 86C964-2 */ +#define PCI_PRODUCT_S3_964_3 0x88d3 /* 86C964-3 */ +#define PCI_PRODUCT_S3_968_0 0x88f0 /* 86C968-0 */ +#define PCI_PRODUCT_S3_968_1 0x88f1 /* 86C968-1 */ +#define PCI_PRODUCT_S3_968_2 0x88f2 /* 86C968-2 */ +#define PCI_PRODUCT_S3_968_3 0x88f3 /* 86C968-3 */ +#define PCI_PRODUCT_S3_TRIO64V2_DX 0x8901 /* Trio64V2/DX */ +#define PCI_PRODUCT_S3_PLATO_PX 0x8901 /* Plato/PX */ +#define PCI_PRODUCT_S3_TRIO3D 0x8904 /* 86C365 Trio3D */ +#define PCI_PRODUCT_S3_VIRGE_DX 0x8a01 /* ViRGE/DX */ +#define PCI_PRODUCT_S3_VIRGE_GX2 0x8a10 /* ViRGE/GX2 */ +#define PCI_PRODUCT_S3_TRIO3D2X 0x8a13 /* Trio3D/2X */ +#define PCI_PRODUCT_S3_SAVAGE3D 0x8a20 /* Savage3D */ +#define PCI_PRODUCT_S3_SAVAGE3D_MV 0x8a21 /* Savage3D+MV */ +#define PCI_PRODUCT_S3_SAVAGE4 0x8a22 /* Savage4 */ +#define PCI_PRODUCT_S3_VIRGE_MX 0x8c01 /* ViRGE/MX */ +#define PCI_PRODUCT_S3_VIRGE_MXP 0x8c03 /* ViRGE/MXP */ +#define PCI_PRODUCT_S3_SAVAGE_MX_MV 0x8c10 /* Savage/MX+MV */ +#define PCI_PRODUCT_S3_SAVAGE_MX 0x8c11 /* Savage/MX */ +#define PCI_PRODUCT_S3_SAVAGE_IX_MV 0x8c12 /* Savage/IX+MV */ +#define PCI_PRODUCT_S3_SAVAGE_IX 0x8c13 /* Savage/IX */ +#define PCI_PRODUCT_S3_SAVAGE2000 0x9102 /* Savage2000 */ +#define PCI_PRODUCT_S3_SONICVIBES 0xca00 /* SonicVibes */ + +/* Samsung Semiconductor products */ +#define PCI_PRODUCT_SAMSUNGSEMI_KS8920 0x8920 /* KS8920 10/100 Ethernet */ + +/* SGI products */ +#define PCI_PRODUCT_SGI_IOC3 0x0003 /* IOC3 */ +#define PCI_PRODUCT_SGI_RAD1 0x0005 /* PsiTech RAD1 */ +#define PCI_PRODUCT_SGI_TIGON 0x0009 /* Tigon Gigabit Ethernet */ + +/* SGS Thomson products */ +#define PCI_PRODUCT_SGSTHOMSON_2000 0x0008 /* STG 2000X */ +#define PCI_PRODUCT_SGSTHOMSON_1764 0x1746 /* STG 1764X */ + +/* SiByte, Inc. products */ +#define PCI_PRODUCT_SIBYTE_SB1250_PCI 0x0001 /* BCM1250 PCI Host Bridge */ +#define PCI_PRODUCT_SIBYTE_SB1250_LDT 0x0002 /* BCM1250 HyperTransport Host Bridge */ + +/* Sigma Designs products */ +#define PCI_PRODUCT_SIGMA_HOLLYWOODPLUS 0x8300 /* REALmagic Hollywood-Plus MPEG-2 Decoder */ + +/* Silicon Integrated System products */ +#define PCI_PRODUCT_SIS_86C201 0x0001 /* 86C201 */ +#define PCI_PRODUCT_SIS_86C202 0x0002 /* 86C202 */ +#define PCI_PRODUCT_SIS_86C205 0x0005 /* 86C205 */ +#define PCI_PRODUCT_SIS_85C503 0x0008 /* 85C503 or 5597/5598 ISA bridge */ +#define PCI_PRODUCT_SIS_600PMC 0x0009 /* 600 Power Mngmt Controller */ +#define PCI_PRODUCT_SIS_5597_VGA 0x0200 /* 5597/5598 integrated VGA */ +#define PCI_PRODUCT_SIS_85C501 0x0406 /* 85C501 */ +#define PCI_PRODUCT_SIS_85C496 0x0496 /* 85C496 */ +#define PCI_PRODUCT_SIS_530HB 0x0530 /* 530 Host to PCI Bridge */ +#define PCI_PRODUCT_SIS_85C601 0x0601 /* 85C601 */ +#define PCI_PRODUCT_SIS_900 0x0900 /* SiS 900 10/100 Ethernet */ +#define PCI_PRODUCT_SIS_5597_IDE 0x5513 /* 5597/5598 IDE controller */ +#define PCI_PRODUCT_SIS_5597_HB 0x5597 /* 5597/5598 host bridge */ +#define PCI_PRODUCT_SIS_530VGA 0x6306 /* 530 GUI Accelerator+3D */ +#define PCI_PRODUCT_SIS_6326 0x6326 /* 6326 AGP VGA */ +#define PCI_PRODUCT_SIS_5597_USB 0x7001 /* 5597/5598 USB host controller */ +#define PCI_PRODUCT_SIS_7016 0x7016 /* SiS 7016 10/100 Ethernet */ + +/* Silicon Motion products */ +#define PCI_PRODUCT_SILMOTION_LYNX_E 0x0810 /* Lynx E */ + +/* SMC products */ +#define PCI_PRODUCT_SMC_37C665 0x1000 /* FDC 37C665 */ +#define PCI_PRODUCT_SMC_37C922 0x1001 /* FDC 37C922 */ +#define PCI_PRODUCT_SMC_83C170 0x0005 /* 83C170 (\"EPIC/100\") Fast Ethernet */ +#define PCI_PRODUCT_SMC_83C175 0x0006 /* 83C175 (\"EPIC/100\") Fast Ethernet */ + +/* Solidum Systems Corporation */ +#define PCI_PRODUCT_SOLIDUM_AMD971 0x2000 /* SNP8023: AMD 971 */ +#define PCI_PRODUCT_SOLIDUM_CLASS802 0x8023 /* SNP8023: Classifier Engine */ + +/* Sony products */ +#define PCI_PRODUCT_SONY_CXD1947A 0x8009 /* CXD1947A IEEE 1394 Host Controller */ +#define PCI_PRODUCT_SONY_CXD32222 0x8039 /* CXD3222 OHCI IEEE 1394 Host Controller */ +#define PCI_PRODUCT_SONY_MEMSTICK 0x808a /* Memory Stick I/F Controller */ + +/* Sun Microsystems products */ +#define PCI_PRODUCT_SUN_EBUS 0x1000 /* PCIO Ebus2 */ +#define PCI_PRODUCT_SUN_HMENETWORK 0x1001 /* PCIO Happy Meal Ethernet */ +#define PCI_PRODUCT_SUN_SIMBA 0x5000 /* Simba PCI bridge */ +#define PCI_PRODUCT_SUN_MS_IIep 0x9000 /* microSPARC IIep PCI */ +#define PCI_PRODUCT_SUN_US_IIi 0xa000 /* UltraSPARC IIi PCI */ + +/* Sundance Technology products */ +#define PCI_PRODUCT_SUNDANCETI_ST201 0x0201 /* ST201 10/100 Ethernet */ + +/* Surecom Technology products */ +#define PCI_PRODUCT_SURECOM_NE34 0x0e34 /* NE-34 Ethernet */ + +/* Symphony Labs products */ +#define PCI_PRODUCT_SYMPHONY_82C101 0x0001 /* 82C101 */ +#define PCI_PRODUCT_SYMPHONY_82C103 0x0103 /* 82C103 */ +#define PCI_PRODUCT_SYMPHONY_82C105 0x0105 /* 82C105 */ +#define PCI_PRODUCT_SYMPHONY2_82C101 0x0001 /* 82C101 */ +#define PCI_PRODUCT_SYMPHONY_83C553 0x0565 /* 83C553 PCI-ISA Bridge */ + +/* Schneider & Koch (really SysKonnect) products */ +#define PCI_PRODUCT_SCHNEIDERKOCH_SKNET_FDDI 0x4000 /* SK-NET FDDI-xP */ + +/* Tekram Technology products (1st PCI Vendor ID)*/ +#define PCI_PRODUCT_TEKRAM_DC290 0xdc29 /* DC-290(M) */ + +/* Tekram Technology products (2nd PCI Vendor ID) */ +#define PCI_PRODUCT_TEKRAM2_DC690C 0x690c /* DC-690C */ + +/* Texas Instruments products */ +#define PCI_PRODUCT_TI_TLAN 0x0500 /* TLAN */ +#define PCI_PRODUCT_TI_TVP4020 0x3d07 /* TVP4020 Permedia 2 */ +#define PCI_PRODUCT_TI_TSB12LV21 0x8000 /* TSB12LV21 IEEE 1394 Host Controller */ +#define PCI_PRODUCT_TI_TSB12LV22 0x8009 /* TSB12LV22 OHCI IEEE 1394 Host Controller */ +#define PCI_PRODUCT_TI_TSB12LV23 0x8019 /* TSB12LV23 OHCI IEEE 1394 Host Controller */ +#define PCI_PRODUCT_TI_TSB12LV26 0x8020 /* TSB12LV26 OHCI IEEE 1394 Host Controller */ +#define PCI_PRODUCT_TI_PCI1130 0xac12 /* PCI1130 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1031 0xac13 /* PCI1031 PCI-PCMCIA Bridge */ +#define PCI_PRODUCT_TI_PCI1131 0xac15 /* PCI1131 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1250 0xac16 /* PCI1250 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1220 0xac17 /* PCI1220 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1221 0xac19 /* PCI1221 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1450 0xac1b /* PCI1450 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1225 0xac1c /* PCI1225 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1251 0xac1d /* PCI1251 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1211 0xac1e /* PCI1211 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1251B 0xac1f /* PCI1251B PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI2030 0xac20 /* PCI2030 PCI-PCI Bridge */ +#define PCI_PRODUCT_TI_PCI1420 0xac51 /* PCI1420 PCI-CardBus Bridge */ +#define PCI_PRODUCT_TI_PCI1451 0xac52 /* PCI1451 PCI-CardBus Bridge */ + +/* Toshiba America products */ +#define PCI_PRODUCT_TOSHIBA_R4X00 0x0009 /* R4x00 Host-PCI Bridge */ +#define PCI_PRODUCT_TOSHIBA_TC35856F 0x0020 /* TC35856F ATM (\"Meteor\") */ + +/* Toshiba America Info Systems products */ +#define PCI_PRODUCT_TOSHIBA2_HOST 0x0601 /* Host Bridge/Controller */ +#define PCI_PRODUCT_TOSHIBA2_ISA 0x0602 /* ISA Bridge */ +#define PCI_PRODUCT_TOSHIBA2_ToPIC95 0x0603 /* ToPIC95 CardBus-PCI Bridge */ +#define PCI_PRODUCT_TOSHIBA2_ToPIC95B 0x060a /* ToPIC95B CardBus-PCI Bridge */ +#define PCI_PRODUCT_TOSHIBA2_ToPIC97 0x060f /* ToPIC97 CardBus-PCI Bridge */ +#define PCI_PRODUCT_TOSHIBA2_ToPIC100 0x0617 /* ToPIC100 CardBus-PCI Bridge */ +#define PCI_PRODUCT_TOSHIBA2_FIRO 0x0701 /* Fast Infrared Type O */ + +/* Trident products */ +#define PCI_PRODUCT_TRIDENT_CYBERBLADE_I7 0x8420 /* CyberBlade i7 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9320 0x9320 /* TGUI 9320 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9350 0x9350 /* TGUI 9350 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9360 0x9360 /* TGUI 9360 */ +#define PCI_PRODUCT_TRIDENT_CYBER_9397 0x9397 /* CYBER 9397 */ +#define PCI_PRODUCT_TRIDENT_CYBER_9397DVD 0x939a /* CYBER 9397DVD */ +#define PCI_PRODUCT_TRIDENT_CYBER_9525 0x9525 /* CYBER 9525 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9420 0x9420 /* TGUI 9420 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9440 0x9440 /* TGUI 9440 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9660 0x9660 /* TGUI 9660 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9680 0x9680 /* TGUI 9680 */ +#define PCI_PRODUCT_TRIDENT_TGUI_9682 0x9682 /* TGUI 9682 */ + +/* Triones Technologies products */ +/* The 366 and 370 controllers have the same product ID */ +#define PCI_PRODUCT_TRIONES_HPT366 0x0004 /* HPT366/370 IDE Controller */ + +/* TriTech Microelectronics products*/ +#define PCI_PRODUCT_TRITECH_TR25202 0xfc02 /* Pyramid3D TR25202 */ + +/* Tseng Labs products */ +#define PCI_PRODUCT_TSENG_ET4000_W32P_A 0x3202 /* ET4000w32p rev A */ +#define PCI_PRODUCT_TSENG_ET4000_W32P_B 0x3205 /* ET4000w32p rev B */ +#define PCI_PRODUCT_TSENG_ET4000_W32P_C 0x3206 /* ET4000w32p rev C */ +#define PCI_PRODUCT_TSENG_ET4000_W32P_D 0x3207 /* ET4000w32p rev D */ +#define PCI_PRODUCT_TSENG_ET6000 0x3208 /* ET6000 */ + +/* UMC products */ +#define PCI_PRODUCT_UMC_UM82C881 0x0001 /* UM82C881 486 Chipset */ +#define PCI_PRODUCT_UMC_UM82C886 0x0002 /* UM82C886 ISA Bridge */ +#define PCI_PRODUCT_UMC_UM8673F 0x0101 /* UM8673F EIDE Controller */ +#define PCI_PRODUCT_UMC_UM8881 0x0881 /* UM8881 HB4 486 PCI Chipset */ +#define PCI_PRODUCT_UMC_UM82C891 0x0891 /* UM82C891 */ +#define PCI_PRODUCT_UMC_UM886A 0x1001 /* UM886A */ +#define PCI_PRODUCT_UMC_UM8886BF 0x673a /* UM8886BF */ +#define PCI_PRODUCT_UMC_UM8710 0x8710 /* UM8710 */ +#define PCI_PRODUCT_UMC_UM8886 0x886a /* UM8886 */ +#define PCI_PRODUCT_UMC_UM8881F 0x8881 /* UM8881F PCI-Host bridge */ +#define PCI_PRODUCT_UMC_UM8886F 0x8886 /* UM8886F PCI-ISA bridge */ +#define PCI_PRODUCT_UMC_UM8886A 0x888a /* UM8886A */ +#define PCI_PRODUCT_UMC_UM8891A 0x8891 /* UM8891A */ +#define PCI_PRODUCT_UMC_UM9017F 0x9017 /* UM9017F */ +#define PCI_PRODUCT_UMC_UM8886N 0xe88a /* UM8886N */ +#define PCI_PRODUCT_UMC_UM8891N 0xe891 /* UM8891N */ + +/* ULSI Systems products */ +#define PCI_PRODUCT_ULSI_US201 0x0201 /* US201 */ + +/* US Robotics products */ +#define PCI_PRODUCT_USR_3CP5609 0x1008 /* 3CP5609 PCI 16550 Modem */ + +/* V3 Semiconductor products */ +#define PCI_PRODUCT_V3_V292PBC 0x0292 /* V292PBC AMD290x0 Host-PCI Bridge */ +#define PCI_PRODUCT_V3_V960PBC 0x0960 /* V960PBC i960 Host-PCI Bridge */ +#define PCI_PRODUCT_V3_V96DPC 0xC960 /* V96DPC i960 (Dual) Host-PCI Bridge */ + +/* VIA Technologies products, from http://www.via.com.tw/ */ +#define PCI_PRODUCT_VIATECH_VT8371_HB 0x0391 /* VT8371 (Apollo KX133) Host Bridge */ +#define PCI_PRODUCT_VIATECH_VT8501_MVP4 0x0501 /* VT8501 MVP4 System Controller */ +#define PCI_PRODUCT_VIATECH_VT82C505 0x0505 /* VT82C505 (Pluto) */ +#define PCI_PRODUCT_VIATECH_VT82C561 0x0561 /* VT82C561 */ +#define PCI_PRODUCT_VIATECH_VT82C586A_IDE 0x0571 /* VT82C586A IDE Controller */ +#define PCI_PRODUCT_VIATECH_VT82C576 0x0576 /* VT82C576 3V */ +#define PCI_PRODUCT_VIATECH_VT82C580VP 0x0585 /* VT82C580 (Apollo VP) Host-PCI Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C586_ISA 0x0586 /* VT82C586 (Apollo VP) PCI-ISA Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C595 0x0595 /* VT82C595 (Apollo VP2) Host-PCI Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C596A 0x0596 /* VT82C596A (Apollo Pro) PCI-ISA Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C597 0x0597 /* VT82C597 (Apollo VP3) Host-PCI Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C598PCI 0x0598 /* VT82C598 (Apollo MVP3) Host-PCI */ +#define PCI_PRODUCT_VIATECH_VT82C686A_ISA 0x0686 /* VT82C686A (Apollo KX133) PCI-ISA Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C691 0x0691 /* VT82C691 (Apollo Pro) Host-PCI */ +#define PCI_PRODUCT_VIATECH_VT82C693 0x0693 /* VT82C693 (Apollo Pro Plus) Host-PCI */ +#define PCI_PRODUCT_VIATECH_VT86C926 0x0926 /* VT86C926 Amazon PCI-Ethernet Controller */ +#define PCI_PRODUCT_VIATECH_VT82C570M 0x1000 /* VT82C570M (Apollo) Host-PCI Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C570MV 0x1006 /* VT82C570M (Apollo) PCI-ISA Bridge */ +#define PCI_PRODUCT_VIATECH_VT82C586_IDE 0x1571 /* VT82C586 (Apollo VP) IDE Controller */ +#define PCI_PRODUCT_VIATECH_VT82C595_2 0x1595 /* VT82C595 (Apollo VP2) Host-PCI Bridge */ +#define PCI_PRODUCT_VIATECH_VT83C572 0x3038 /* VT83C572 USB Controller */ +#define PCI_PRODUCT_VIATECH_VT82C586_PWR 0x3040 /* VT82C586 (Apollo VP) Power Management Controller */ +#define PCI_PRODUCT_VIATECH_VT3043 0x3043 /* VT3043 (Rhine) 10/100 Ethernet */ +#define PCI_PRODUCT_VIATECH_VT82C686A_SMB 0x3057 /* VT82C686A SMBus Controller */ +#define PCI_PRODUCT_VIATECH_VT82C686A_AC97 0x3058 /* VT82C686A AC-97 Audio Controller */ +#define PCI_PRODUCT_VIATECH_VT82C686A_MC97 0x3068 /* VT82C686A MC-97 Modem Controller */ +#define PCI_PRODUCT_VIATECH_VT86C100A 0x6100 /* VT86C100A (Rhine-II) 10/100 Ethernet */ +#define PCI_PRODUCT_VIATECH_VT8371_PPB 0x8391 /* VT8371 (Apollo KX133) PCI-PCI Bridge */ +#define PCI_PRODUCT_VIATECH_VT8501AGP 0x8501 /* VT8501 PCI-AGP */ +#define PCI_PRODUCT_VIATECH_VT82C597AGP 0x8597 /* VT82C597 (Apollo VP3) PCI-AGP */ +#define PCI_PRODUCT_VIATECH_VT82C598AGP 0x8598 /* VT82C598 (Apollo MVP3) PCI-AGP */ + +/* Vortex Computer Systems products */ +/* GDT_PCI */ +#define PCI_PRODUCT_VORTEX_GDT_60x0 0x0000 /* GDT6000/6020/6050 */ +#define PCI_PRODUCT_VORTEX_GDT_6000B 0x0001 /* GDT6000B/6010 */ +/* GDT_PCINEW */ +#define PCI_PRODUCT_VORTEX_GDT_6x10 0x0002 /* GDT6110/6510 */ +#define PCI_PRODUCT_VORTEX_GDT_6x20 0x0003 /* GDT6120/6520 */ +#define PCI_PRODUCT_VORTEX_GDT_6530 0x0004 /* GDT6530 */ +#define PCI_PRODUCT_VORTEX_GDT_6550 0x0005 /* GDT6550 */ +/* GDT_PCINEW, wide/ultra SCSI controllers */ +#define PCI_PRODUCT_VORTEX_GDT_6x17 0x0006 /* GDT6117/6517 */ +#define PCI_PRODUCT_VORTEX_GDT_6x27 0x0007 /* GDT6127/6527 */ +#define PCI_PRODUCT_VORTEX_GDT_6537 0x0008 /* GDT6537 */ +#define PCI_PRODUCT_VORTEX_GDT_6557 0x0009 /* GDT6557/6557-ECC */ +/* GDT_PCINEW, wide SCSI controllers */ +#define PCI_PRODUCT_VORTEX_GDT_6x15 0x0010 /* GDT6115/6515 */ +#define PCI_PRODUCT_VORTEX_GDT_6x25 0x0011 /* GDT6125/6525 */ +#define PCI_PRODUCT_VORTEX_GDT_6535 0x0012 /* GDT6535 */ +#define PCI_PRODUCT_VORTEX_GDT_6555 0x0013 /* GDT6555/6555-ECC */ +/* GDT_MPR, RP series, wide/ultra SCSI */ +#define PCI_PRODUCT_VORTEX_GDT_6x17RP 0x0100 /* GDT6117RP/GDT6517RP */ +#define PCI_PRODUCT_VORTEX_GDT_6x27RP 0x0101 /* GDT6127RP/GDT6527RP */ +#define PCI_PRODUCT_VORTEX_GDT_6537RP 0x0102 /* GDT6537RP */ +#define PCI_PRODUCT_VORTEX_GDT_6557RP 0x0103 /* GDT6557RP */ +/* GDT_MPR, RP series, narrow/ultra SCSI */ +#define PCI_PRODUCT_VORTEX_GDT_6x11RP 0x0104 /* GDT6111RP/GDT6511RP */ +#define PCI_PRODUCT_VORTEX_GDT_6x21RP 0x0105 /* GDT6121RP/GDT6521RP */ +/* GDT_MPR, RD series, wide/ultra SCSI */ +#define PCI_PRODUCT_VORTEX_GDT_6x17RD 0x0110 /* GDT6117RD/GDT6517RD */ +#define PCI_PRODUCT_VORTEX_GDT_6x27RD 0x0111 /* GDT6127RD/GDT6527RD */ +#define PCI_PRODUCT_VORTEX_GDT_6537RD 0x0112 /* GDT6537RD */ +#define PCI_PRODUCT_VORTEX_GDT_6557RD 0x0113 /* GDT6557RD */ +/* GDT_MPR, RD series, narrow/ultra SCSI */ +#define PCI_PRODUCT_VORTEX_GDT_6x11RD 0x0114 /* GDT6111RD/GDT6511RD */ +#define PCI_PRODUCT_VORTEX_GDT_6x21RD 0x0115 /* GDT6121RD/GDT6521RD */ +/* GDT_MPR, RD series, wide/ultra2 SCSI */ +#define PCI_PRODUCT_VORTEX_GDT_6x18RD 0x0118 /* GDT6118RD/GDT6518RD/GDT6618RD */ +#define PCI_PRODUCT_VORTEX_GDT_6x28RD 0x0119 /* GDT6128RD/GDT6528RD/GDT6628RD */ +#define PCI_PRODUCT_VORTEX_GDT_6x38RD 0x011A /* GDT6538RD/GDT6638RD */ +#define PCI_PRODUCT_VORTEX_GDT_6x58RD 0x011B /* GDT6558RD/GDT6658RD */ +/* GDT_MPR, RN series (64-bit PCI), wide/ultra2 SCSI */ +#define PCI_PRODUCT_VORTEX_GDT_7x18RN 0x0168 /* GDT7118RN/GDT7518RN/GDT7618RN */ +#define PCI_PRODUCT_VORTEX_GDT_7x28RN 0x0169 /* GDT7128RN/GDT7528RN/GDT7628RN */ +#define PCI_PRODUCT_VORTEX_GDT_7x38RN 0x016A /* GDT7538RN/GDT7638RN */ +#define PCI_PRODUCT_VORTEX_GDT_7x58RN 0x016B /* GDT7558RN/GDT7658RN */ +/* GDT_MPR, RD series, Fibre Channel */ +#define PCI_PRODUCT_VORTEX_GDT_6x19RD 0x0210 /* GDT6519RD/GDT6619RD */ +#define PCI_PRODUCT_VORTEX_GDT_6x29RD 0x0211 /* GDT6529RD/GDT6629RD */ +/* GDT_MPR, RN series (64-bit PCI), Fibre Channel */ +#define PCI_PRODUCT_VORTEX_GDT_7x19RN 0x0260 /* GDT7519RN/GDT7619RN */ +#define PCI_PRODUCT_VORTEX_GDT_7x29RN 0x0261 /* GDT7529RN/GDT7629RN */ + +/* VLSI products */ +#define PCI_PRODUCT_VLSI_82C592 0x0005 /* 82C592 CPU Bridge */ +#define PCI_PRODUCT_VLSI_82C593 0x0006 /* 82C593 ISA Bridge */ +#define PCI_PRODUCT_VLSI_82C594 0x0007 /* 82C594 Wildcat System Controller */ +#define PCI_PRODUCT_VLSI_82C596597 0x0008 /* 82C596/597 Wildcat ISA Bridge */ +#define PCI_PRODUCT_VLSI_82C541 0x000c /* 82C541 */ +#define PCI_PRODUCT_VLSI_82C543 0x000d /* 82C543 */ +#define PCI_PRODUCT_VLSI_82C532 0x0101 /* 82C532 */ +#define PCI_PRODUCT_VLSI_82C534 0x0102 /* 82C534 */ +#define PCI_PRODUCT_VLSI_82C535 0x0104 /* 82C535 */ +#define PCI_PRODUCT_VLSI_82C147 0x0105 /* 82C147 */ +#define PCI_PRODUCT_VLSI_82C975 0x0200 /* 82C975 */ +#define PCI_PRODUCT_VLSI_82C925 0x0280 /* 82C925 */ + +/* Weitek products */ +#define PCI_PRODUCT_WEITEK_P9000 0x9001 /* P9000 */ +#define PCI_PRODUCT_WEITEK_P9100 0x9100 /* P9100 */ + +/* Western Digital products */ +#define PCI_PRODUCT_WD_WD33C193A 0x0193 /* WD33C193A */ +#define PCI_PRODUCT_WD_WD33C196A 0x0196 /* WD33C196A */ +#define PCI_PRODUCT_WD_WD33C197A 0x0197 /* WD33C197A */ +#define PCI_PRODUCT_WD_WD7193 0x3193 /* WD7193 */ +#define PCI_PRODUCT_WD_WD7197 0x3197 /* WD7197 */ +#define PCI_PRODUCT_WD_WD33C296A 0x3296 /* WD33C296A */ +#define PCI_PRODUCT_WD_WD34C296 0x4296 /* WD34C296 */ +#define PCI_PRODUCT_WD_90C 0xC24A /* 90C */ + +/* Winbond Electronics products */ +#define PCI_PRODUCT_WINBOND_W83769F 0x0001 /* W83769F */ +#define PCI_PRODUCT_WINBOND_W89C840F 0x0840 /* W89C840F 10/100 Ethernet */ +#define PCI_PRODUCT_WINBOND_W89C940F 0x0940 /* W89C940F Ethernet */ +#define PCI_PRODUCT_WINBOND_W89C940F_1 0x5a5a /* W89C940F Ethernet */ + +/* Xircom products */ +/* is the `-3' here just indicating revision 3, or is it really part + of the device name? */ +#define PCI_PRODUCT_XIRCOM_X3201_3 0x0002 /* X3201-3 Fast Ethernet Controller */ +/* this is the device id `indicating 21143 driver compatibility' */ +#define PCI_PRODUCT_XIRCOM_X3201_3_21143 0x0003 /* X3201-3 Fast Ethernet Controller (21143) */ + +/* Yamaha products */ +#define PCI_PRODUCT_YAMAHA_YMF724 0x0004 /* 724 Audio */ +#define PCI_PRODUCT_YAMAHA_YMF740 0x000A /* 740 Audio */ +#define PCI_PRODUCT_YAMAHA_YMF740C 0x000C /* 740C (DS-1) Audio */ +#define PCI_PRODUCT_YAMAHA_YMF724F 0x000D /* 724F (DS-1) Audio */ +#define PCI_PRODUCT_YAMAHA_YMF744B 0x0010 /* 744 (DS-1S) Audio */ +#define PCI_PRODUCT_YAMAHA_YMF754 0x0012 /* 754 (DS-1E) Audio */ + +/* Zeinet products */ +#define PCI_PRODUCT_ZEINET_1221 0x0001 /* 1221 */ + +/* Ziatech products */ +#define PCI_PRODUCT_ZIATECH_ZT8905 0x8905 /* PCI-ST32 Bridge */ + +/* Zoran products */ +#define PCI_PRODUCT_ZORAN_ZR36120 0x6120 /* Video Controller */ diff --git a/cfe/cfe/pci/pcidevs_data.h b/cfe/cfe/pci/pcidevs_data.h new file mode 100644 index 0000000..1bdc7f4 --- /dev/null +++ b/cfe/cfe/pci/pcidevs_data.h @@ -0,0 +1,5873 @@ +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * generated from: + * pcidevs 2002/09/03 broadcom + */ + +/* + * Copyright (c) 1995, 1996 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +static const struct pci_knowndev pci_knowndevs[] = { + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C985, + 0, + "3Com", + "3c985 Gigabit Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C590, + 0, + "3Com", + "3c590 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C595TX, + 0, + "3Com", + "3c595-TX 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C595T4, + 0, + "3Com", + "3c595-T4 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C595MII, + 0, + "3Com", + "3c595-MII 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C900TPO, + 0, + "3Com", + "3c900-TPO Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C900COMBO, + 0, + "3Com", + "3c900-COMBO Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C905TX, + 0, + "3Com", + "3c905-TX 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C905T4, + 0, + "3Com", + "3c905-T4 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C900BTPO, + 0, + "3Com", + "3c900B-TPO Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C900BCOMBO, + 0, + "3Com", + "3c900B-COMBO Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C900BTPC, + 0, + "3Com", + "3c900B-TPC Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C905BTX, + 0, + "3Com", + "3c905B-TX 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C905BT4, + 0, + "3Com", + "3c905B-T4 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C905BCOMBO, + 0, + "3Com", + "3c905B-COMBO 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C905BFX, + 0, + "3Com", + "3c905B-FX 100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C905CTX, + 0, + "3Com", + "3c905C-TX 10/100 Ethernet with mngmt", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C980SRV, + 0, + "3Com", + "3c980 Server Adapter 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C980CTXM, + 0, + "3Com", + "3c980C-TXM 10/100 Ethernet", + }, + { + PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990TX97, + 0, + "3Com", + "3CR990-TX-97 10/100 Ethernet", + }, + { + PCI_VENDOR_3DFX, PCI_PRODUCT_3DFX_VOODOO, + 0, + "3Dfx Interactive", + "Voodoo", + }, + { + PCI_VENDOR_3DFX, PCI_PRODUCT_3DFX_VOODOO2, + 0, + "3Dfx Interactive", + "Voodoo2", + }, + { + PCI_VENDOR_3DFX, PCI_PRODUCT_3DFX_BANSHEE, + 0, + "3Dfx Interactive", + "Banshee", + }, + { + PCI_VENDOR_3DFX, PCI_PRODUCT_3DFX_VOODOO3, + 0, + "3Dfx Interactive", + "Voodoo3", + }, + { + PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_300SX, + 0, + "3D Labs", + "GLINT 300SX", + }, + { + PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_500TX, + 0, + "3D Labs", + "GLINT 500TX", + }, + { + PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_DELTA, + 0, + "3D Labs", + "GLINT DELTA", + }, + { + PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_PERMEDIA, + 0, + "3D Labs", + "GLINT Permedia", + }, + { + PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_500MX, + 0, + "3D Labs", + "GLINT 500MX", + }, + { + PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_PERMEDI2, + 0, + "3D Labs", + "GLINT Permedia 2", + }, + { + PCI_VENDOR_3WARE, PCI_PRODUCT_3WARE_ESCALADE, + 0, + "3ware", + "Escalade IDE RAID", + }, + { + PCI_VENDOR_ACC, PCI_PRODUCT_ACC_2188, + 0, + "ACC Microelectronics", + "ACCM 2188 VL-PCI Bridge", + }, + { + PCI_VENDOR_ACC, PCI_PRODUCT_ACC_2051_HB, + 0, + "ACC Microelectronics", + "2051 PCI Single Chip Solution (host bridge)", + }, + { + PCI_VENDOR_ACC, PCI_PRODUCT_ACC_2051_ISA, + 0, + "ACC Microelectronics", + "2051 PCI Single Chip Solution (ISA bridge)", + }, + { + PCI_VENDOR_ACARD, PCI_PRODUCT_ACARD_AEC6710, + 0, + "Acard", + "AEC6710 SCSI", + }, + { + PCI_VENDOR_ACARD, PCI_PRODUCT_ACARD_AEC6712UW, + 0, + "Acard", + "AEC6712UW SCSI", + }, + { + PCI_VENDOR_ACARD, PCI_PRODUCT_ACARD_AEC6712U, + 0, + "Acard", + "AEC6712U SCSI", + }, + { + PCI_VENDOR_ACARD, PCI_PRODUCT_ACARD_AEC6712S, + 0, + "Acard", + "AEC6712S SCSI", + }, + { + PCI_VENDOR_ACARD, PCI_PRODUCT_ACARD_AEC6710D, + 0, + "Acard", + "AEC6710D SCSI", + }, + { + PCI_VENDOR_ACARD, PCI_PRODUCT_ACARD_AEC6715UW, + 0, + "Acard", + "AEC6715UW SCSI", + }, + { + PCI_VENDOR_ACCTON, PCI_PRODUCT_ACCTON_MPX5030, + 0, + "Accton Technology", + "MPX 5030/5038 Ethernet", + }, + { + PCI_VENDOR_ACER, PCI_PRODUCT_ACER_M1435, + 0, + "Acer", + "M1435 VL-PCI Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1445, + 0, + "Acer Labs", + "M1445 VL-PCI Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1449, + 0, + "Acer Labs", + "M1449 PCI-ISA Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1451, + 0, + "Acer Labs", + "M1451 Host-PCI Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1461, + 0, + "Acer Labs", + "M1461 Host-PCI Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1531, + 0, + "Acer Labs", + "M1531 Host-PCI Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1541, + 0, + "Acer Labs", + "M1541 Host-PCI Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543, + 0, + "Acer Labs", + "M1543 PCI-ISA Bridge", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M3309, + 0, + "Acer Labs", + "M3309 MPEG Decoder", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M4803, + 0, + "Acer Labs", + "M4803", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5229, + 0, + "Acer Labs", + "M5229 UDMA IDE Controller", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5237, + 0, + "Acer Labs", + "M5237 USB Host Controller", + }, + { + PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M7101, + 0, + "Acer Labs", + "M7101 Power Management Controller", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7850, + 0, + "Adaptec", + "AIC-7850", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7855, + 0, + "Adaptec", + "AIC-7855", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC5900, + 0, + "Adaptec", + "AIC-5900 ATM", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC5905, + 0, + "Adaptec", + "AIC-5905 ATM", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC6915, + 0, + "Adaptec", + "AIC-6915 10/100 Ethernet", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7860, + 0, + "Adaptec", + "AIC-7860", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_APA1480, + 0, + "Adaptec", + "APA-1480 Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940AU, + 0, + "Adaptec", + "AHA-2940A Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7870, + 0, + "Adaptec", + "AIC-7870", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940, + 0, + "Adaptec", + "AHA-2940", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3940, + 0, + "Adaptec", + "AHA-3940", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3985, + 0, + "Adaptec", + "AHA-3985", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2944, + 0, + "Adaptec", + "AHA-2944", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7895, + 0, + "Adaptec", + "AIC-7895 Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7880, + 0, + "Adaptec", + "AIC-7880 Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940U, + 0, + "Adaptec", + "AHA-2940 Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3940U, + 0, + "Adaptec", + "AHA-3940 Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_389XU, + 0, + "Adaptec", + "AHA-389X Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2944U, + 0, + "Adaptec", + "AHA-2944 Ultra", + }, + { + PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940UP, + 0, + "Adaptec", + "AHA-2940 Ultra Pro", + }, + { + PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_2940U2, + 0, + "Adaptec (2nd PCI Vendor ID)", + "AHA-2940 Ultra2", + }, + { + PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_2930U2, + 0, + "Adaptec (2nd PCI Vendor ID)", + "AHA-2930 Ultra2", + }, + { + PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7890, + 0, + "Adaptec (2nd PCI Vendor ID)", + "AIC-7890/1", + }, + { + PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3950U2B, + 0, + "Adaptec (2nd PCI Vendor ID)", + "AHA-3950 Ultra2", + }, + { + PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3950U2D, + 0, + "Adaptec (2nd PCI Vendor ID)", + "AHA-3950 Ultra2", + }, + { + PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7896, + 0, + "Adaptec (2nd PCI Vendor ID)", + "AIC-7896/7", + }, + { + PCI_VENDOR_ADDTRON, PCI_PRODUCT_ADDTRON_8139, + 0, + "Addtron Technology", + "8139 Ethernet", + }, + { + PCI_VENDOR_ADMTEK, PCI_PRODUCT_ADMTEK_AL981, + 0, + "ADMtek", + "ADMtek AL981 10/100 Ethernet", + }, + { + PCI_VENDOR_ADVSYS, PCI_PRODUCT_ADVSYS_1200A, + 0, + "Advanced System Products", + "", + }, + { + PCI_VENDOR_ADVSYS, PCI_PRODUCT_ADVSYS_1200B, + 0, + "Advanced System Products", + "", + }, + { + PCI_VENDOR_ADVSYS, PCI_PRODUCT_ADVSYS_ULTRA, + 0, + "Advanced System Products", + "ABP-930/40UA", + }, + { + PCI_VENDOR_ADVSYS, PCI_PRODUCT_ADVSYS_WIDE, + 0, + "Advanced System Products", + "ABP-940UW", + }, + { + PCI_VENDOR_ADVSYS, PCI_PRODUCT_ADVSYS_U2W, + 0, + "Advanced System Products", + "ASB-3940U2W", + }, + { + PCI_VENDOR_ADVSYS, PCI_PRODUCT_ADVSYS_U3W, + 0, + "Advanced System Products", + "ASB-3940U3W", + }, + { + PCI_VENDOR_ALLIANCE, PCI_PRODUCT_ALLIANCE_AT24, + 0, + "Alliance Semiconductor", + "AT24", + }, + { + PCI_VENDOR_ALLIANCE, PCI_PRODUCT_ALLIANCE_AT25, + 0, + "Alliance Semiconductor", + "AT25", + }, + { + PCI_VENDOR_ALTEON, PCI_PRODUCT_ALTEON_ACENIC, + 0, + "Alteon", + "ACEnic Gigabit Ethernet", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PCNET_PCI, + 0, + "Advanced Micro Devices", + "79c970 PCnet-PCI LANCE Ethernet", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PCNET_HOME, + 0, + "Advanced Micro Devices", + "79c978 PCnet-PCI Home", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PCSCSI_PCI, + 0, + "Advanced Micro Devices", + "53c974 PCscsi-PCI SCSI", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PCNETS_PCI, + 0, + "Advanced Micro Devices", + "79C974 PCnet-PCI Ethernet & SCSI", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_SC751_SC, + 0, + "Advanced Micro Devices", + "AMD751 System Controller", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_SC751_PPB, + 0, + "Advanced Micro Devices", + "AMD751 PCI-to-PCI Bridge", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_ISA, + 0, + "Advanced Micro Devices", + "AMD756 PCI-to-ISA Bridge", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_IDE, + 0, + "Advanced Micro Devices", + "AMD756 IDE controller", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC, + 0, + "Advanced Micro Devices", + "AMD756 Power Management Controller", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_USB, + 0, + "Advanced Micro Devices", + "AMD756 USB Host Controller", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_HT7520, + 0, + "Advanced Micro Devices", + "(PLX) HT7520 PCIX Tunnel", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_HT7520_PIC, + 0, + "Advanced Micro Devices", + "(PLX) HT7520 PCIX IOAPIC", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_AMD8151_AGP, + 0, + "Advanced Micro Devices", + "AMD8151 AGP Device", + }, + { + PCI_VENDOR_AMD, PCI_PRODUCT_AMD_AMD8151, + 0, + "Advanced Micro Devices", + "AMD8151 HyperTransport-AGP Bridge", + }, + { + PCI_VENDOR_API, PCI_PRODUCT_API_STURGEON, + 0, + "API Networks", + "AP1011 HyperTransport-PCI Bridge", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_BANDIT, + 0, + "Apple Computer", + "Bandit Host-PCI Bridge", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_GC, + 0, + "Apple Computer", + "Grand Central I/O Controller", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_CONTROL, + 0, + "Apple Computer", + "Control", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_PLANB, + 0, + "Apple Computer", + "PlanB", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_OHARE, + 0, + "Apple Computer", + "OHare I/O Controller", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_BANDIT2, + 0, + "Apple Computer", + "Bandit Host-PCI Bridge", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_HEATHROW, + 0, + "Apple Computer", + "MAC-IO I/O Controller (Heathrow)", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_PADDINGTON, + 0, + "Apple Computer", + "MAC-IO I/O Controller (Paddington)", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_KEYLARGO_USB, + 0, + "Apple Computer", + "KeyLargo USB Controller", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTH1, + 0, + "Apple Computer", + "UniNorth Host-PCI Bridge", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTH2, + 0, + "Apple Computer", + "UniNorth Host-PCI Bridge", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTH_AGP, + 0, + "Apple Computer", + "UniNorth AGP Interface", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_GMAC, + 0, + "Apple Computer", + "GMAC Ethernet", + }, + { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_KEYLARGO, + 0, + "Apple Computer", + "MAC-IO I/O Controller (KeyLargo)", + }, + { + PCI_VENDOR_ARC, PCI_PRODUCT_ARC_1000PV, + 0, + "ARC Logic", + "1000PV", + }, + { + PCI_VENDOR_ARC, PCI_PRODUCT_ARC_2000PV, + 0, + "ARC Logic", + "2000PV", + }, + { + PCI_VENDOR_ARC, PCI_PRODUCT_ARC_2000MT, + 0, + "ARC Logic", + "2000MT", + }, + { + PCI_VENDOR_ASIX, PCI_PRODUCT_ASIX_AX88140A, + 0, + "ASIX Electronics", + "AX88140A 10/100 Ethernet", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH32, + 0, + "ATI Technologies", + "Mach32", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_CT, + 0, + "ATI Technologies", + "Mach64 CT", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_CX, + 0, + "ATI Technologies", + "Mach64 CX", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_ET, + 0, + "ATI Technologies", + "Mach64 ET", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_VT, + 0, + "ATI Technologies", + "Mach64 VT", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_B, + 0, + "ATI Technologies", + "Mach64 B", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GB, + 0, + "ATI Technologies", + "Mach64 GB", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GD, + 0, + "ATI Technologies", + "Mach64 GD", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GI, + 0, + "ATI Technologies", + "Mach64 GI", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GP, + 0, + "ATI Technologies", + "Mach64 GP", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GQ, + 0, + "ATI Technologies", + "Mach64 GQ", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GT, + 0, + "ATI Technologies", + "Mach64 GT", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GU, + 0, + "ATI Technologies", + "Mach64 GU", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GV, + 0, + "ATI Technologies", + "Mach64 GV", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GW, + 0, + "ATI Technologies", + "Mach64 GW", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GX, + 0, + "ATI Technologies", + "Mach64 GX", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_GZ, + 0, + "ATI Technologies", + "Mach64 GZ", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_LB, + 0, + "ATI Technologies", + "Mach64 LB", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_LD, + 0, + "ATI Technologies", + "Mach64 LD", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_LG, + 0, + "ATI Technologies", + "Mach64 LG", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_LI, + 0, + "ATI Technologies", + "Mach64 LI", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_LM, + 0, + "ATI Technologies", + "Mach64 LM", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_LP, + 0, + "ATI Technologies", + "Mach64 LP", + }, + { + PCI_VENDOR_ATI, PCI_PRODUCT_ATI_MACH64_LR, + 0, + "ATI Technologies", + "Mach64 LR", + }, + { + PCI_VENDOR_AURAVISION, PCI_PRODUCT_AURAVISION_VXP524, + 0, + "Auravision", + "VxP524 PCI Video Processor", + }, + { + PCI_VENDOR_AUREAL, PCI_PRODUCT_AUREAL_AU8820, + 0, + "Aureal Semiconductor", + "AU8820 Vortex Digital Audio Processor", + }, + { + PCI_VENDOR_AMCIRCUITS, PCI_PRODUCT_AMCIRCUITS_S5933, + 0, + "Applied Micro Circuits", + "S5933 PCI Matchmaker", + }, + { + PCI_VENDOR_AMCIRCUITS, PCI_PRODUCT_AMCIRCUITS_LANAI, + 0, + "Applied Micro Circuits", + "Myrinet LANai Interface", + }, + { + PCI_VENDOR_AMCIRCUITS, PCI_PRODUCT_AMCIRCUITS_S5920, + 0, + "Applied Micro Circuits", + "S5920 PCI Target", + }, + { + PCI_VENDOR_ATRONICS, PCI_PRODUCT_ATRONICS_IDE_2015PL, + 0, + "Atronics", + "IDE-2015PL", + }, + { + PCI_VENDOR_AVANCE, PCI_PRODUCT_AVANCE_AVL2301, + 0, + "Avance Logic", + "AVL2301", + }, + { + PCI_VENDOR_AVANCE, PCI_PRODUCT_AVANCE_AVG2302, + 0, + "Avance Logic", + "AVG2302", + }, + { + PCI_VENDOR_AVANCE2, PCI_PRODUCT_AVANCE2_ALG2301, + 0, + "Avance Logic (2nd PCI Vendor ID)", + "ALG2301", + }, + { + PCI_VENDOR_AVANCE2, PCI_PRODUCT_AVANCE2_ALG2302, + 0, + "Avance Logic (2nd PCI Vendor ID)", + "ALG2302", + }, + { + PCI_VENDOR_CCUBE, PCI_PRODUCT_CCUBE_CINEMASTER, + 0, + "C-Cube Microsystems", + "Cinemaster C 3.0 DVD Decoder", + }, + { + PCI_VENDOR_AVM, PCI_PRODUCT_AVM_FRITZ_CARD, + 0, + "AVM", + "Fritz! Card ISDN Interface", + }, + { + PCI_VENDOR_BIT3, PCI_PRODUCT_BIT3_PCIVME617, + 0, + "Bit3 Computer Corp.", + "PCI-VME Interface Mod. 617", + }, + { + PCI_VENDOR_BIT3, PCI_PRODUCT_BIT3_PCIVME618, + 0, + "Bit3 Computer Corp.", + "PCI-VME Interface Mod. 618", + }, + { + PCI_VENDOR_BIT3, PCI_PRODUCT_BIT3_PCIVME2706, + 0, + "Bit3 Computer Corp.", + "PCI-VME Interface Mod. 2706", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4211, + 0, + "Broadcom", + "BCM4211 iLine10 Controller", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4212, + 0, + "Broadcom", + "BCM4212 V.90 Modem", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5700, + 0, + "Broadcom", + "BCM5700 10/100/1000 Ethernet", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5701, + 0, + "Broadcom", + "BCM5701 10/100/1000 Ethernet", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5702, + 0, + "Broadcom", + "BCM5702 10/100/1000 Ethernet", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5703, + 0, + "Broadcom", + "BCM5703 10/100/1000 Ethernet", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5705, + 0, + "Broadcom", + "BCM5705 10/100/1000 Ethernet", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5820, + 0, + "Broadcom", + "BCM5820 eCommerce Processor", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5821, + 0, + "Broadcom", + "BCM5821 Super-eCommerce Processor", + }, + { + PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM5850, + 0, + "Broadcom", + "BCM5850 SSL/TLS Protocol Processor", + }, + { + PCI_VENDOR_BROOKTREE, PCI_PRODUCT_BROOKTREE_BT848, + 0, + "Brooktree", + "Bt848 Video Capture", + }, + { + PCI_VENDOR_BROOKTREE, PCI_PRODUCT_BROOKTREE_BT849, + 0, + "Brooktree", + "Bt849 Video Capture", + }, + { + PCI_VENDOR_BROOKTREE, PCI_PRODUCT_BROOKTREE_BT878, + 0, + "Brooktree", + "Bt878 Video Capture", + }, + { + PCI_VENDOR_BROOKTREE, PCI_PRODUCT_BROOKTREE_BT879, + 0, + "Brooktree", + "Bt879 Video Capture", + }, + { + PCI_VENDOR_BUSLOGIC, PCI_PRODUCT_BUSLOGIC_MULTIMASTER_NC, + 0, + "BusLogic", + "MultiMaster NC", + }, + { + PCI_VENDOR_BUSLOGIC, PCI_PRODUCT_BUSLOGIC_MULTIMASTER, + 0, + "BusLogic", + "MultiMaster", + }, + { + PCI_VENDOR_BUSLOGIC, PCI_PRODUCT_BUSLOGIC_FLASHPOINT, + 0, + "BusLogic", + "FlashPoint", + }, + { + PCI_VENDOR_C4T, PCI_PRODUCT_C4T_GPPCI, + 0, + "c't Magazin", + "GPPCI", + }, + { + PCI_VENDOR_CHIPS, PCI_PRODUCT_CHIPS_64310, + 0, + "Chips and Technologies", + "64310", + }, + { + PCI_VENDOR_CHIPS, PCI_PRODUCT_CHIPS_65545, + 0, + "Chips and Technologies", + "65545", + }, + { + PCI_VENDOR_CHIPS, PCI_PRODUCT_CHIPS_65548, + 0, + "Chips and Technologies", + "65548", + }, + { + PCI_VENDOR_CHIPS, PCI_PRODUCT_CHIPS_65550, + 0, + "Chips and Technologies", + "65550", + }, + { + PCI_VENDOR_CHIPS, PCI_PRODUCT_CHIPS_65554, + 0, + "Chips and Technologies", + "65554", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD7548, + 0, + "Cirrus Logic", + "CL-GD7548", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD5430, + 0, + "Cirrus Logic", + "CL-GD5430", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD5434_4, + 0, + "Cirrus Logic", + "CL-GD5434-4", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD5434_8, + 0, + "Cirrus Logic", + "CL-GD5434-8", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD5436, + 0, + "Cirrus Logic", + "CL-GD5436", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD5446, + 0, + "Cirrus Logic", + "CL-GD5446", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD5480, + 0, + "Cirrus Logic", + "CL-GD5480", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_PD6729, + 0, + "Cirrus Logic", + "CL-PD6729", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_PD6832, + 0, + "Cirrus Logic", + "CL-PD6832 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_PD6833, + 0, + "Cirrus Logic", + "CL-PD6833 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD7542, + 0, + "Cirrus Logic", + "CL-GD7542", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD7543, + 0, + "Cirrus Logic", + "CL-GD7543", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_GD7541, + 0, + "Cirrus Logic", + "CL-GD7541", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CL_CD4400, + 0, + "Cirrus Logic", + "CL-CD4400 Communications Controller", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CS4610, + 0, + "Cirrus Logic", + "CS4610 SoundFusion Audio Accelerator", + }, + { + PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CS4280, + 0, + "Cirrus Logic", + "CS4280 CrystalClear Audio Interface", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_640, + 0, + "CMD Technology", + "PCI0640", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_642, + 0, + "CMD Technology", + "PCI0642", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_643, + 0, + "CMD Technology", + "PCI0643", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_646, + 0, + "CMD Technology", + "PCI0646", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_647, + 0, + "CMD Technology", + "PCI0647", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_648, + 0, + "CMD Technology", + "PCI0648", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_649, + 0, + "CMD Technology", + "PCI0649", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_650A, + 0, + "CMD Technology", + "PCI0650A", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_670, + 0, + "CMD Technology", + "USB0670", + }, + { + PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_673, + 0, + "CMD Technology", + "USB0673", + }, + { + PCI_VENDOR_CMEDIA, PCI_PRODUCT_CMEDIA_CMI8338A, + 0, + "C-Media Electronics Inc", + "CMI8338A PCI Audio Device", + }, + { + PCI_VENDOR_CMEDIA, PCI_PRODUCT_CMEDIA_CMI8338B, + 0, + "C-Media Electronics Inc", + "CMI8338B PCI Audio Device", + }, + { + PCI_VENDOR_CMEDIA, PCI_PRODUCT_CMEDIA_CMI8738, + 0, + "C-Media Electronics Inc", + "CMI8738/C3DX PCI Audio Device", + }, + { + PCI_VENDOR_CMEDIA, PCI_PRODUCT_CMEDIA_HSP56, + 0, + "C-Media Electronics Inc", + "HSP56 Audiomodem Riser", + }, + { + PCI_VENDOR_COGENT, PCI_PRODUCT_COGENT_EM110TX, + 0, + "Cogent Data Technologies", + "EX110TX PCI Fast Ethernet Adapter", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_PCI_EISA_BRIDGE, + 0, + "Compaq", + "PCI-EISA Bridge", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_PCI_ISA_BRIDGE, + 0, + "Compaq", + "PCI-ISA Bridge", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX1, + 0, + "Compaq", + "Triflex Host-PCI Bridge", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX2, + 0, + "Compaq", + "Triflex Host-PCI Bridge", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_QVISION_V0, + 0, + "Compaq", + "QVision", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_QVISION_1280P, + 0, + "Compaq", + "QVision 1280/p", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_QVISION_V2, + 0, + "Compaq", + "QVision", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX4, + 0, + "Compaq", + "Triflex Host-PCI Bridge", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_USB, + 0, + "Compaq", + "USB Controller", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_SMART2P, + 0, + "Compaq", + "SMART2P RAID", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_N100TX, + 0, + "Compaq", + "Netelligent 10/100 TX", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_N10T, + 0, + "Compaq", + "Netelligent 10 T", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_IntNF3P, + 0, + "Compaq", + "Integrated NetFlex 3/P", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_DPNet100TX, + 0, + "Compaq", + "Dual Port Netelligent 10/100 TX", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_IntPL100TX, + 0, + "Compaq", + "ProLiant Integrated Netelligent 10/100 TX", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_DP4000, + 0, + "Compaq", + "Deskpro 4000 5233MMX", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_NF3P_BNC, + 0, + "Compaq", + "NetFlex 3/P w/ BNC", + }, + { + PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_NF3P, + 0, + "Compaq", + "NetFlex 3/P", + }, + { + PCI_VENDOR_COMPEX, PCI_PRODUCT_COMPEX_NE2KETHER, + 0, + "Compex", + "Ethernet", + }, + { + PCI_VENDOR_COMPEX, PCI_PRODUCT_COMPEX_RL100ATX, + 0, + "Compex", + "RL100-ATX 10/100 Ethernet", + }, + { + PCI_VENDOR_COMPEX, PCI_PRODUCT_COMPEX_RL100TX, + 0, + "Compex", + "RL100-TX 10/100 Ethernet", + }, + { + PCI_VENDOR_CONEXANT, PCI_PRODUCT_CONEXANT_SOFTK56, + 0, + "Conexant Systems", + "SoftK56 PCI Software Modem", + }, + { + PCI_VENDOR_CONTAQ, PCI_PRODUCT_CONTAQ_82C599, + 0, + "Contaq Microsystems", + "82C599 PCI-VLB Bridge", + }, + { + PCI_VENDOR_CONTAQ, PCI_PRODUCT_CONTAQ_82C693, + 0, + "Contaq Microsystems", + "82C693 PCI-ISA Bridge", + }, + { + PCI_VENDOR_COROLLARY, PCI_PRODUCT_COROLLARY_CBUSII_PCIB, + 0, + "Corrollary", + "\"C-Bus II\"-PCI Bridge", + }, + { + PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_SBLIVE, + 0, + "Creative Labs", + "SBLive! EMU 10000", + }, + { + PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_SBJOY, + 0, + "Creative Labs", + "PCI Gameport Joystick", + }, + { + PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_EV1938, + 0, + "Creative Labs", + "Ectiva 1938", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOMY_1, + 0, + "Cyclades", + "Cyclom-Y below 1M", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOMY_2, + 0, + "Cyclades", + "Cyclom-Y above 1M", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOM4Y_1, + 0, + "Cyclades", + "Cyclom-4Y below 1M", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOM4Y_2, + 0, + "Cyclades", + "Cyclom-4Y above 1M", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOM8Y_1, + 0, + "Cyclades", + "Cyclom-8Y below 1M", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOM8Y_2, + 0, + "Cyclades", + "Cyclom-8Y above 1M", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOMZ_1, + 0, + "Cyclades", + "Cyclom-Z below 1M", + }, + { + PCI_VENDOR_CYCLADES, PCI_PRODUCT_CYCLADES_CYCLOMZ_2, + 0, + "Cyclades", + "Cyclom-Z above 1M", + }, + { + PCI_VENDOR_DAVICOM, PCI_PRODUCT_DAVICOM_DM9102, + 0, + "Davicom Semiconductor", + "Davicom DM9102 10/100 Ethernet", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21050, + 0, + "Digital Equipment", + "DECchip 21050 PCI-PCI Bridge", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21040, + 0, + "Digital Equipment", + "DECchip 21040 Ethernet", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21030, + 0, + "Digital Equipment", + "DECchip 21030 (\"TGA\")", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_NVRAM, + 0, + "Digital Equipment", + "Zephyr NV-RAM", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_KZPSA, + 0, + "Digital Equipment", + "KZPSA", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21140, + 0, + "Digital Equipment", + "DECchip 21140 10/100 Ethernet", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_PBXGB, + 0, + "Digital Equipment", + "TGA2", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_DEFPA, + 0, + "Digital Equipment", + "DEFPA", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21041, + 0, + "Digital Equipment", + "DECchip 21041 Ethernet", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_DGLPB, + 0, + "Digital Equipment", + "DGLPB (\"OPPO\")", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21142, + 0, + "Digital Equipment", + "DECchip 21142/21143 10/100 Ethernet", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21052, + 0, + "Digital Equipment", + "DECchip 21052 PCI-PCI Bridge", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21150, + 0, + "Digital Equipment", + "DECchip 21150 PCI-PCI Bridge", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21152, + 0, + "Digital Equipment", + "DECchip 21152 PCI-PCI Bridge", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21153, + 0, + "Digital Equipment", + "DECchip 21153 PCI-PCI Bridge", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21154, + 0, + "Digital Equipment", + "DECchip 21154 PCI-PCI Bridge", + }, + { + PCI_VENDOR_DEC, PCI_PRODUCT_DEC_CPQ42XX, + 0, + "Digital Equipment", + "Compaq SMART RAID 42xx", + }, + { + PCI_VENDOR_DELTA, PCI_PRODUCT_DELTA_8139, + 0, + "Delta Electronics", + "8139 Ethernet", + }, + { + PCI_VENDOR_DIAMOND, PCI_PRODUCT_DIAMOND_VIPER, + 0, + "Diamond Computer Systems", + "Viper/PCI", + }, + { + PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DFE550TX, + 0, + "D-Link Systems", + "DFE-550TX 10/100 Ethernet", + }, + { + PCI_VENDOR_DPT, PCI_PRODUCT_DPT_SC_RAID, + 0, + "Distributed Processing Technology", + "SmartCache/SmartRAID", + }, + { + PCI_VENDOR_DPT, PCI_PRODUCT_DPT_RAID_I2O, + 0, + "Distributed Processing Technology", + "SmartRAID (I2O)", + }, + { + PCI_VENDOR_DPT, PCI_PRODUCT_DPT_MEMCTLR, + 0, + "Distributed Processing Technology", + "Memory Controller", + }, + { + PCI_VENDOR_DOLPHIN, PCI_PRODUCT_DOLPHIN_PCISCI, + 0, + "Dolphin Interconnect Solutions", + "PCI-SCI Bridge", + }, + { + PCI_VENDOR_DOMEX, PCI_PRODUCT_DOMEX_PCISCSI, + 0, + "Domex", + "DMX-3191D", + }, + { + PCI_VENDOR_ELSA, PCI_PRODUCT_ELSA_QS1PCI, + 0, + "Elsa", + "QuickStep 1000 ISDN card", + }, + { + PCI_VENDOR_EMULEX, PCI_PRODUCT_EMULEX_LPPFC, + 0, + "Emulex", + "\"Light Pulse\" FibreChannel adapter", + }, + { + PCI_VENDOR_ENSONIQ, PCI_PRODUCT_ENSONIQ_AUDIOPCI, + 0, + "Ensoniq", + "AudioPCI", + }, + { + PCI_VENDOR_ENSONIQ, PCI_PRODUCT_ENSONIQ_AUDIOPCI97, + 0, + "Ensoniq", + "AudioPCI 97", + }, + { + PCI_VENDOR_ENSONIQ, PCI_PRODUCT_ENSONIQ_CT5880, + 0, + "Ensoniq", + "CT5880", + }, + { + PCI_VENDOR_EPIGRAM, PCI_PRODUCT_EPIGRAM_BCM4210, + 0, + "Epigram", + "BCM4210 iLine10 Controller", + }, + { + PCI_VENDOR_ESSENTIAL, PCI_PRODUCT_ESSENTIAL_RR_HIPPI, + 0, + "Essential Communications", + "RoadRunner HIPPI Interface", + }, + { + PCI_VENDOR_ESSENTIAL, PCI_PRODUCT_ESSENTIAL_RR_GIGE, + 0, + "Essential Communications", + "RoadRunner Gig-E Interface", + }, + { + PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO1, + 0, + "ESS Technology Inc", + "Maestro 1 PCI Audio Accelerator", + }, + { + PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO2, + 0, + "ESS Technology Inc", + "Maestro 2 PCI Audio Accelerator", + }, + { + PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_SOLO1, + 0, + "ESS Technology Inc", + "Solo-1 PCI AudioDrive", + }, + { + PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO2E, + 0, + "ESS Technology Inc", + "Maestro 2E PCI Audio Accelerator", + }, + { + PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO3, + 0, + "ESS Technology Inc", + "Maestro 3 PCI Audio Accelerator", + }, + { + PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO3MODEM, + 0, + "ESS Technology Inc", + "Maestro 3 Modem", + }, + { + PCI_VENDOR_ESSTECH2, PCI_PRODUCT_ESSTECH2_MAESTRO1, + 0, + "ESS Technology Inc", + "Maestro 1 PCI Audio Accelerator", + }, + { + PCI_VENDOR_O2MICRO, PCI_PRODUCT_O2MICRO_OZ6832, + 0, + "O2 Micro Inc", + "OZ6832 CardBus Controller", + }, + { + PCI_VENDOR_ES, PCI_PRODUCT_ES_FREEDOM, + 0, + "Evans & Sutherland", + "Freedom PCI-GBus Interface", + }, + { + PCI_VENDOR_FORE, PCI_PRODUCT_FORE_PCA200, + 0, + "FORE Systems", + "ATM PCA-200", + }, + { + PCI_VENDOR_FORE, PCI_PRODUCT_FORE_PCA200E, + 0, + "FORE Systems", + "ATM PCA-200e", + }, + { + PCI_VENDOR_FORTEMEDIA, PCI_PRODUCT_FORTEMEDIA_FM801, + 0, + "Forte Media", + "Forte Media 801 Sound", + }, + { + PCI_VENDOR_FUTUREDOMAIN, PCI_PRODUCT_FUTUREDOMAIN_TMC_18C30, + 0, + "Future Domain", + "TMC-18C30 (36C70)", + }, + { + PCI_VENDOR_EFFICIENTNETS, PCI_PRODUCT_EFFICIENTNETS_ENI155PF, + 0, + "Efficent Networks", + "155P-MF1 ATM (FPGA)", + }, + { + PCI_VENDOR_EFFICIENTNETS, PCI_PRODUCT_EFFICIENTNETS_ENI155PA, + 0, + "Efficent Networks", + "155P-MF1 ATM (ASIC)", + }, + { + PCI_VENDOR_EFFICIENTNETS, PCI_PRODUCT_EFFICIENTNETS_ENI25P, + 0, + "Efficent Networks", + "SpeedStream ENI-25p", + }, + { + PCI_VENDOR_EFFICIENTNETS, PCI_PRODUCT_EFFICIENTNETS_SS3000, + 0, + "Efficent Networks", + "SpeedStream 3000", + }, + { + PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64010A, + 0, + "Galileo Technology", + "GT-64010A System Controller", + }, + { + PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64115, + 0, + "Galileo Technology", + "GT-64115 System Controller", + }, + { + PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64011, + 0, + "Galileo Technology", + "GT-64011 System Controller", + }, + { + PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64120, + 0, + "Galileo Technology", + "GT-64120 System Controller", + }, + { + PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64130, + 0, + "Galileo Technology", + "GT-64130 System Controller", + }, + { + PCI_VENDOR_HP, PCI_PRODUCT_HP_J2585A, + 0, + "Hewlett-Packard", + "J2585A", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_MCABRIDGE, + 0, + "IBM", + "MCA Bridge", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_ALTALITE, + 0, + "IBM", + "CPU Bridge - Alta Lite", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_ALTAMP, + 0, + "IBM", + "CPU Bridge - Alta MP", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_ISABRIDGE, + 0, + "IBM", + "ISA Bridge w/PnP", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_CPUBRIDGE, + 0, + "IBM", + "CPU Bridge", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_LANSTREAMER, + 0, + "IBM", + "Auto LANStreamer", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_GXT150P, + 0, + "IBM", + "GXT-150P 2D Accelerator", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_MCABRIDGE2, + 0, + "IBM", + "MCA Bridge", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_82351, + 0, + "IBM", + "82351 PCI-PCI Bridge", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID, + 0, + "IBM", + "ServeRAID", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_OLYMPIC, + 0, + "IBM", + "Token Ring", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_MIAMI, + 0, + "IBM", + "Miami/PCI", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_TURBOWAYS25, + 0, + "IBM", + "Turboways 25 ATM", + }, + { + PCI_VENDOR_IBM, PCI_PRODUCT_IBM_MPIC2, + 0, + "IBM", + "MPIC-II", + }, + { + PCI_VENDOR_IDT, PCI_PRODUCT_IDT_77201, + 0, + "IDT", + "77201/77211 ATM (\"NICStAR\")", + }, + { + PCI_VENDOR_INITIO, PCI_PRODUCT_INITIO_I920, + 0, + "Initio", + "INIC-920 SCSI", + }, + { + PCI_VENDOR_INITIO, PCI_PRODUCT_INITIO_I940, + 0, + "Initio", + "INIC-940 SCSI", + }, + { + PCI_VENDOR_INITIO, PCI_PRODUCT_INITIO_I935, + 0, + "Initio", + "INIC-935 SCSI", + }, + { + PCI_VENDOR_INITIO, PCI_PRODUCT_INITIO_I950, + 0, + "Initio", + "INIC-950 SCSI", + }, + { + PCI_VENDOR_IMS, PCI_PRODUCT_IMS_8849, + 0, + "Integrated Micro Solutions", + "8849", + }, + { + PCI_VENDOR_IMS, PCI_PRODUCT_IMS_TT128M, + 0, + "Integrated Micro Solutions", + "TwinTurbo 128M", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCEB, + 0, + "Intel", + "82375EB/SB PCI-EISA Bridge (PCEB)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_CDC, + 0, + "Intel", + "82424ZX Cache and DRAM controller (CDC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_SIO, + 0, + "Intel", + "82378ZB System I/O (SIO)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82426EX, + 0, + "Intel", + "82426EX PCI-to-ISA Bridge (PCIB)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCMC, + 0, + "Intel", + "82434LX/NX PCI, Cache and Memory Controller (PCMC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_IN_BUSINESS, + 0, + "Intel", + "InBusiness Fast Ethernet LAN Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82559ER, + 0, + "Intel", + "82559ER Fast Ethernet LAN Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82092AA, + 0, + "Intel", + "82092AA IDE controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_SAA7116, + 0, + "Intel", + "SAA7116", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82596, + 0, + "Intel", + "82596 LAN Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EEPRO100, + 0, + "Intel", + "EE Pro 100 10/100 Fast Ethernet", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EEPRO100S, + 0, + "Intel", + "EE Pro 100 Smart 10/100 Fast Ethernet", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82557, + 0, + "Intel", + "82557 Fast Ethernet LAN Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82437FX, + 0, + "Intel", + "82437FX System Controller (TSC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA, + 0, + "Intel", + "82371FB PCI-to-ISA Bridge (PIIX)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_IDE, + 0, + "Intel", + "82371FB IDE controller (PIIX)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX, + 0, + "Intel", + "82371MX Mobile PCI I/O IDE Xcelerator (MPIIX)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82437MX, + 0, + "Intel", + "82437MX Mobile System Controller (MTSC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82441FX, + 0, + "Intel", + "82441FX PCI and Memory Controller (PMC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82380AB, + 0, + "Intel", + "82380AB Mobile PCI-to-ISA Bridge (MISA)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82380FB, + 0, + "Intel", + "82380FB Mobile PCI-to-PCI Bridge (MPCI2)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82439HX, + 0, + "Intel", + "82439HX System Controller (TXC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC, + 0, + "Intel", + "82801AA LPC Interface Bridge", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_IDE, + 0, + "Intel", + "82801AA IDE Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_USB, + 0, + "Intel", + "82801AA USB Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_SMB, + 0, + "Intel", + "82801AA SMBus Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_ACA, + 0, + "Intel", + "82801AA AC-97 Audio Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_ACM, + 0, + "Intel", + "82801AA AC-97 PCI Modem", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_HPB, + 0, + "Intel", + "82801AA Hub-to-PCI Bridge", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_LPC, + 0, + "Intel", + "82801AB LPC Interface Bridge", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_IDE, + 0, + "Intel", + "82801AB IDE Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_USB, + 0, + "Intel", + "82801AB USB Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_SMB, + 0, + "Intel", + "82801AB SMBus Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_ACA, + 0, + "Intel", + "82801AB AC-97 Audio Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_ACM, + 0, + "Intel", + "82801AB AC-97 PCI Modem", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_HPB, + 0, + "Intel", + "82801AB Hub-to-PCI Bridge", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC, + 0, + "Intel", + "82801BA LPC Interface Bridge", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_USB1, + 0, + "Intel", + "82801BA USB Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_SMB, + 0, + "Intel", + "82801BA SMBus Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_USB2, + 0, + "Intel", + "82801BA USB Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_ACA, + 0, + "Intel", + "82801BA AC-97 Audio Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_ACM, + 0, + "Intel", + "82801BA AC-97 PCI Modem", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LAN, + 0, + "Intel", + "82801BA LAN Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_IDE, + 0, + "Intel", + "82801BA IDE Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_HPB, + 0, + "Intel", + "82801BA Hub-to-PCI Bridge", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA, + 0, + "Intel", + "82371SB PCI-to-ISA Bridge (PIIX3)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_IDE, + 0, + "Intel", + "82371SB IDE Interface (PIIX3)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_USB, + 0, + "Intel", + "82371SB USB Host Controller (PIIX3)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82437VX, + 0, + "Intel", + "82437VX System Controller (TVX)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82439TX, + 0, + "Intel", + "82439TX System Controller (MTXC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA, + 0, + "Intel", + "82371AB PCI-to-ISA Bridge (PIIX4)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_IDE, + 0, + "Intel", + "82371AB IDE controller (PIIX4)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_USB, + 0, + "Intel", + "82371AB USB Host Controller (PIIX4)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_PMC, + 0, + "Intel", + "82371AB Power Management Controller (PIIX4)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_MCH, + 0, + "Intel", + "82810 Memory Controller Hub", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_GC, + 0, + "Intel", + "82810 Graphics Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_DC100_MCH, + 0, + "Intel", + "82810-DC100 Memory Controller Hub", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_DC100_GC, + 0, + "Intel", + "82810-DC100 Graphics Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810E_MCH, + 0, + "Intel", + "82810E Memory Controller Hub", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810E_GC, + 0, + "Intel", + "82810E Graphics Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82443LX, + 0, + "Intel", + "82443LX PCI AGP Controller (PAC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82443LX_AGP, + 0, + "Intel", + "82443LX AGP Interface (PAC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82443BX, + 0, + "Intel", + "82443BX Host Bridge/Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82443BX_AGP, + 0, + "Intel", + "82443BX AGP Interface", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82443BX_NOAGP, + 0, + "Intel", + "82443BX Host Bridge/Controller (AGP disabled)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX, + 0, + "Intel", + "82440MX Host Bridge/Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_ACA, + 0, + "Intel", + "82440MX AC-97 Audio Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_ISA, + 0, + "Intel", + "82440MX PCI-to-ISA Bridge", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_IDE, + 0, + "Intel", + "82440MX IDE Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_USB, + 0, + "Intel", + "82440MX USB Host Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_PMC, + 0, + "Intel", + "82440MX Power Management Controller", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I740, + 0, + "Intel", + "i740 Graphics Accelerator", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCI450_PB, + 0, + "Intel", + "82454KX/GX PCI Bridge (PB)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PCI450_MC, + 0, + "Intel", + "82451KX/GX Memory Controller (MC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82451NX_MIOC, + 0, + "Intel", + "82451NX Memory & I/O Controller (MIOC)", + }, + { + PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82451NX_PXB, + 0, + "Intel", + "82451NX PCI Expander Bridge (PXB)", + }, + { + PCI_VENDOR_INTERGRAPH, PCI_PRODUCT_INTERGRAPH_4D50T, + 0, + "Intergraph", + "Powerstorm 4D50T", + }, + { + PCI_VENDOR_ITT, PCI_PRODUCT_ITT_AGX016, + 0, + "I. T. T.", + "AGX016", + }, + { + PCI_VENDOR_ITT, PCI_PRODUCT_ITT_ITT3204, + 0, + "I. T. T.", + "ITT3204 MPEG Decoder", + }, + { + PCI_VENDOR_KTI, PCI_PRODUCT_KTI_NE2KETHER, + 0, + "KTI", + "Ethernet", + }, + { + PCI_VENDOR_LMC, PCI_PRODUCT_LMC_HSSI, + 0, + "LAN Media Corporation", + "HSSI Interface", + }, + { + PCI_VENDOR_LMC, PCI_PRODUCT_LMC_DS3, + 0, + "LAN Media Corporation", + "DS3 Interface", + }, + { + PCI_VENDOR_LMC, PCI_PRODUCT_LMC_SSI, + 0, + "LAN Media Corporation", + "SSI", + }, + { + PCI_VENDOR_LEADTEK, PCI_PRODUCT_LEADTEK_S3_805, + 0, + "LeadTek Research", + "S3 805", + }, + { + PCI_VENDOR_LINEARSYS, PCI_PRODUCT_LINEARSYS_DVB_TX, + 0, + "Linear Systems", + "DVB Transmitter", + }, + { + PCI_VENDOR_LINEARSYS, PCI_PRODUCT_LINEARSYS_DVB_RX, + 0, + "Linear Systems", + "DVB Receiver", + }, + { + PCI_VENDOR_LITEON, PCI_PRODUCT_LITEON_82C168, + 0, + "Lite-On Communications", + "82C168/82C169 (PNIC) 10/100 Ethernet", + }, + { + PCI_VENDOR_LITEON, PCI_PRODUCT_LITEON_82C115, + 0, + "Lite-On Communications", + "82C115 (PNIC II) 10/100 Ethernet", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0440, + 0, + "AT&T Microelectronics", + "K56flex DSVD LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0441, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0442, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0443, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0444, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0445, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0446, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0447, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0448, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0449, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_044A, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_044B, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_044C, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_044D, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_044E, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0450, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0451, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0452, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0453, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0454, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0455, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0456, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0457, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0458, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_0459, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_LTMODEM_045A, + 0, + "AT&T Microelectronics", + "LTMODEM", + }, + { + PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_USBHC, + 0, + "AT&T Microelectronics", + "USB Host Controller", + }, + { + PCI_VENDOR_MACRONIX, PCI_PRODUCT_MACRONIX_MX98713, + 0, + "Macronix", + "MX98713 (PMAC) 10/100 Ethernet", + }, + { + PCI_VENDOR_MACRONIX, PCI_PRODUCT_MACRONIX_MX987x5, + 0, + "Macronix", + "MX987x5 (PMAC) 10/100 Ethernet", + }, + { + PCI_VENDOR_MADGE, PCI_PRODUCT_MADGE_COLLAGE25, + 0, + "Madge Networks", + "Collage 25 ATM adapter", + }, + { + PCI_VENDOR_MADGE, PCI_PRODUCT_MADGE_COLLAGE155, + 0, + "Madge Networks", + "Collage 155 ATM adapter", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_ATLAS, + 0, + "Matrox", + "MGA PX2085 (\"Atlas\")", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_MILLENNIUM, + 0, + "Matrox", + "MGA Millennium 2064W", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_MYSTIQUE, + 0, + "Matrox", + "MGA Mystique 1064SG", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_MILLENNIUM2, + 0, + "Matrox", + "MGA Millennium II 2164W", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_MILLENNIUM2_AGP, + 0, + "Matrox", + "MGA Millennium II 2164WA-B AG", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_G200_PCI, + 0, + "Matrox", + "MGA G200 PCI", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_G200_AGP, + 0, + "Matrox", + "MGA G200 AGP", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_G400_AGP, + 0, + "Matrox", + "MGA G400 AGP", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_IMPRESSION, + 0, + "Matrox", + "MGA Impression", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_G100_PCI, + 0, + "Matrox", + "MGA G100 PCI", + }, + { + PCI_VENDOR_MATROX, PCI_PRODUCT_MATROX_G100_AGP, + 0, + "Matrox", + "MGA G100 AGP", + }, + { + PCI_VENDOR_MOT, PCI_PRODUCT_MOT_MPC105, + 0, + "Motorola", + "MPC105 \"Eagle\" Host Bridge", + }, + { + PCI_VENDOR_MOT, PCI_PRODUCT_MOT_MPC106, + 0, + "Motorola", + "MPC106 \"Grackle\" Host Bridge", + }, + { + PCI_VENDOR_MYLEX, PCI_PRODUCT_MYLEX_960P, + 0, + "Mylex", + "DAC960P RAID controller", + }, + { + PCI_VENDOR_MUTECH, PCI_PRODUCT_MUTECH_MV1000, + 0, + "Mutech", + "MV1000", + }, + { + PCI_VENDOR_NETVIN, PCI_PRODUCT_NETVIN_5000, + 0, + "NetVin", + "5000 Ethernet", + }, + { + PCI_VENDOR_NEWBRIDGE, PCI_PRODUCT_NEWBRIDGE_CA91CX42, + 0, + "Newbridge Microsystems / Tundra Semiconductor", + "Universe VME bridge", + }, + { + PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83810, + 0, + "National Semiconductor", + "DP83810 10/100 Ethernet", + }, + { + PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815, + 0, + "National Semiconductor", + "DP83815 10/100 Ethernet", + }, + { + PCI_VENDOR_NS, PCI_PRODUCT_NS_NS87410, + 0, + "National Semiconductor", + "NS87410", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_810, + 0, + "Symbios Logic", + "53c810", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_820, + 0, + "Symbios Logic", + "53c820", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_825, + 0, + "Symbios Logic", + "53c825", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_815, + 0, + "Symbios Logic", + "53c815", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_810AP, + 0, + "Symbios Logic", + "53c810AP", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_860, + 0, + "Symbios Logic", + "53c860", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_896, + 0, + "Symbios Logic", + "53c896", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_895, + 0, + "Symbios Logic", + "53c895", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_885, + 0, + "Symbios Logic", + "53c885", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_875, + 0, + "Symbios Logic", + "53c875", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_1510, + 0, + "Symbios Logic", + "53c1510", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_875J, + 0, + "Symbios Logic", + "53c875J", + }, + { + PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_PE_GNIC, + 0, + "Symbios Logic", + "Packet Engines G-NIC Ethernet", + }, + { + PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB, + 0, + "NEC", + "USB Host Controller", + }, + { + PCI_VENDOR_NEC, PCI_PRODUCT_NEC_POWERVR2, + 0, + "NEC", + "PowerVR PCX2", + }, + { + PCI_VENDOR_NEC, PCI_PRODUCT_NEC_PD72872, + 0, + "NEC", + "uPD72872 IEEE 1394 OHCI Host Controller", + }, + { + PCI_VENDOR_NEC, PCI_PRODUCT_NEC_PD72870, + 0, + "NEC", + "uPD72870 IEEE 1394 OHCI Host Controller", + }, + { + PCI_VENDOR_NEC, PCI_PRODUCT_NEC_PD72871, + 0, + "NEC", + "uPD72871 IEEE 1394 OHCI Host Controller", + }, + { + PCI_VENDOR_NEOMAGIC, PCI_PRODUCT_NEOMAGIC_NMMG128ZV, + 0, + "Neomagic", + "MagicGraph 128ZV", + }, + { + PCI_VENDOR_NEOMAGIC, PCI_PRODUCT_NEOMAGIC_NMMG2160, + 0, + "Neomagic", + "MagicGraph 128XD", + }, + { + PCI_VENDOR_NEOMAGIC, PCI_PRODUCT_NEOMAGIC_NMMM256AV_VGA, + 0, + "Neomagic", + "MagicMedia 256AV VGA", + }, + { + PCI_VENDOR_NEOMAGIC, PCI_PRODUCT_NEOMAGIC_NMMM256ZX_VGA, + 0, + "Neomagic", + "MagicMedia 256ZX VGA", + }, + { + PCI_VENDOR_NEOMAGIC, PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU, + 0, + "Neomagic", + "MagicMedia 256AV Audio", + }, + { + PCI_VENDOR_NEOMAGIC, PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU, + 0, + "Neomagic", + "MagicMedia 256ZX Audio", + }, + { + PCI_VENDOR_NETGEAR, PCI_PRODUCT_NETGEAR_GA620, + 0, + "Netgear", + "GA620 Gigabit Ethernet", + }, + { + PCI_VENDOR_NEXGEN, PCI_PRODUCT_NEXGEN_NX82C501, + 0, + "NexGen Microsystems", + "NX82C501 Host-PCI Bridge", + }, + { + PCI_VENDOR_NKK, PCI_PRODUCT_NKK_NDR4600, + 0, + "NKK Corporation", + "NDR4600 Host-PCI Bridge", + }, + { + PCI_VENDOR_NUMBER9, PCI_PRODUCT_NUMBER9_I128, + 0, + "Number 9 Computer Company", + "Imagine-128", + }, + { + PCI_VENDOR_NUMBER9, PCI_PRODUCT_NUMBER9_I128_2, + 0, + "Number 9 Computer Company", + "Imagine-128 II", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_RIVATNT, + 0, + "Nvidia Corporation", + "RIVA TNT", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_RIVATNT2, + 0, + "Nvidia Corporation", + "RIVA TNT2", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_RIVATNT2U, + 0, + "Nvidia Corporation", + "RIVA TNT2 Ultra", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_VANTA, + 0, + "Nvidia Corporation", + "Vanta", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_RIVATNT2M64, + 0, + "Nvidia Corporation", + "RIVA TNT2 Model 64", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_ALADDINTNT2, + 0, + "Nvidia Corporation", + "Aladdin TNT2", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_GEFORCE256, + 0, + "Nvidia Corporation", + "GeForce 256", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_GEFORCEDDR, + 0, + "Nvidia Corporation", + "GeForce DDR", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_QUADRO, + 0, + "Nvidia Corporation", + "Quadro", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_GEFORCE2, + 0, + "Nvidia Corporation", + "GeForce2 GTS", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_GEFORCE2DDR, + 0, + "Nvidia Corporation", + "GeForce2 GTS (DDR)", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_GEFORCE2BR, + 0, + "Nvidia Corporation", + "GeForce2 GTS", + }, + { + PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_QUADRO2, + 0, + "Nvidia Corporation", + "Quadro2", + }, + { + PCI_VENDOR_NVIDIA_SGS, PCI_PRODUCT_NVIDIA_SGS_RIVA128, + 0, + "Nvidia Corporation & SGS Thomson Microelectric", + "Riva 128", + }, + { + PCI_VENDOR_OAKTECH, PCI_PRODUCT_OAKTECH_OTI1007, + 0, + "Oak Technology", + "OTI107", + }, + { + PCI_VENDOR_OLICOM, PCI_PRODUCT_OLICOM_OC2183, + 0, + "Olicom", + "Olicom OC-2183/2185 Ethernet", + }, + { + PCI_VENDOR_OLICOM, PCI_PRODUCT_OLICOM_OC2325, + 0, + "Olicom", + "Olicom OC-2325 Ethernet", + }, + { + PCI_VENDOR_OLICOM, PCI_PRODUCT_OLICOM_OC2326, + 0, + "Olicom", + "Olicom OC-2326 10/100-TX Ethernet", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C557, + 0, + "Opti", + "82C557", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558, + 0, + "Opti", + "82C558", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C568, + 0, + "Opti", + "82C568", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82D568, + 0, + "Opti", + "82D568", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C621, + 0, + "Opti", + "82C621", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C822, + 0, + "Opti", + "82C822", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_RM861HA, + 0, + "Opti", + "RM861HA", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700, + 0, + "Opti", + "82C700", + }, + { + PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C701, + 0, + "Opti", + "82C701", + }, + { + PCI_VENDOR_PCTECH, PCI_PRODUCT_PCTECH_RZ1000, + 0, + "PC Technology", + "RZ1000", + }, + { + PCI_VENDOR_PLX, PCI_PRODUCT_PLX_9060ES, + 0, + "PLX Technology", + "9060ES PCI bus controller", + }, + { + PCI_VENDOR_PROLAN, PCI_PRODUCT_PROLAN_NE2KETHER, + 0, + "ProLAN", + "Ethernet", + }, + { + PCI_VENDOR_PROMISE, PCI_PRODUCT_PROMISE_DC5030, + 0, + "Promise Technology", + "DC5030", + }, + { + PCI_VENDOR_PROMISE, PCI_PRODUCT_PROMISE_ULTRA33, + 0, + "Promise Technology", + "Ultra33/ATA Bus Master IDE Accelerator", + }, + { + PCI_VENDOR_PROMISE, PCI_PRODUCT_PROMISE_ULTRA66, + 0, + "Promise Technology", + "Ultra66/ATA Bus Master IDE Accelerator", + }, + { + PCI_VENDOR_PROMISE, PCI_PRODUCT_PROMISE_ULTRA100, + 0, + "Promise Technology", + "Ultra100/ATA Bus Master IDE Accelerator", + }, + { + PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP1020, + 0, + "Q Logic", + "ISP1020", + }, + { + PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP1022, + 0, + "Q Logic", + "ISP1022", + }, + { + PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP1080, + 0, + "Q Logic", + "ISP1080", + }, + { + PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP1240, + 0, + "Q Logic", + "ISP1240", + }, + { + PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2100, + 0, + "Q Logic", + "ISP2100", + }, + { + PCI_VENDOR_QUANTUMDESIGNS, PCI_PRODUCT_QUANTUMDESIGNS_8500, + 0, + "Quantum Designs", + "8500", + }, + { + PCI_VENDOR_QUANTUMDESIGNS, PCI_PRODUCT_QUANTUMDESIGNS_8580, + 0, + "Quantum Designs", + "8580", + }, + { + PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8029, + 0, + "Realtek Semiconductor", + "8029 Ethernet", + }, + { + PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8129, + 0, + "Realtek Semiconductor", + "8129 10/100 Ethernet", + }, + { + PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8139, + 0, + "Realtek Semiconductor", + "8139 10/100 Ethernet", + }, + { + PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C465, + 0, + "Ricoh", + "5C465 PCI-CardBus bridge", + }, + { + PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C466, + 0, + "Ricoh", + "5C466 PCI-CardBus bridge", + }, + { + PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C475, + 0, + "Ricoh", + "5C475 PCI-CardBus bridge", + }, + { + PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_RL5C476, + 0, + "Ricoh", + "5C476 PCI-CardBus bridge", + }, + { + PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C477, + 0, + "Ricoh", + "5C477 PCI-CardBus bridge", + }, + { + PCI_VENDOR_RICOH, PCI_PRODUCT_RICOH_Rx5C478, + 0, + "Ricoh", + "5C478 PCI-CardBus bridge", + }, + { + PCI_VENDOR_RISCOM, PCI_PRODUCT_RISCOM_N2, + 0, + "RISCom", + "N2", + }, + { + PCI_VENDOR_RNS, PCI_PRODUCT_RNS_FDDI, + 0, + "RNS", + "2200 FDDI", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE, + 0, + "S3", + "ViRGE", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_TRIO32, + 0, + "S3", + "Trio32", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_TRIO64, + 0, + "S3", + "Trio32/64", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_AURORA64P, + 0, + "S3", + "Aurora64V+", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_TRIO64UVP, + 0, + "S3", + "Trio64UV+", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE_VX, + 0, + "S3", + "ViRGE/VX", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_868, + 0, + "S3", + "868", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_928, + 0, + "S3", + "86C928", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_864_0, + 0, + "S3", + "86C864-0", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_864_1, + 0, + "S3", + "86C864-1", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_864_2, + 0, + "S3", + "86C864-2", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_864_3, + 0, + "S3", + "86C864-3", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_964_0, + 0, + "S3", + "86C964-0", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_964_1, + 0, + "S3", + "86C964-1", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_964_2, + 0, + "S3", + "86C964-2", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_964_3, + 0, + "S3", + "86C964-3", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_968_0, + 0, + "S3", + "86C968-0", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_968_1, + 0, + "S3", + "86C968-1", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_968_2, + 0, + "S3", + "86C968-2", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_968_3, + 0, + "S3", + "86C968-3", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_TRIO64V2_DX, + 0, + "S3", + "Trio64V2/DX", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_PLATO_PX, + 0, + "S3", + "Plato/PX", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_TRIO3D, + 0, + "S3", + "86C365 Trio3D", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE_DX, + 0, + "S3", + "ViRGE/DX", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE_GX2, + 0, + "S3", + "ViRGE/GX2", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_TRIO3D2X, + 0, + "S3", + "Trio3D/2X", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE3D, + 0, + "S3", + "Savage3D", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE3D_MV, + 0, + "S3", + "Savage3D+MV", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE4, + 0, + "S3", + "Savage4", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE_MX, + 0, + "S3", + "ViRGE/MX", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE_MXP, + 0, + "S3", + "ViRGE/MXP", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE_MX_MV, + 0, + "S3", + "Savage/MX+MV", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE_MX, + 0, + "S3", + "Savage/MX", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE_IX_MV, + 0, + "S3", + "Savage/IX+MV", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE_IX, + 0, + "S3", + "Savage/IX", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SAVAGE2000, + 0, + "S3", + "Savage2000", + }, + { + PCI_VENDOR_S3, PCI_PRODUCT_S3_SONICVIBES, + 0, + "S3", + "SonicVibes", + }, + { + PCI_VENDOR_SAMSUNGSEMI, PCI_PRODUCT_SAMSUNGSEMI_KS8920, + 0, + "Samsung Semiconductors", + "KS8920 10/100 Ethernet", + }, + { + PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3, + 0, + "Silicon Graphics", + "IOC3", + }, + { + PCI_VENDOR_SGI, PCI_PRODUCT_SGI_RAD1, + 0, + "Silicon Graphics", + "PsiTech RAD1", + }, + { + PCI_VENDOR_SGI, PCI_PRODUCT_SGI_TIGON, + 0, + "Silicon Graphics", + "Tigon Gigabit Ethernet", + }, + { + PCI_VENDOR_SGSTHOMSON, PCI_PRODUCT_SGSTHOMSON_2000, + 0, + "SGS Thomson Microelectric", + "STG 2000X", + }, + { + PCI_VENDOR_SGSTHOMSON, PCI_PRODUCT_SGSTHOMSON_1764, + 0, + "SGS Thomson Microelectric", + "STG 1764X", + }, + { + PCI_VENDOR_SIBYTE, PCI_PRODUCT_SIBYTE_SB1250_PCI, + 0, + "SiByte, Inc.", + "BCM1250 PCI Host Bridge", + }, + { + PCI_VENDOR_SIBYTE, PCI_PRODUCT_SIBYTE_SB1250_LDT, + 0, + "SiByte, Inc.", + "BCM1250 HyperTransport Host Bridge", + }, + { + PCI_VENDOR_SIGMA, PCI_PRODUCT_SIGMA_HOLLYWOODPLUS, + 0, + "Sigma Designs", + "REALmagic Hollywood-Plus MPEG-2 Decoder", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_86C201, + 0, + "Silicon Integrated System", + "86C201", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_86C202, + 0, + "Silicon Integrated System", + "86C202", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_86C205, + 0, + "Silicon Integrated System", + "86C205", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, + 0, + "Silicon Integrated System", + "85C503 or 5597/5598 ISA bridge", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_600PMC, + 0, + "Silicon Integrated System", + "600 Power Mngmt Controller", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_5597_VGA, + 0, + "Silicon Integrated System", + "5597/5598 integrated VGA", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C501, + 0, + "Silicon Integrated System", + "85C501", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C496, + 0, + "Silicon Integrated System", + "85C496", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_530HB, + 0, + "Silicon Integrated System", + "530 Host to PCI Bridge", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C601, + 0, + "Silicon Integrated System", + "85C601", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_900, + 0, + "Silicon Integrated System", + "SiS 900 10/100 Ethernet", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_5597_IDE, + 0, + "Silicon Integrated System", + "5597/5598 IDE controller", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_5597_HB, + 0, + "Silicon Integrated System", + "5597/5598 host bridge", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_530VGA, + 0, + "Silicon Integrated System", + "530 GUI Accelerator+3D", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_6326, + 0, + "Silicon Integrated System", + "6326 AGP VGA", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_5597_USB, + 0, + "Silicon Integrated System", + "5597/5598 USB host controller", + }, + { + PCI_VENDOR_SIS, PCI_PRODUCT_SIS_7016, + 0, + "Silicon Integrated System", + "SiS 7016 10/100 Ethernet", + }, + { + PCI_VENDOR_SILMOTION, PCI_PRODUCT_SILMOTION_LYNX_E, + 0, + "Silicon Motion", + "Lynx E", + }, + { + PCI_VENDOR_SMC, PCI_PRODUCT_SMC_37C665, + 0, + "Standard Microsystems", + "FDC 37C665", + }, + { + PCI_VENDOR_SMC, PCI_PRODUCT_SMC_37C922, + 0, + "Standard Microsystems", + "FDC 37C922", + }, + { + PCI_VENDOR_SMC, PCI_PRODUCT_SMC_83C170, + 0, + "Standard Microsystems", + "83C170 (\"EPIC/100\") Fast Ethernet", + }, + { + PCI_VENDOR_SMC, PCI_PRODUCT_SMC_83C175, + 0, + "Standard Microsystems", + "83C175 (\"EPIC/100\") Fast Ethernet", + }, + { + PCI_VENDOR_SOLIDUM, PCI_PRODUCT_SOLIDUM_AMD971, + 0, + "Solidum Systems Corp.", + "SNP8023: AMD 971", + }, + { + PCI_VENDOR_SOLIDUM, PCI_PRODUCT_SOLIDUM_CLASS802, + 0, + "Solidum Systems Corp.", + "SNP8023: Classifier Engine", + }, + { + PCI_VENDOR_SONY, PCI_PRODUCT_SONY_CXD1947A, + 0, + "Sony", + "CXD1947A IEEE 1394 Host Controller", + }, + { + PCI_VENDOR_SONY, PCI_PRODUCT_SONY_CXD32222, + 0, + "Sony", + "CXD3222 OHCI IEEE 1394 Host Controller", + }, + { + PCI_VENDOR_SONY, PCI_PRODUCT_SONY_MEMSTICK, + 0, + "Sony", + "Memory Stick I/F Controller", + }, + { + PCI_VENDOR_SUN, PCI_PRODUCT_SUN_EBUS, + 0, + "Sun Microsystems", + "PCIO Ebus2", + }, + { + PCI_VENDOR_SUN, PCI_PRODUCT_SUN_HMENETWORK, + 0, + "Sun Microsystems", + "PCIO Happy Meal Ethernet", + }, + { + PCI_VENDOR_SUN, PCI_PRODUCT_SUN_SIMBA, + 0, + "Sun Microsystems", + "Simba PCI bridge", + }, + { + PCI_VENDOR_SUN, PCI_PRODUCT_SUN_MS_IIep, + 0, + "Sun Microsystems", + "microSPARC IIep PCI", + }, + { + PCI_VENDOR_SUN, PCI_PRODUCT_SUN_US_IIi, + 0, + "Sun Microsystems", + "UltraSPARC IIi PCI", + }, + { + PCI_VENDOR_SUNDANCETI, PCI_PRODUCT_SUNDANCETI_ST201, + 0, + "Sundance Technology", + "ST201 10/100 Ethernet", + }, + { + PCI_VENDOR_SURECOM, PCI_PRODUCT_SURECOM_NE34, + 0, + "Surecom Technology", + "NE-34 Ethernet", + }, + { + PCI_VENDOR_SYMPHONY, PCI_PRODUCT_SYMPHONY_82C101, + 0, + "Symphony Labs", + "82C101", + }, + { + PCI_VENDOR_SYMPHONY, PCI_PRODUCT_SYMPHONY_82C103, + 0, + "Symphony Labs", + "82C103", + }, + { + PCI_VENDOR_SYMPHONY, PCI_PRODUCT_SYMPHONY_82C105, + 0, + "Symphony Labs", + "82C105", + }, + { + PCI_VENDOR_SYMPHONY2, PCI_PRODUCT_SYMPHONY2_82C101, + 0, + "Symphony Labs (2nd PCI Vendor ID)", + "82C101", + }, + { + PCI_VENDOR_SYMPHONY, PCI_PRODUCT_SYMPHONY_83C553, + 0, + "Symphony Labs", + "83C553 PCI-ISA Bridge", + }, + { + PCI_VENDOR_SCHNEIDERKOCH, PCI_PRODUCT_SCHNEIDERKOCH_SKNET_FDDI, + 0, + "Schneider & Koch", + "SK-NET FDDI-xP", + }, + { + PCI_VENDOR_TEKRAM, PCI_PRODUCT_TEKRAM_DC290, + 0, + "Tekram Technology (1st PCI Vendor ID)", + "DC-290(M)", + }, + { + PCI_VENDOR_TEKRAM2, PCI_PRODUCT_TEKRAM2_DC690C, + 0, + "Tekram Technology (2nd PCI Vendor ID)", + "DC-690C", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_TLAN, + 0, + "Texas Instruments", + "TLAN", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_TVP4020, + 0, + "Texas Instruments", + "TVP4020 Permedia 2", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_TSB12LV21, + 0, + "Texas Instruments", + "TSB12LV21 IEEE 1394 Host Controller", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_TSB12LV22, + 0, + "Texas Instruments", + "TSB12LV22 OHCI IEEE 1394 Host Controller", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_TSB12LV23, + 0, + "Texas Instruments", + "TSB12LV23 OHCI IEEE 1394 Host Controller", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_TSB12LV26, + 0, + "Texas Instruments", + "TSB12LV26 OHCI IEEE 1394 Host Controller", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1130, + 0, + "Texas Instruments", + "PCI1130 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1031, + 0, + "Texas Instruments", + "PCI1031 PCI-PCMCIA Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1131, + 0, + "Texas Instruments", + "PCI1131 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1250, + 0, + "Texas Instruments", + "PCI1250 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1220, + 0, + "Texas Instruments", + "PCI1220 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1221, + 0, + "Texas Instruments", + "PCI1221 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1450, + 0, + "Texas Instruments", + "PCI1450 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1225, + 0, + "Texas Instruments", + "PCI1225 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1251, + 0, + "Texas Instruments", + "PCI1251 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1211, + 0, + "Texas Instruments", + "PCI1211 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1251B, + 0, + "Texas Instruments", + "PCI1251B PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI2030, + 0, + "Texas Instruments", + "PCI2030 PCI-PCI Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1420, + 0, + "Texas Instruments", + "PCI1420 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TI, PCI_PRODUCT_TI_PCI1451, + 0, + "Texas Instruments", + "PCI1451 PCI-CardBus Bridge", + }, + { + PCI_VENDOR_TOSHIBA, PCI_PRODUCT_TOSHIBA_R4X00, + 0, + "Toshiba America", + "R4x00 Host-PCI Bridge", + }, + { + PCI_VENDOR_TOSHIBA, PCI_PRODUCT_TOSHIBA_TC35856F, + 0, + "Toshiba America", + "TC35856F ATM (\"Meteor\")", + }, + { + PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_HOST, + 0, + "Toshiba America Info Systems", + "Host Bridge/Controller", + }, + { + PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ISA, + 0, + "Toshiba America Info Systems", + "ISA Bridge", + }, + { + PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95, + 0, + "Toshiba America Info Systems", + "ToPIC95 CardBus-PCI Bridge", + }, + { + PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC95B, + 0, + "Toshiba America Info Systems", + "ToPIC95B CardBus-PCI Bridge", + }, + { + PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC97, + 0, + "Toshiba America Info Systems", + "ToPIC97 CardBus-PCI Bridge", + }, + { + PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_ToPIC100, + 0, + "Toshiba America Info Systems", + "ToPIC100 CardBus-PCI Bridge", + }, + { + PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_FIRO, + 0, + "Toshiba America Info Systems", + "Fast Infrared Type O", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_CYBERBLADE_I7, + 0, + "Trident Microsystems", + "CyberBlade i7", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9320, + 0, + "Trident Microsystems", + "TGUI 9320", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9350, + 0, + "Trident Microsystems", + "TGUI 9350", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9360, + 0, + "Trident Microsystems", + "TGUI 9360", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_CYBER_9397, + 0, + "Trident Microsystems", + "CYBER 9397", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_CYBER_9397DVD, + 0, + "Trident Microsystems", + "CYBER 9397DVD", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_CYBER_9525, + 0, + "Trident Microsystems", + "CYBER 9525", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9420, + 0, + "Trident Microsystems", + "TGUI 9420", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9440, + 0, + "Trident Microsystems", + "TGUI 9440", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9660, + 0, + "Trident Microsystems", + "TGUI 9660", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9680, + 0, + "Trident Microsystems", + "TGUI 9680", + }, + { + PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_TGUI_9682, + 0, + "Trident Microsystems", + "TGUI 9682", + }, + { + PCI_VENDOR_TRIONES, PCI_PRODUCT_TRIONES_HPT366, + 0, + "Triones Technologies", + "HPT366/370 IDE Controller", + }, + { + PCI_VENDOR_TRITECH, PCI_PRODUCT_TRITECH_TR25202, + 0, + "TriTech Microelectronics", + "Pyramid3D TR25202", + }, + { + PCI_VENDOR_TSENG, PCI_PRODUCT_TSENG_ET4000_W32P_A, + 0, + "Tseng Labs", + "ET4000w32p rev A", + }, + { + PCI_VENDOR_TSENG, PCI_PRODUCT_TSENG_ET4000_W32P_B, + 0, + "Tseng Labs", + "ET4000w32p rev B", + }, + { + PCI_VENDOR_TSENG, PCI_PRODUCT_TSENG_ET4000_W32P_C, + 0, + "Tseng Labs", + "ET4000w32p rev C", + }, + { + PCI_VENDOR_TSENG, PCI_PRODUCT_TSENG_ET4000_W32P_D, + 0, + "Tseng Labs", + "ET4000w32p rev D", + }, + { + PCI_VENDOR_TSENG, PCI_PRODUCT_TSENG_ET6000, + 0, + "Tseng Labs", + "ET6000", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM82C881, + 0, + "United Microelectronics", + "UM82C881 486 Chipset", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM82C886, + 0, + "United Microelectronics", + "UM82C886 ISA Bridge", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8673F, + 0, + "United Microelectronics", + "UM8673F EIDE Controller", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8881, + 0, + "United Microelectronics", + "UM8881 HB4 486 PCI Chipset", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM82C891, + 0, + "United Microelectronics", + "UM82C891", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM886A, + 0, + "United Microelectronics", + "UM886A", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8886BF, + 0, + "United Microelectronics", + "UM8886BF", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8710, + 0, + "United Microelectronics", + "UM8710", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8886, + 0, + "United Microelectronics", + "UM8886", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8881F, + 0, + "United Microelectronics", + "UM8881F PCI-Host bridge", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8886F, + 0, + "United Microelectronics", + "UM8886F PCI-ISA bridge", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8886A, + 0, + "United Microelectronics", + "UM8886A", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8891A, + 0, + "United Microelectronics", + "UM8891A", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM9017F, + 0, + "United Microelectronics", + "UM9017F", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8886N, + 0, + "United Microelectronics", + "UM8886N", + }, + { + PCI_VENDOR_UMC, PCI_PRODUCT_UMC_UM8891N, + 0, + "United Microelectronics", + "UM8891N", + }, + { + PCI_VENDOR_ULSI, PCI_PRODUCT_ULSI_US201, + 0, + "ULSI Systems", + "US201", + }, + { + PCI_VENDOR_USR, PCI_PRODUCT_USR_3CP5609, + 0, + "US Robotics (3Com)", + "3CP5609 PCI 16550 Modem", + }, + { + PCI_VENDOR_V3, PCI_PRODUCT_V3_V292PBC, + 0, + "V3 Semiconductor", + "V292PBC AMD290x0 Host-PCI Bridge", + }, + { + PCI_VENDOR_V3, PCI_PRODUCT_V3_V960PBC, + 0, + "V3 Semiconductor", + "V960PBC i960 Host-PCI Bridge", + }, + { + PCI_VENDOR_V3, PCI_PRODUCT_V3_V96DPC, + 0, + "V3 Semiconductor", + "V96DPC i960 (Dual) Host-PCI Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8371_HB, + 0, + "VIA Technologies", + "VT8371 (Apollo KX133) Host Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8501_MVP4, + 0, + "VIA Technologies", + "VT8501 MVP4 System Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C505, + 0, + "VIA Technologies", + "VT82C505 (Pluto)", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C561, + 0, + "VIA Technologies", + "VT82C561", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586A_IDE, + 0, + "VIA Technologies", + "VT82C586A IDE Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C576, + 0, + "VIA Technologies", + "VT82C576 3V", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C580VP, + 0, + "VIA Technologies", + "VT82C580 (Apollo VP) Host-PCI Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA, + 0, + "VIA Technologies", + "VT82C586 (Apollo VP) PCI-ISA Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C595, + 0, + "VIA Technologies", + "VT82C595 (Apollo VP2) Host-PCI Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596A, + 0, + "VIA Technologies", + "VT82C596A (Apollo Pro) PCI-ISA Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C597, + 0, + "VIA Technologies", + "VT82C597 (Apollo VP3) Host-PCI Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C598PCI, + 0, + "VIA Technologies", + "VT82C598 (Apollo MVP3) Host-PCI", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_ISA, + 0, + "VIA Technologies", + "VT82C686A (Apollo KX133) PCI-ISA Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C691, + 0, + "VIA Technologies", + "VT82C691 (Apollo Pro) Host-PCI", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C693, + 0, + "VIA Technologies", + "VT82C693 (Apollo Pro Plus) Host-PCI", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT86C926, + 0, + "VIA Technologies", + "VT86C926 Amazon PCI-Ethernet Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C570M, + 0, + "VIA Technologies", + "VT82C570M (Apollo) Host-PCI Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C570MV, + 0, + "VIA Technologies", + "VT82C570M (Apollo) PCI-ISA Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_IDE, + 0, + "VIA Technologies", + "VT82C586 (Apollo VP) IDE Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C595_2, + 0, + "VIA Technologies", + "VT82C595 (Apollo VP2) Host-PCI Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT83C572, + 0, + "VIA Technologies", + "VT83C572 USB Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_PWR, + 0, + "VIA Technologies", + "VT82C586 (Apollo VP) Power Management Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT3043, + 0, + "VIA Technologies", + "VT3043 (Rhine) 10/100 Ethernet", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_SMB, + 0, + "VIA Technologies", + "VT82C686A SMBus Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_AC97, + 0, + "VIA Technologies", + "VT82C686A AC-97 Audio Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_MC97, + 0, + "VIA Technologies", + "VT82C686A MC-97 Modem Controller", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT86C100A, + 0, + "VIA Technologies", + "VT86C100A (Rhine-II) 10/100 Ethernet", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8371_PPB, + 0, + "VIA Technologies", + "VT8371 (Apollo KX133) PCI-PCI Bridge", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8501AGP, + 0, + "VIA Technologies", + "VT8501 PCI-AGP", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C597AGP, + 0, + "VIA Technologies", + "VT82C597 (Apollo VP3) PCI-AGP", + }, + { + PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C598AGP, + 0, + "VIA Technologies", + "VT82C598 (Apollo MVP3) PCI-AGP", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_60x0, + 0, + "Vortex Computer Systems", + "GDT6000/6020/6050", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6000B, + 0, + "Vortex Computer Systems", + "GDT6000B/6010", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x10, + 0, + "Vortex Computer Systems", + "GDT6110/6510", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x20, + 0, + "Vortex Computer Systems", + "GDT6120/6520", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6530, + 0, + "Vortex Computer Systems", + "GDT6530", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6550, + 0, + "Vortex Computer Systems", + "GDT6550", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x17, + 0, + "Vortex Computer Systems", + "GDT6117/6517", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x27, + 0, + "Vortex Computer Systems", + "GDT6127/6527", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6537, + 0, + "Vortex Computer Systems", + "GDT6537", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6557, + 0, + "Vortex Computer Systems", + "GDT6557/6557-ECC", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x15, + 0, + "Vortex Computer Systems", + "GDT6115/6515", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x25, + 0, + "Vortex Computer Systems", + "GDT6125/6525", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6535, + 0, + "Vortex Computer Systems", + "GDT6535", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6555, + 0, + "Vortex Computer Systems", + "GDT6555/6555-ECC", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x17RP, + 0, + "Vortex Computer Systems", + "GDT6117RP/GDT6517RP", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x27RP, + 0, + "Vortex Computer Systems", + "GDT6127RP/GDT6527RP", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6537RP, + 0, + "Vortex Computer Systems", + "GDT6537RP", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6557RP, + 0, + "Vortex Computer Systems", + "GDT6557RP", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x11RP, + 0, + "Vortex Computer Systems", + "GDT6111RP/GDT6511RP", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x21RP, + 0, + "Vortex Computer Systems", + "GDT6121RP/GDT6521RP", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x17RD, + 0, + "Vortex Computer Systems", + "GDT6117RD/GDT6517RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x27RD, + 0, + "Vortex Computer Systems", + "GDT6127RD/GDT6527RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6537RD, + 0, + "Vortex Computer Systems", + "GDT6537RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6557RD, + 0, + "Vortex Computer Systems", + "GDT6557RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x11RD, + 0, + "Vortex Computer Systems", + "GDT6111RD/GDT6511RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x21RD, + 0, + "Vortex Computer Systems", + "GDT6121RD/GDT6521RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x18RD, + 0, + "Vortex Computer Systems", + "GDT6118RD/GDT6518RD/GDT6618RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x28RD, + 0, + "Vortex Computer Systems", + "GDT6128RD/GDT6528RD/GDT6628RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x38RD, + 0, + "Vortex Computer Systems", + "GDT6538RD/GDT6638RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x58RD, + 0, + "Vortex Computer Systems", + "GDT6558RD/GDT6658RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x18RN, + 0, + "Vortex Computer Systems", + "GDT7118RN/GDT7518RN/GDT7618RN", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x28RN, + 0, + "Vortex Computer Systems", + "GDT7128RN/GDT7528RN/GDT7628RN", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x38RN, + 0, + "Vortex Computer Systems", + "GDT7538RN/GDT7638RN", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x58RN, + 0, + "Vortex Computer Systems", + "GDT7558RN/GDT7658RN", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x19RD, + 0, + "Vortex Computer Systems", + "GDT6519RD/GDT6619RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x29RD, + 0, + "Vortex Computer Systems", + "GDT6529RD/GDT6629RD", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x19RN, + 0, + "Vortex Computer Systems", + "GDT7519RN/GDT7619RN", + }, + { + PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x29RN, + 0, + "Vortex Computer Systems", + "GDT7529RN/GDT7629RN", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C592, + 0, + "VLSI Technology", + "82C592 CPU Bridge", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C593, + 0, + "VLSI Technology", + "82C593 ISA Bridge", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C594, + 0, + "VLSI Technology", + "82C594 Wildcat System Controller", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C596597, + 0, + "VLSI Technology", + "82C596/597 Wildcat ISA Bridge", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C541, + 0, + "VLSI Technology", + "82C541", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C543, + 0, + "VLSI Technology", + "82C543", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C532, + 0, + "VLSI Technology", + "82C532", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C534, + 0, + "VLSI Technology", + "82C534", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C535, + 0, + "VLSI Technology", + "82C535", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C147, + 0, + "VLSI Technology", + "82C147", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C975, + 0, + "VLSI Technology", + "82C975", + }, + { + PCI_VENDOR_VLSI, PCI_PRODUCT_VLSI_82C925, + 0, + "VLSI Technology", + "82C925", + }, + { + PCI_VENDOR_WEITEK, PCI_PRODUCT_WEITEK_P9000, + 0, + "Weitek", + "P9000", + }, + { + PCI_VENDOR_WEITEK, PCI_PRODUCT_WEITEK_P9100, + 0, + "Weitek", + "P9100", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_WD33C193A, + 0, + "Western Digital", + "WD33C193A", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_WD33C196A, + 0, + "Western Digital", + "WD33C196A", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_WD33C197A, + 0, + "Western Digital", + "WD33C197A", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_WD7193, + 0, + "Western Digital", + "WD7193", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_WD7197, + 0, + "Western Digital", + "WD7197", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_WD33C296A, + 0, + "Western Digital", + "WD33C296A", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_WD34C296, + 0, + "Western Digital", + "WD34C296", + }, + { + PCI_VENDOR_WD, PCI_PRODUCT_WD_90C, + 0, + "Western Digital", + "90C", + }, + { + PCI_VENDOR_WINBOND, PCI_PRODUCT_WINBOND_W83769F, + 0, + "Winbond Electronics", + "W83769F", + }, + { + PCI_VENDOR_WINBOND, PCI_PRODUCT_WINBOND_W89C840F, + 0, + "Winbond Electronics", + "W89C840F 10/100 Ethernet", + }, + { + PCI_VENDOR_WINBOND, PCI_PRODUCT_WINBOND_W89C940F, + 0, + "Winbond Electronics", + "W89C940F Ethernet", + }, + { + PCI_VENDOR_WINBOND, PCI_PRODUCT_WINBOND_W89C940F_1, + 0, + "Winbond Electronics", + "W89C940F Ethernet", + }, + { + PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_X3201_3, + 0, + "Xircom", + "X3201-3 Fast Ethernet Controller", + }, + { + PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_X3201_3_21143, + 0, + "Xircom", + "X3201-3 Fast Ethernet Controller (21143)", + }, + { + PCI_VENDOR_YAMAHA, PCI_PRODUCT_YAMAHA_YMF724, + 0, + "Yamaha", + "724 Audio", + }, + { + PCI_VENDOR_YAMAHA, PCI_PRODUCT_YAMAHA_YMF740, + 0, + "Yamaha", + "740 Audio", + }, + { + PCI_VENDOR_YAMAHA, PCI_PRODUCT_YAMAHA_YMF740C, + 0, + "Yamaha", + "740C (DS-1) Audio", + }, + { + PCI_VENDOR_YAMAHA, PCI_PRODUCT_YAMAHA_YMF724F, + 0, + "Yamaha", + "724F (DS-1) Audio", + }, + { + PCI_VENDOR_YAMAHA, PCI_PRODUCT_YAMAHA_YMF744B, + 0, + "Yamaha", + "744 (DS-1S) Audio", + }, + { + PCI_VENDOR_YAMAHA, PCI_PRODUCT_YAMAHA_YMF754, + 0, + "Yamaha", + "754 (DS-1E) Audio", + }, + { + PCI_VENDOR_ZEINET, PCI_PRODUCT_ZEINET_1221, + 0, + "Zeinet", + "1221", + }, + { + PCI_VENDOR_ZIATECH, PCI_PRODUCT_ZIATECH_ZT8905, + 0, + "Ziatech", + "PCI-ST32 Bridge", + }, + { + PCI_VENDOR_ZORAN, PCI_PRODUCT_ZORAN_ZR36120, + 0, + "Zoran Corporation", + "Video Controller", + }, + { + PCI_VENDOR_COMPAQ, 0, + PCI_KNOWNDEV_NOPROD, + "Compaq", + NULL, + }, + { + PCI_VENDOR_SYMBIOS, 0, + PCI_KNOWNDEV_NOPROD, + "Symbios Logic", + NULL, + }, + { + PCI_VENDOR_ATI, 0, + PCI_KNOWNDEV_NOPROD, + "ATI Technologies", + NULL, + }, + { + PCI_VENDOR_ULSI, 0, + PCI_KNOWNDEV_NOPROD, + "ULSI Systems", + NULL, + }, + { + PCI_VENDOR_VLSI, 0, + PCI_KNOWNDEV_NOPROD, + "VLSI Technology", + NULL, + }, + { + PCI_VENDOR_AVANCE, 0, + PCI_KNOWNDEV_NOPROD, + "Avance Logic", + NULL, + }, + { + PCI_VENDOR_NS, 0, + PCI_KNOWNDEV_NOPROD, + "National Semiconductor", + NULL, + }, + { + PCI_VENDOR_TSENG, 0, + PCI_KNOWNDEV_NOPROD, + "Tseng Labs", + NULL, + }, + { + PCI_VENDOR_WEITEK, 0, + PCI_KNOWNDEV_NOPROD, + "Weitek", + NULL, + }, + { + PCI_VENDOR_DEC, 0, + PCI_KNOWNDEV_NOPROD, + "Digital Equipment", + NULL, + }, + { + PCI_VENDOR_CIRRUS, 0, + PCI_KNOWNDEV_NOPROD, + "Cirrus Logic", + NULL, + }, + { + PCI_VENDOR_IBM, 0, + PCI_KNOWNDEV_NOPROD, + "IBM", + NULL, + }, + { + PCI_VENDOR_WD, 0, + PCI_KNOWNDEV_NOPROD, + "Western Digital", + NULL, + }, + { + PCI_VENDOR_AMD, 0, + PCI_KNOWNDEV_NOPROD, + "Advanced Micro Devices", + NULL, + }, + { + PCI_VENDOR_TRIDENT, 0, + PCI_KNOWNDEV_NOPROD, + "Trident Microsystems", + NULL, + }, + { + PCI_VENDOR_ACER, 0, + PCI_KNOWNDEV_NOPROD, + "Acer", + NULL, + }, + { + PCI_VENDOR_MATROX, 0, + PCI_KNOWNDEV_NOPROD, + "Matrox", + NULL, + }, + { + PCI_VENDOR_CHIPS, 0, + PCI_KNOWNDEV_NOPROD, + "Chips and Technologies", + NULL, + }, + { + PCI_VENDOR_TOSHIBA, 0, + PCI_KNOWNDEV_NOPROD, + "Toshiba America", + NULL, + }, + { + PCI_VENDOR_NEC, 0, + PCI_KNOWNDEV_NOPROD, + "NEC", + NULL, + }, + { + PCI_VENDOR_FUTUREDOMAIN, 0, + PCI_KNOWNDEV_NOPROD, + "Future Domain", + NULL, + }, + { + PCI_VENDOR_SIS, 0, + PCI_KNOWNDEV_NOPROD, + "Silicon Integrated System", + NULL, + }, + { + PCI_VENDOR_HP, 0, + PCI_KNOWNDEV_NOPROD, + "Hewlett-Packard", + NULL, + }, + { + PCI_VENDOR_PCTECH, 0, + PCI_KNOWNDEV_NOPROD, + "PC Technology", + NULL, + }, + { + PCI_VENDOR_DPT, 0, + PCI_KNOWNDEV_NOPROD, + "Distributed Processing Technology", + NULL, + }, + { + PCI_VENDOR_OPTI, 0, + PCI_KNOWNDEV_NOPROD, + "Opti", + NULL, + }, + { + PCI_VENDOR_ELSA, 0, + PCI_KNOWNDEV_NOPROD, + "Elsa", + NULL, + }, + { + PCI_VENDOR_SGSTHOMSON, 0, + PCI_KNOWNDEV_NOPROD, + "SGS Thomson Microelectric", + NULL, + }, + { + PCI_VENDOR_BUSLOGIC, 0, + PCI_KNOWNDEV_NOPROD, + "BusLogic", + NULL, + }, + { + PCI_VENDOR_TI, 0, + PCI_KNOWNDEV_NOPROD, + "Texas Instruments", + NULL, + }, + { + PCI_VENDOR_SONY, 0, + PCI_KNOWNDEV_NOPROD, + "Sony", + NULL, + }, + { + PCI_VENDOR_OAKTECH, 0, + PCI_KNOWNDEV_NOPROD, + "Oak Technology", + NULL, + }, + { + PCI_VENDOR_WINBOND, 0, + PCI_KNOWNDEV_NOPROD, + "Winbond Electronics", + NULL, + }, + { + PCI_VENDOR_MOT, 0, + PCI_KNOWNDEV_NOPROD, + "Motorola", + NULL, + }, + { + PCI_VENDOR_PROMISE, 0, + PCI_KNOWNDEV_NOPROD, + "Promise Technology", + NULL, + }, + { + PCI_VENDOR_NUMBER9, 0, + PCI_KNOWNDEV_NOPROD, + "Number 9 Computer Company", + NULL, + }, + { + PCI_VENDOR_UMC, 0, + PCI_KNOWNDEV_NOPROD, + "United Microelectronics", + NULL, + }, + { + PCI_VENDOR_ITT, 0, + PCI_KNOWNDEV_NOPROD, + "I. T. T.", + NULL, + }, + { + PCI_VENDOR_MYLEX, 0, + PCI_KNOWNDEV_NOPROD, + "Mylex", + NULL, + }, + { + PCI_VENDOR_APPLE, 0, + PCI_KNOWNDEV_NOPROD, + "Apple Computer", + NULL, + }, + { + PCI_VENDOR_YAMAHA, 0, + PCI_KNOWNDEV_NOPROD, + "Yamaha", + NULL, + }, + { + PCI_VENDOR_NEXGEN, 0, + PCI_KNOWNDEV_NOPROD, + "NexGen Microsystems", + NULL, + }, + { + PCI_VENDOR_QLOGIC, 0, + PCI_KNOWNDEV_NOPROD, + "Q Logic", + NULL, + }, + { + PCI_VENDOR_LEADTEK, 0, + PCI_KNOWNDEV_NOPROD, + "LeadTek Research", + NULL, + }, + { + PCI_VENDOR_CONTAQ, 0, + PCI_KNOWNDEV_NOPROD, + "Contaq Microsystems", + NULL, + }, + { + PCI_VENDOR_BIT3, 0, + PCI_KNOWNDEV_NOPROD, + "Bit3 Computer Corp.", + NULL, + }, + { + PCI_VENDOR_OLICOM, 0, + PCI_KNOWNDEV_NOPROD, + "Olicom", + NULL, + }, + { + PCI_VENDOR_SUN, 0, + PCI_KNOWNDEV_NOPROD, + "Sun Microsystems", + NULL, + }, + { + PCI_VENDOR_INTERGRAPH, 0, + PCI_KNOWNDEV_NOPROD, + "Intergraph", + NULL, + }, + { + PCI_VENDOR_DIAMOND, 0, + PCI_KNOWNDEV_NOPROD, + "Diamond Computer Systems", + NULL, + }, + { + PCI_VENDOR_CMDTECH, 0, + PCI_KNOWNDEV_NOPROD, + "CMD Technology", + NULL, + }, + { + PCI_VENDOR_QUANTUMDESIGNS, 0, + PCI_KNOWNDEV_NOPROD, + "Quantum Designs", + NULL, + }, + { + PCI_VENDOR_BROOKTREE, 0, + PCI_KNOWNDEV_NOPROD, + "Brooktree", + NULL, + }, + { + PCI_VENDOR_SGI, 0, + PCI_KNOWNDEV_NOPROD, + "Silicon Graphics", + NULL, + }, + { + PCI_VENDOR_ACC, 0, + PCI_KNOWNDEV_NOPROD, + "ACC Microelectronics", + NULL, + }, + { + PCI_VENDOR_SYMPHONY, 0, + PCI_KNOWNDEV_NOPROD, + "Symphony Labs", + NULL, + }, + { + PCI_VENDOR_PLX, 0, + PCI_KNOWNDEV_NOPROD, + "PLX Technology", + NULL, + }, + { + PCI_VENDOR_MADGE, 0, + PCI_KNOWNDEV_NOPROD, + "Madge Networks", + NULL, + }, + { + PCI_VENDOR_3COM, 0, + PCI_KNOWNDEV_NOPROD, + "3Com", + NULL, + }, + { + PCI_VENDOR_SMC, 0, + PCI_KNOWNDEV_NOPROD, + "Standard Microsystems", + NULL, + }, + { + PCI_VENDOR_ALI, 0, + PCI_KNOWNDEV_NOPROD, + "Acer Labs", + NULL, + }, + { + PCI_VENDOR_SURECOM, 0, + PCI_KNOWNDEV_NOPROD, + "Surecom Technology", + NULL, + }, + { + PCI_VENDOR_SAMSUNGSEMI, 0, + PCI_KNOWNDEV_NOPROD, + "Samsung Semiconductors", + NULL, + }, + { + PCI_VENDOR_NEOMAGIC, 0, + PCI_KNOWNDEV_NOPROD, + "Neomagic", + NULL, + }, + { + PCI_VENDOR_ADVSYS, 0, + PCI_KNOWNDEV_NOPROD, + "Advanced System Products", + NULL, + }, + { + PCI_VENDOR_MACRONIX, 0, + PCI_KNOWNDEV_NOPROD, + "Macronix", + NULL, + }, + { + PCI_VENDOR_ES, 0, + PCI_KNOWNDEV_NOPROD, + "Evans & Sutherland", + NULL, + }, + { + PCI_VENDOR_NVIDIA, 0, + PCI_KNOWNDEV_NOPROD, + "Nvidia Corporation", + NULL, + }, + { + PCI_VENDOR_EMULEX, 0, + PCI_KNOWNDEV_NOPROD, + "Emulex", + NULL, + }, + { + PCI_VENDOR_IMS, 0, + PCI_KNOWNDEV_NOPROD, + "Integrated Micro Solutions", + NULL, + }, + { + PCI_VENDOR_TEKRAM, 0, + PCI_KNOWNDEV_NOPROD, + "Tekram Technology (1st PCI Vendor ID)", + NULL, + }, + { + PCI_VENDOR_NEWBRIDGE, 0, + PCI_KNOWNDEV_NOPROD, + "Newbridge Microsystems / Tundra Semiconductor", + NULL, + }, + { + PCI_VENDOR_AMCIRCUITS, 0, + PCI_KNOWNDEV_NOPROD, + "Applied Micro Circuits", + NULL, + }, + { + PCI_VENDOR_REALTEK, 0, + PCI_KNOWNDEV_NOPROD, + "Realtek Semiconductor", + NULL, + }, + { + PCI_VENDOR_NKK, 0, + PCI_KNOWNDEV_NOPROD, + "NKK Corporation", + NULL, + }, + { + PCI_VENDOR_INITIO, 0, + PCI_KNOWNDEV_NOPROD, + "Initio", + NULL, + }, + { + PCI_VENDOR_CREATIVELABS, 0, + PCI_KNOWNDEV_NOPROD, + "Creative Labs", + NULL, + }, + { + PCI_VENDOR_TRIONES, 0, + PCI_KNOWNDEV_NOPROD, + "Triones Technologies", + NULL, + }, + { + PCI_VENDOR_SIGMA, 0, + PCI_KNOWNDEV_NOPROD, + "Sigma Designs", + NULL, + }, + { + PCI_VENDOR_VIATECH, 0, + PCI_KNOWNDEV_NOPROD, + "VIA Technologies", + NULL, + }, + { + PCI_VENDOR_COGENT, 0, + PCI_KNOWNDEV_NOPROD, + "Cogent Data Technologies", + NULL, + }, + { + PCI_VENDOR_RNS, 0, + PCI_KNOWNDEV_NOPROD, + "RNS", + NULL, + }, + { + PCI_VENDOR_ACCTON, 0, + PCI_KNOWNDEV_NOPROD, + "Accton Technology", + NULL, + }, + { + PCI_VENDOR_VORTEX, 0, + PCI_KNOWNDEV_NOPROD, + "Vortex Computer Systems", + NULL, + }, + { + PCI_VENDOR_EFFICIENTNETS, 0, + PCI_KNOWNDEV_NOPROD, + "Efficent Networks", + NULL, + }, + { + PCI_VENDOR_IDT, 0, + PCI_KNOWNDEV_NOPROD, + "IDT", + NULL, + }, + { + PCI_VENDOR_FORE, 0, + PCI_KNOWNDEV_NOPROD, + "FORE Systems", + NULL, + }, + { + PCI_VENDOR_ZIATECH, 0, + PCI_KNOWNDEV_NOPROD, + "Ziatech", + NULL, + }, + { + PCI_VENDOR_ALLIANCE, 0, + PCI_KNOWNDEV_NOPROD, + "Alliance Semiconductor", + NULL, + }, + { + PCI_VENDOR_SCHNEIDERKOCH, 0, + PCI_KNOWNDEV_NOPROD, + "Schneider & Koch", + NULL, + }, + { + PCI_VENDOR_MUTECH, 0, + PCI_KNOWNDEV_NOPROD, + "Mutech", + NULL, + }, + { + PCI_VENDOR_XIRCOM, 0, + PCI_KNOWNDEV_NOPROD, + "Xircom", + NULL, + }, + { + PCI_VENDOR_ALTERA, 0, + PCI_KNOWNDEV_NOPROD, + "Altera Corporation", + NULL, + }, + { + PCI_VENDOR_TOSHIBA2, 0, + PCI_KNOWNDEV_NOPROD, + "Toshiba America Info Systems", + NULL, + }, + { + PCI_VENDOR_RICOH, 0, + PCI_KNOWNDEV_NOPROD, + "Ricoh", + NULL, + }, + { + PCI_VENDOR_DLINK, 0, + PCI_KNOWNDEV_NOPROD, + "D-Link Systems", + NULL, + }, + { + PCI_VENDOR_COROLLARY, 0, + PCI_KNOWNDEV_NOPROD, + "Corrollary", + NULL, + }, + { + PCI_VENDOR_ACARD, 0, + PCI_KNOWNDEV_NOPROD, + "Acard", + NULL, + }, + { + PCI_VENDOR_ZEINET, 0, + PCI_KNOWNDEV_NOPROD, + "Zeinet", + NULL, + }, + { + PCI_VENDOR_GALILEO, 0, + PCI_KNOWNDEV_NOPROD, + "Galileo Technology", + NULL, + }, + { + PCI_VENDOR_LITEON, 0, + PCI_KNOWNDEV_NOPROD, + "Lite-On Communications", + NULL, + }, + { + PCI_VENDOR_V3, 0, + PCI_KNOWNDEV_NOPROD, + "V3 Semiconductor", + NULL, + }, + { + PCI_VENDOR_LUCENT, 0, + PCI_KNOWNDEV_NOPROD, + "AT&T Microelectronics", + NULL, + }, + { + PCI_VENDOR_DOLPHIN, 0, + PCI_KNOWNDEV_NOPROD, + "Dolphin Interconnect Solutions", + NULL, + }, + { + PCI_VENDOR_AURAVISION, 0, + PCI_KNOWNDEV_NOPROD, + "Auravision", + NULL, + }, + { + PCI_VENDOR_ZORAN, 0, + PCI_KNOWNDEV_NOPROD, + "Zoran Corporation", + NULL, + }, + { + PCI_VENDOR_COMPEX, 0, + PCI_KNOWNDEV_NOPROD, + "Compex", + NULL, + }, + { + PCI_VENDOR_PMCSIERRA, 0, + PCI_KNOWNDEV_NOPROD, + "PMC-Sierra", + NULL, + }, + { + PCI_VENDOR_CYCLADES, 0, + PCI_KNOWNDEV_NOPROD, + "Cyclades", + NULL, + }, + { + PCI_VENDOR_ESSENTIAL, 0, + PCI_KNOWNDEV_NOPROD, + "Essential Communications", + NULL, + }, + { + PCI_VENDOR_O2MICRO, 0, + PCI_KNOWNDEV_NOPROD, + "O2 Micro Inc", + NULL, + }, + { + PCI_VENDOR_3DFX, 0, + PCI_KNOWNDEV_NOPROD, + "3Dfx Interactive", + NULL, + }, + { + PCI_VENDOR_CCUBE, 0, + PCI_KNOWNDEV_NOPROD, + "C-Cube Microsystems", + NULL, + }, + { + PCI_VENDOR_AVM, 0, + PCI_KNOWNDEV_NOPROD, + "AVM", + NULL, + }, + { + PCI_VENDOR_LINEARSYS, 0, + PCI_KNOWNDEV_NOPROD, + "Linear Systems", + NULL, + }, + { + PCI_VENDOR_ASIX, 0, + PCI_KNOWNDEV_NOPROD, + "ASIX Electronics", + NULL, + }, + { + PCI_VENDOR_ESSTECH, 0, + PCI_KNOWNDEV_NOPROD, + "ESS Technology Inc", + NULL, + }, + { + PCI_VENDOR_SILMOTION, 0, + PCI_KNOWNDEV_NOPROD, + "Silicon Motion", + NULL, + }, + { + PCI_VENDOR_ENSONIQ, 0, + PCI_KNOWNDEV_NOPROD, + "Ensoniq", + NULL, + }, + { + PCI_VENDOR_DAVICOM, 0, + PCI_KNOWNDEV_NOPROD, + "Davicom Semiconductor", + NULL, + }, + { + PCI_VENDOR_ESSTECH2, 0, + PCI_KNOWNDEV_NOPROD, + "ESS Technology Inc", + NULL, + }, + { + PCI_VENDOR_TRITECH, 0, + PCI_KNOWNDEV_NOPROD, + "TriTech Microelectronics", + NULL, + }, + { + PCI_VENDOR_ALTEON, 0, + PCI_KNOWNDEV_NOPROD, + "Alteon", + NULL, + }, + { + PCI_VENDOR_RISCOM, 0, + PCI_KNOWNDEV_NOPROD, + "RISCom", + NULL, + }, + { + PCI_VENDOR_USR, 0, + PCI_KNOWNDEV_NOPROD, + "US Robotics (3Com)", + NULL, + }, + { + PCI_VENDOR_NVIDIA_SGS, 0, + PCI_KNOWNDEV_NOPROD, + "Nvidia Corporation & SGS Thomson Microelectric", + NULL, + }, + { + PCI_VENDOR_AUREAL, 0, + PCI_KNOWNDEV_NOPROD, + "Aureal Semiconductor", + NULL, + }, + { + PCI_VENDOR_ADMTEK, 0, + PCI_KNOWNDEV_NOPROD, + "ADMtek", + NULL, + }, + { + PCI_VENDOR_FORTEMEDIA, 0, + PCI_KNOWNDEV_NOPROD, + "Forte Media", + NULL, + }, + { + PCI_VENDOR_DOMEX, 0, + PCI_KNOWNDEV_NOPROD, + "Domex", + NULL, + }, + { + PCI_VENDOR_LMC, 0, + PCI_KNOWNDEV_NOPROD, + "LAN Media Corporation", + NULL, + }, + { + PCI_VENDOR_API, 0, + PCI_KNOWNDEV_NOPROD, + "API Networks", + NULL, + }, + { + PCI_VENDOR_CONEXANT, 0, + PCI_KNOWNDEV_NOPROD, + "Conexant Systems", + NULL, + }, + { + PCI_VENDOR_NETGEAR, 0, + PCI_KNOWNDEV_NOPROD, + "Netgear", + NULL, + }, + { + PCI_VENDOR_3WARE, 0, + PCI_KNOWNDEV_NOPROD, + "3ware", + NULL, + }, + { + PCI_VENDOR_SUNDANCETI, 0, + PCI_KNOWNDEV_NOPROD, + "Sundance Technology", + NULL, + }, + { + PCI_VENDOR_CMEDIA, 0, + PCI_KNOWNDEV_NOPROD, + "C-Media Electronics Inc", + NULL, + }, + { + PCI_VENDOR_DELTA, 0, + PCI_KNOWNDEV_NOPROD, + "Delta Electronics", + NULL, + }, + { + PCI_VENDOR_SOLIDUM, 0, + PCI_KNOWNDEV_NOPROD, + "Solidum Systems Corp.", + NULL, + }, + { + PCI_VENDOR_SIBYTE, 0, + PCI_KNOWNDEV_NOPROD, + "SiByte, Inc.", + NULL, + }, + { + PCI_VENDOR_SYMPHONY2, 0, + PCI_KNOWNDEV_NOPROD, + "Symphony Labs (2nd PCI Vendor ID)", + NULL, + }, + { + PCI_VENDOR_TEKRAM2, 0, + PCI_KNOWNDEV_NOPROD, + "Tekram Technology (2nd PCI Vendor ID)", + NULL, + }, + { + PCI_VENDOR_BROADCOM, 0, + PCI_KNOWNDEV_NOPROD, + "Broadcom", + NULL, + }, + { + PCI_VENDOR_3DLABS, 0, + PCI_KNOWNDEV_NOPROD, + "3D Labs", + NULL, + }, + { + PCI_VENDOR_AVANCE2, 0, + PCI_KNOWNDEV_NOPROD, + "Avance Logic (2nd PCI Vendor ID)", + NULL, + }, + { + PCI_VENDOR_ADDTRON, 0, + PCI_KNOWNDEV_NOPROD, + "Addtron Technology", + NULL, + }, + { + PCI_VENDOR_NETVIN, 0, + PCI_KNOWNDEV_NOPROD, + "NetVin", + NULL, + }, + { + PCI_VENDOR_S3, 0, + PCI_KNOWNDEV_NOPROD, + "S3", + NULL, + }, + { + PCI_VENDOR_C4T, 0, + PCI_KNOWNDEV_NOPROD, + "c't Magazin", + NULL, + }, + { + PCI_VENDOR_INTEL, 0, + PCI_KNOWNDEV_NOPROD, + "Intel", + NULL, + }, + { + PCI_VENDOR_PROLAN, 0, + PCI_KNOWNDEV_NOPROD, + "ProLAN", + NULL, + }, + { + PCI_VENDOR_KTI, 0, + PCI_KNOWNDEV_NOPROD, + "KTI", + NULL, + }, + { + PCI_VENDOR_ADP, 0, + PCI_KNOWNDEV_NOPROD, + "Adaptec", + NULL, + }, + { + PCI_VENDOR_ADP2, 0, + PCI_KNOWNDEV_NOPROD, + "Adaptec (2nd PCI Vendor ID)", + NULL, + }, + { + PCI_VENDOR_ATRONICS, 0, + PCI_KNOWNDEV_NOPROD, + "Atronics", + NULL, + }, + { + PCI_VENDOR_ARC, 0, + PCI_KNOWNDEV_NOPROD, + "ARC Logic", + NULL, + }, + { + PCI_VENDOR_EPIGRAM, 0, + PCI_KNOWNDEV_NOPROD, + "Epigram", + NULL, + }, + { + PCI_VENDOR_INVALID, 0, + PCI_KNOWNDEV_NOPROD, + "INVALID VENDOR ID", + NULL, + }, + { 0, 0, 0, NULL, NULL, } +}; diff --git a/cfe/cfe/pci/pcireg.h b/cfe/cfe/pci/pcireg.h new file mode 100644 index 0000000..932fc7d --- /dev/null +++ b/cfe/cfe/pci/pcireg.h @@ -0,0 +1,615 @@ +/* + * Copyright (c) 1995, 1996, 1999 + * Christopher G. Demetriou. All rights reserved. + * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_PCI_PCIREG_H_ +#define _DEV_PCI_PCIREG_H_ + +/* + * Standardized PCI configuration register definitions and macros. + * Derived from information found in the ``PCI Local Bus Specification, + * Revision 2.2, December 18, 1998.'' + * + * Note: Register and field definitions assume 32-bit register accesses. + */ + +#if !defined(__ASSEMBLER__) +typedef uint16_t pci_vendor_id_t; +typedef uint16_t pci_product_id_t; + +typedef uint8_t pci_class_t; +typedef uint8_t pci_subclass_t; +typedef uint8_t pci_interface_t; +typedef uint8_t pci_revision_t; + +typedef uint8_t pci_intr_latency_t; +typedef uint8_t pci_intr_grant_t; +typedef uint8_t pci_intr_pin_t; +typedef uint8_t pci_intr_line_t; +#endif + +/* some PCI bus constants */ + +#define PCI_BUSMAX 255 +#define PCI_DEVMAX 31 +#define PCI_FUNCMAX 7 +#define PCI_REGMAX 255 + +/* + * Common PCI header + */ + +/* + * Device identification register; contains a vendor ID and a device ID. + */ +#define PCI_ID_REG 0x00 + +#define PCI_VENDOR_SHIFT 0 +#define PCI_VENDOR_MASK 0xffff +#define PCI_VENDOR(id) \ + (((id) >> PCI_VENDOR_SHIFT) & PCI_VENDOR_MASK) + +#define PCI_PRODUCT_SHIFT 16 +#define PCI_PRODUCT_MASK 0xffff +#define PCI_PRODUCT(id) \ + (((id) >> PCI_PRODUCT_SHIFT) & PCI_PRODUCT_MASK) + +/* + * Command and status register. + */ +#define PCI_COMMAND_STATUS_REG 0x04 + +#define PCI_COMMAND_SHIFT 0 +#define PCI_COMMAND_MASK 0xffff +#define PCI_COMMAND(csr) \ + (((csr) >> PCI_COMMAND_SHIFT) & PCI_COMMAND_MASK) + +#define PCI_STATUS_SHIFT 16 +#define PCI_STATUS_MASK 0xffff +#define PCI_STATUS(csr) \ + (((csr) >> PCI_STATUS_SHIFT) & PCI_STATUS_MASK) + +#define PCI_COMMAND_IO_ENABLE 0x00000001 +#define PCI_COMMAND_MEM_ENABLE 0x00000002 +#define PCI_COMMAND_MASTER_ENABLE 0x00000004 +#define PCI_COMMAND_SPECIAL_ENABLE 0x00000008 +#define PCI_COMMAND_INVALIDATE_ENABLE 0x00000010 +#define PCI_COMMAND_PALETTE_ENABLE 0x00000020 +#define PCI_COMMAND_PARITY_ENABLE 0x00000040 +#define PCI_COMMAND_STEPPING_ENABLE 0x00000080 +#define PCI_COMMAND_SERR_ENABLE 0x00000100 +#define PCI_COMMAND_BACKTOBACK_ENABLE 0x00000200 + +#define PCI_STATUS_CAPLIST_SUPPORT 0x00100000 +#define PCI_STATUS_66MHZ_SUPPORT 0x00200000 +#define PCI_STATUS_UDF_SUPPORT 0x00400000 +#define PCI_STATUS_BACKTOBACK_SUPPORT 0x00800000 +#define PCI_STATUS_PARITY_ERROR 0x01000000 +#define PCI_STATUS_DEVSEL_FAST 0x00000000 +#define PCI_STATUS_DEVSEL_MEDIUM 0x02000000 +#define PCI_STATUS_DEVSEL_SLOW 0x04000000 +#define PCI_STATUS_DEVSEL_MASK 0x06000000 +#define PCI_STATUS_DEVSEL_SHIFT 25 +#define PCI_STATUS_DEVSEL(scr) \ + (((scr) & PCI_STATUS_DEVSEL_MASK) >> PCI_STATUS_DEVSEL_SHIFT) +#define PCI_STATUS_TARGET_TARGET_ABORT 0x08000000 +#define PCI_STATUS_MASTER_TARGET_ABORT 0x10000000 +#define PCI_STATUS_MASTER_ABORT 0x20000000 +#define PCI_STATUS_SYSTEM_ERROR 0x40000000 +#define PCI_STATUS_PARITY_DETECT 0x80000000 + +/* + * PCI Class and Revision Register; defines type and revision of device. + */ +#define PCI_CLASS_REG 0x08 + +#define PCI_CLASS_SHIFT 24 +#define PCI_CLASS_MASK 0xff +#define PCI_CLASS(cr) \ + (((cr) >> PCI_CLASS_SHIFT) & PCI_CLASS_MASK) + +#define PCI_SUBCLASS_SHIFT 16 +#define PCI_SUBCLASS_MASK 0xff +#define PCI_SUBCLASS(cr) \ + (((cr) >> PCI_SUBCLASS_SHIFT) & PCI_SUBCLASS_MASK) + +#define PCI_INTERFACE_SHIFT 8 +#define PCI_INTERFACE_MASK 0xff +#define PCI_INTERFACE(cr) \ + (((cr) >> PCI_INTERFACE_SHIFT) & PCI_INTERFACE_MASK) + +#define PCI_REVISION_SHIFT 0 +#define PCI_REVISION_MASK 0xff +#define PCI_REVISION(cr) \ + (((cr) >> PCI_REVISION_SHIFT) & PCI_REVISION_MASK) + +#define PCI_CLASS_CODE(class, subclass, interface) \ + ((((class) & PCI_CLASS_MASK) << PCI_CLASS_SHIFT) | \ + (((subclass) & PCI_SUBCLASS_MASK) << PCI_SUBCLASS_SHIFT) | \ + (((interface) & PCI_INTERFACE_MASK) << PCI_INTERFACE_SHIFT)) + +/* base classes */ +#define PCI_CLASS_PREHISTORIC 0x00 +#define PCI_CLASS_MASS_STORAGE 0x01 +#define PCI_CLASS_NETWORK 0x02 +#define PCI_CLASS_DISPLAY 0x03 +#define PCI_CLASS_MULTIMEDIA 0x04 +#define PCI_CLASS_MEMORY 0x05 +#define PCI_CLASS_BRIDGE 0x06 +#define PCI_CLASS_COMMUNICATIONS 0x07 +#define PCI_CLASS_SYSTEM 0x08 +#define PCI_CLASS_INPUT 0x09 +#define PCI_CLASS_DOCK 0x0a +#define PCI_CLASS_PROCESSOR 0x0b +#define PCI_CLASS_SERIALBUS 0x0c +#define PCI_CLASS_WIRELESS 0x0d +#define PCI_CLASS_I2O 0x0e +#define PCI_CLASS_SATCOM 0x0f +#define PCI_CLASS_CRYPTO 0x10 +#define PCI_CLASS_DASP 0x11 +#define PCI_CLASS_UNDEFINED 0xff + +/* 0x00 prehistoric subclasses */ +#define PCI_SUBCLASS_PREHISTORIC_MISC 0x00 +#define PCI_SUBCLASS_PREHISTORIC_VGA 0x01 + +/* 0x01 mass storage subclasses */ +#define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00 +#define PCI_SUBCLASS_MASS_STORAGE_IDE 0x01 +#define PCI_SUBCLASS_MASS_STORAGE_FLOPPY 0x02 +#define PCI_SUBCLASS_MASS_STORAGE_IPI 0x03 +#define PCI_SUBCLASS_MASS_STORAGE_RAID 0x04 +#define PCI_SUBCLASS_MASS_STORAGE_MISC 0x80 + +/* 0x02 network subclasses */ +#define PCI_SUBCLASS_NETWORK_ETHERNET 0x00 +#define PCI_SUBCLASS_NETWORK_TOKENRING 0x01 +#define PCI_SUBCLASS_NETWORK_FDDI 0x02 +#define PCI_SUBCLASS_NETWORK_ATM 0x03 +#define PCI_SUBCLASS_NETWORK_ISDN 0x04 +#define PCI_SUBCLASS_NETWORK_WORLDFIP 0x05 +#define PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP 0x06 +#define PCI_SUBCLASS_NETWORK_MISC 0x80 + +/* 0x03 display subclasses */ +#define PCI_SUBCLASS_DISPLAY_VGA 0x00 +#define PCI_SUBCLASS_DISPLAY_XGA 0x01 +#define PCI_SUBCLASS_DISPLAY_3D 0x02 +#define PCI_SUBCLASS_DISPLAY_MISC 0x80 + +/* 0x04 multimedia subclasses */ +#define PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00 +#define PCI_SUBCLASS_MULTIMEDIA_AUDIO 0x01 +#define PCI_SUBCLASS_MULTIMEDIA_TELEPHONY 0x02 +#define PCI_SUBCLASS_MULTIMEDIA_MISC 0x80 + +/* 0x05 memory subclasses */ +#define PCI_SUBCLASS_MEMORY_RAM 0x00 +#define PCI_SUBCLASS_MEMORY_FLASH 0x01 +#define PCI_SUBCLASS_MEMORY_MISC 0x80 + +/* 0x06 bridge subclasses */ +#define PCI_SUBCLASS_BRIDGE_HOST 0x00 +#define PCI_SUBCLASS_BRIDGE_ISA 0x01 +#define PCI_SUBCLASS_BRIDGE_EISA 0x02 +#define PCI_SUBCLASS_BRIDGE_MCA 0x03 +#define PCI_SUBCLASS_BRIDGE_PCI 0x04 +#define PCI_SUBCLASS_BRIDGE_PCMCIA 0x05 +#define PCI_SUBCLASS_BRIDGE_NUBUS 0x06 +#define PCI_SUBCLASS_BRIDGE_CARDBUS 0x07 +#define PCI_SUBCLASS_BRIDGE_RACEWAY 0x08 +#define PCI_SUBCLASS_BRIDGE_STPCI 0x09 +#define PCI_SUBCLASS_BRIDGE_INFINIBAND 0x0a +#define PCI_SUBCLASS_BRIDGE_MISC 0x80 + +/* 0x07 communications subclasses */ +#define PCI_SUBCLASS_COMMUNICATIONS_SERIAL 0x00 +#define PCI_SUBCLASS_COMMUNICATIONS_PARALLEL 0x01 +#define PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL 0x02 +#define PCI_SUBCLASS_COMMUNICATIONS_MODEM 0x03 +#define PCI_SUBCLASS_COMMUNICATIONS_MISC 0x80 + +/* 0x08 system subclasses */ +#define PCI_SUBCLASS_SYSTEM_PIC 0x00 +#define PCI_SUBCLASS_SYSTEM_DMA 0x01 +#define PCI_SUBCLASS_SYSTEM_TIMER 0x02 +#define PCI_SUBCLASS_SYSTEM_RTC 0x03 +#define PCI_SUBCLASS_SYSTEM_PCIHOTPLUG 0x04 +#define PCI_SUBCLASS_SYSTEM_MISC 0x80 + +/* 0x09 input subclasses */ +#define PCI_SUBCLASS_INPUT_KEYBOARD 0x00 +#define PCI_SUBCLASS_INPUT_DIGITIZER 0x01 +#define PCI_SUBCLASS_INPUT_MOUSE 0x02 +#define PCI_SUBCLASS_INPUT_SCANNER 0x03 +#define PCI_SUBCLASS_INPUT_GAMEPORT 0x04 +#define PCI_SUBCLASS_INPUT_MISC 0x80 + +/* 0x0a dock subclasses */ +#define PCI_SUBCLASS_DOCK_GENERIC 0x00 +#define PCI_SUBCLASS_DOCK_MISC 0x80 + +/* 0x0b processor subclasses */ +#define PCI_SUBCLASS_PROCESSOR_386 0x00 +#define PCI_SUBCLASS_PROCESSOR_486 0x01 +#define PCI_SUBCLASS_PROCESSOR_PENTIUM 0x02 +#define PCI_SUBCLASS_PROCESSOR_ALPHA 0x10 +#define PCI_SUBCLASS_PROCESSOR_POWERPC 0x20 +#define PCI_SUBCLASS_PROCESSOR_MIPS 0x30 +#define PCI_SUBCLASS_PROCESSOR_COPROC 0x40 + +/* 0x0c serial bus subclasses */ +#define PCI_SUBCLASS_SERIALBUS_FIREWIRE 0x00 +#define PCI_SUBCLASS_SERIALBUS_ACCESS 0x01 +#define PCI_SUBCLASS_SERIALBUS_SSA 0x02 +#define PCI_SUBCLASS_SERIALBUS_USB 0x03 +#define PCI_SUBCLASS_SERIALBUS_FIBER 0x04 /* XXX _FIBRECHANNEL */ +#define PCI_SUBCLASS_SERIALBUS_SMBUS 0x05 +#define PCI_SUBCLASS_SERIALBUS_INFINIBAND 0x06 +#define PCI_SUBCLASS_SERIALBUS_IPMI 0x07 +#define PCI_SUBCLASS_SERIALBUS_SERCOS 0x08 +#define PCI_SUBCLASS_SERIALBUS_CANBUS 0x09 + +/* 0x0d wireless subclasses */ +#define PCI_SUBCLASS_WIRELESS_IRDA 0x00 +#define PCI_SUBCLASS_WIRELESS_CONSUMERIR 0x01 +#define PCI_SUBCLASS_WIRELESS_RF 0x10 +#define PCI_SUBCLASS_WIRELESS_MISC 0x80 + +/* 0x0e I2O (Intelligent I/O) subclasses */ +#define PCI_SUBCLASS_I2O_STANDARD 0x00 + +/* 0x0f satellite communication subclasses */ +/* PCI_SUBCLASS_SATCOM_??? 0x00 / * XXX ??? */ +#define PCI_SUBCLASS_SATCOM_TV 0x01 +#define PCI_SUBCLASS_SATCOM_AUDIO 0x02 +#define PCI_SUBCLASS_SATCOM_VOICE 0x03 +#define PCI_SUBCLASS_SATCOM_DATA 0x04 + +/* 0x10 encryption/decryption subclasses */ +#define PCI_SUBCLASS_CRYPTO_NETCOMP 0x00 +#define PCI_SUBCLASS_CRYPTO_ENTERTAINMENT 0x10 +#define PCI_SUBCLASS_CRYPTO_MISC 0x80 + +/* 0x11 data acquisition and signal processing subclasses */ +#define PCI_SUBCLASS_DASP_DPIO 0x00 +#define PCI_SUBCLASS_DASP_TIMERFREQ 0x01 +#define PCI_SUBCLASS_DASP_MISC 0x80 + +/* + * PCI BIST/Header Type/Latency Timer/Cache Line Size Register. + */ +#define PCI_BHLC_REG 0x0c + +#define PCI_BIST_SHIFT 24 +#define PCI_BIST_MASK 0xff +#define PCI_BIST(bhlcr) \ + (((bhlcr) >> PCI_BIST_SHIFT) & PCI_BIST_MASK) + +#define PCI_HDRTYPE_SHIFT 16 +#define PCI_HDRTYPE_MASK 0xff +#define PCI_HDRTYPE(bhlcr) \ + (((bhlcr) >> PCI_HDRTYPE_SHIFT) & PCI_HDRTYPE_MASK) + +#define PCI_HDRTYPE_TYPE(bhlcr) \ + (PCI_HDRTYPE(bhlcr) & 0x7f) +#define PCI_HDRTYPE_MULTIFN(bhlcr) \ + ((PCI_HDRTYPE(bhlcr) & 0x80) != 0) + +#define PCI_LATTIMER_SHIFT 8 +#define PCI_LATTIMER_MASK 0xff +#define PCI_LATTIMER(bhlcr) \ + (((bhlcr) >> PCI_LATTIMER_SHIFT) & PCI_LATTIMER_MASK) +#define PCI_LATTIMER_SET(bhlcr,v) \ + (bhlcr) = ((bhlcr) & ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT)) | \ + ((v) << PCI_LATTIMER_SHIFT) + +#define PCI_CACHELINE_SHIFT 0 +#define PCI_CACHELINE_MASK 0xff +#define PCI_CACHELINE(bhlcr) \ + (((bhlcr) >> PCI_CACHELINE_SHIFT) & PCI_CACHELINE_MASK) +#define PCI_CACHELINE_SET(bhlcr,v) \ + (bhlcr) = ((bhlcr) & ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT)) | \ + ((v) << PCI_CACHELINE_SHIFT) + +/* + * The currently defined header types are + * 00h prefix PCI_ below + * 01h prefix PPB_ below (PCI-to-PCI bridges) + * 02h prefix PCB_ below (Cardbus bridges) + */ + +/* + * Type 00h Configuration Space extensions. + */ + +/* + * Mapping registers + */ +#define PCI_MAPREG_START 0x10 +#define PCI_MAPREG_END 0x28 + +#define PCI_MAPREG_PPB_END 0x18 +#define PCI_MAPREG_PPB_ROM 0x38 +#define PCI_MAPREG_PCB_END 0x14 +#define PCI_MAPREG_NONE 0x00 + +#define PCI_MAPREG_TYPE(mr) \ + ((mr) & PCI_MAPREG_TYPE_MASK) +#define PCI_MAPREG_TYPE_MASK 0x00000001 + +#define PCI_MAPREG_TYPE_MEM 0x00000000 +#define PCI_MAPREG_TYPE_IO 0x00000001 + +#define PCI_MAPREG_MEM_TYPE(mr) \ + ((mr) & PCI_MAPREG_MEM_TYPE_MASK) +#define PCI_MAPREG_MEM_TYPE_MASK 0x00000006 + +#define PCI_MAPREG_MEM_TYPE_32BIT 0x00000000 +#define PCI_MAPREG_MEM_TYPE_32BIT_1M 0x00000002 +#define PCI_MAPREG_MEM_TYPE_64BIT 0x00000004 + +#define PCI_MAPREG_MEM_PREFETCHABLE(mr) \ + (((mr) & PCI_MAPREG_MEM_PREFETCHABLE_MASK) != 0) +#define PCI_MAPREG_MEM_PREFETCHABLE_MASK 0x00000008 + +#define PCI_MAPREG_MEM_ADDR(mr) \ + ((mr) & PCI_MAPREG_MEM_ADDR_MASK) +#define PCI_MAPREG_MEM_SIZE(mr) \ + (PCI_MAPREG_MEM_ADDR(mr) & -PCI_MAPREG_MEM_ADDR(mr)) +#define PCI_MAPREG_MEM_ADDR_MASK 0xfffffff0 + +#define PCI_MAPREG_MEM64_ADDR(mr) \ + ((mr) & PCI_MAPREG_MEM64_ADDR_MASK) +#define PCI_MAPREG_MEM64_SIZE(mr) \ + (PCI_MAPREG_MEM64_ADDR(mr) & -PCI_MAPREG_MEM64_ADDR(mr)) +#define PCI_MAPREG_MEM64_ADDR_MASK 0xfffffffffffffff0ULL + +#define PCI_MAPREG_IO_ADDR(mr) \ + ((mr) & PCI_MAPREG_IO_ADDR_MASK) +#define PCI_MAPREG_IO_SIZE(mr) \ + (PCI_MAPREG_IO_ADDR(mr) & -PCI_MAPREG_IO_ADDR(mr)) +#define PCI_MAPREG_IO_ADDR_MASK 0xfffffffc + +#define PCI_MAPREG_SIZE_TO_MASK(size) \ + (-(size)) + +#define PCI_MAPREG(num) (PCI_MAPREG_START + 4*(num)) +#define PCI_MAPREG_NUM(offset) \ + (((unsigned)(offset)-PCI_MAPREG_START)/4) + +/* + * Cardbus CIS pointer (PCI rev. 2.1) + */ +#define PCI_CARDBUS_CIS_REG 0x28 + +/* + * Subsystem identification register; contains a vendor ID and a device ID. + * Types/macros for PCI_ID_REG apply. + * (PCI rev. 2.1) + */ +#define PCI_SUBSYS_ID_REG 0x2c + +/* + * Expansion ROM base address register; contains an address and enable bit. + */ +#define PCI_MAPREG_ROM 0x30 +#define PCI_MAPREG_ROM_ADDR(mr) \ + ((mr) & PCI_MAPREG_ROM_ADDR_MASK) +#define PCI_MAPREG_ROM_ADDR_MASK 0xfffff800 +#define PCI_MAPREG_ROM_ENABLE 0x00000001 + +/* + * capabilities link list (PCI rev. 2.2) + */ +#define PCI_CAPLISTPTR_REG 0x34 /* header type 0 */ +#define PCI_CARDBUS_CAPLISTPTR_REG 0x14 /* header type 2 */ +#define PCI_CAPLIST_PTR(cpr) ((cpr) & 0xff) +#define PCI_CAPLIST_NEXT(cr) (((cr) >> 8) & 0xff) +#define PCI_CAPLIST_CAP(cr) ((cr) & 0xff) + +#define PCI_CAP_RESERVED0 0x00 +#define PCI_CAP_PWRMGMT 0x01 +#define PCI_CAP_AGP 0x02 +#define PCI_CAP_VPD 0x03 +#define PCI_CAP_SLOTID 0x04 +#define PCI_CAP_MBI 0x05 +#define PCI_CAP_CPCI_HOTSWAP 0x06 +#define PCI_CAP_PCIX 0x07 +#define PCI_CAP_LDT 0x08 +#define PCI_CAP_VENDSPEC 0x09 +#define PCI_CAP_DEBUGPORT 0x0a +#define PCI_CAP_CPCI_RSRCCTL 0x0b +#define PCI_CAP_HOTPLUG 0x0c + +/* + * Power Management Control Status Register; access via capability pointer. + */ +#define PCI_PMCSR_STATE_MASK 0x03 +#define PCI_PMCSR_STATE_D0 0x00 +#define PCI_PMCSR_STATE_D1 0x01 +#define PCI_PMCSR_STATE_D2 0x02 +#define PCI_PMCSR_STATE_D3 0x03 + +/* + * Bus Parameter and Interrupt Configuration Register; + * contains interrupt pin and line. + */ +#define PCI_BPARAM_INTERRUPT_REG 0x3c + +#define PCI_BPARAM_LATENCY_SHIFT 24 +#define PCI_BPARAM_LATENCY_MASK 0xff +#define PCI_BPARAM_LATENCY(bpir) \ + (((bpir) >> PCI_BPARAM_LATENCY_SHIFT) & PCI_BPARAM_LATENCY_MASK) + +#define PCI_BPARAM_GRANT_SHIFT 16 +#define PCI_BPARAM_GRANT_MASK 0xff +#define PCI_BPARAM_GRANT(bpir) \ + (((bpir) >> PCI_BPARAM_GRANT_SHIFT) & PCI_BPARAM_GRANT_MASK) + +#define PCI_INTERRUPT_PIN_SHIFT 8 +#define PCI_INTERRUPT_PIN_MASK 0xff +#define PCI_INTERRUPT_PIN(bpir) \ + (((bpir) >> PCI_INTERRUPT_PIN_SHIFT) & PCI_INTERRUPT_PIN_MASK) + +#define PCI_INTERRUPT_LINE_SHIFT 0 +#define PCI_INTERRUPT_LINE_MASK 0xff +#define PCI_INTERRUPT_LINE(bpir) \ + (((bpir) >> PCI_INTERRUPT_LINE_SHIFT) & PCI_INTERRUPT_LINE_MASK) + +#define PCI_INTERRUPT_PIN_NONE 0x00 +#define PCI_INTERRUPT_PIN_A 0x01 +#define PCI_INTERRUPT_PIN_B 0x02 +#define PCI_INTERRUPT_PIN_C 0x03 +#define PCI_INTERRUPT_PIN_D 0x04 +#define PCI_INTERRUPT_PIN_MAX 0x04 + + +/* + * Type 01h Configuration Space extension: + * PCI to PCI Bridge registers (cf ppbreg.h) + * Derived from information found in the ``PCI to PCI Bridge + * Architecture Specification, Revision 1.1, December 18, 1998.'' + */ + +#define PPB_MAPREG_START 0x10 +#define PPB_MAPREG_END 0x18 + +/* + * Bus Information Register; contains bus hierarchy and secondary latency. + */ +#define PPB_BUSINFO_REG 0x18 + +#define PPB_BUSINFO_LATENCY_SHIFT 24 +#define PPB_BUSINFO_LATENCY_MASK 0xff +#define PPB_BUSINFO_LATENCY(br) \ + (((br) >> PPB_BUSINFO_LATENCY_SHIFT) & PPB_BUSINFO_LATENCY_MASK) + +#define PPB_BUSINFO_SUBORD_SHIFT 16 +#define PPB_BUSINFO_SUBORD_MASK 0xff +#define PPB_BUSINFO_SUBORD(br) \ + (((br) >> PPB_BUSINFO_SUBORD_SHIFT) & PPB_BUSINFO_SUBORD_MASK) + +#define PPB_BUSINFO_SECONDARY_SHIFT 8 +#define PPB_BUSINFO_SECONDARY_MASK 0xff +#define PPB_BUSINFO_SECONDARY(br) \ + (((br) >> PPB_BUSINFO_SECONDARY_SHIFT) & PPB_BUSINFO_SECONDARY_MASK) + +#define PPB_BUSINFO_PRIMARY_SHIFT 0 +#define PPB_BUSINFO_PRIMARY_MASK 0xff +#define PPB_BUSINFO_PRIMARY(br) \ + (((br) >> PPB_BUSINFO_PRIMARY_SHIFT) & PPB_BUSINFO_PRIMARY_MASK) + +/* + * IO Status Register; contains I/O base + limit and secondary status. + * Masks/macros for PCI_STATUS apply to Secondary Status. + */ +#define PPB_IO_STATUS_REG 0x1C + +#define PPB_IO_BASE_MASK 0x000000ff +#define PPB_IO_LIMIT_MASK 0x0000ff00 +#define PPB_IO_ADDR_CAP_MASK 0x00000f0f +#define PPB_IO_ADDR_CAP_16 0x00000000 +#define PPB_IO_ADDR_CAP_32 0x00000101 +#define PPB_IO_BASE(iosr) \ + (((iosr) >> 0) & 0xff) +#define PPB_IO_LIMIT(iosr) \ + (((iosr) >> 8) & 0xff) + +#define PPB_SECSTATUS_SHIFT 16 +#define PPB_SECSTATUS_MASK 0xffff +#define PPB_SECSTATUS(iosr) \ + (((iosr) >> PPB_SECSTATUS_SHIFT) & PPB_SECSTATUS_MASK) + +/* + * Base and limit values for address ranges have common packing. + */ +#define PPB_BASE_SHIFT 0 +#define PPB_BASE_MASK 0xffff +#define PPB_BASE(blr) \ + (((blr) >> PPB_BASE_SHIFT) & PPB_BASE_MASK) + +#define PPB_LIMIT_SHIFT 16 +#define PPB_LIMIT_MASK 0xffff +#define PPB_LIMIT(blr) \ + (((blr) >> PPB_LIMIT_SHIFT) & PPB_LIMIT_MASK) + +/* + * Memory Registers; contains memory base + limit. + */ +#define PPB_MEM_REG 0x20 +#define PPB_PREFMEM_REG 0x24 + +#define PPB_MEM_BASE_MASK 0x0000ffff +#define PPB_MEM_LIMIT_MASK 0xffff0000 + +/* + * Prefetchable Memory Upper Registers; contain high bits + */ +#define PPB_PREFMEM_BASE_UPPER_REG 0x28 +#define PPB_PREFMEM_LIMIT_UPPER_REG 0x2c + +/* + * IO Upper Register; contains I/O base + limit high bits + */ +#define PPB_IO_UPPER_REG 0x30 + +#define PPB_IO_UPPER_BASE_MASK 0x0000ffff +#define PPB_IO_UPPER_LIMIT_MASK 0xffff0000 + +/* + * Expansion ROM Base Address Register. + */ +#define PPB_MAPREG_ROM 0x38 + +/* + * Bridge Control and Interrupt Register + * Masks/macros for PCI_INTERRUPT apply to Interrupt + */ +#define PPB_BRCTL_INTERRUPT_REG 0x3C + +#define PPB_BRCTL_SHIFT 16 +#define PPB_BRCTL_MASK 0xffff +#define PPB_BRCTL(bcir) \ + (((bcir) >> PPB_BRCTL_SHIFT) & PPB_BRCTL_MASK) + +#define PPB_BRCTL_PARITY_ENABLE 0x00010000 +#define PPB_BRCTL_SERR_ENABLE 0x00020000 +#define PPB_BRCTL_ISA_ENABLE 0x00040000 +#define PPB_BRCTL_VGA_ENABLE 0x00080000 +#define PPB_BRCTL_MASTER_ABORT_MODE 0x00200000 +#define PPB_BRCTL_SECONDARY_RESET 0x00400000 +#define PPB_BRCTL_BACKTOBACK_ENABLE 0x00800000 +#define PPB_BRCTL_PRIMARY_DISCARD_TIMER 0x01000000 +#define PPB_BRCTL_SECONDARY_DISCARD_TIMER 0x02000000 +#define PPB_BRCTL_DISCARD_TIMER_STATUS 0x04000000 +#define PPB_BRCTL_DISCARD_SERR_ENABLE 0x08000000 + +#endif /* _DEV_PCI_PCIREG_H_ */ diff --git a/cfe/cfe/pci/pcivar.h b/cfe/cfe/pci/pcivar.h new file mode 100644 index 0000000..51f0b40 --- /dev/null +++ b/cfe/cfe/pci/pcivar.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PCIVAR_H_ +#define _PCIVAR_H_ + +/* + * Definitions for PCI autoconfiguration. + * + * The initial segment of this file describes types and functions + * that are exported for PCI configuration and address mapping. */ + +#include "pci_machdep.h" + +/* From _pci_machdep.c */ + +pcitag_t pci_make_tag(int, int, int); +pcireg_t pci_conf_read(pcitag_t, int); +void pci_conf_write(pcitag_t, int, pcireg_t); + +typedef enum { + PCI_MATCH_BYTES = 0, + PCI_MATCH_BITS = 1 +} pci_endian_t; + +int pci_map_io(pcitag_t, int, pci_endian_t, phys_addr_t *); +int pci_map_mem(pcitag_t, int, pci_endian_t, phys_addr_t *); + +uint8_t inb(unsigned int port); +uint16_t inw(unsigned int port); +uint32_t inl(unsigned int port); +void outb(unsigned int port, uint8_t val); +void outw(unsigned int port, uint16_t val); +void outl(unsigned int port, uint32_t val); + +int pci_map_window(phys_addr_t pa, + unsigned int offset, unsigned int len, + int l2ca, int endian); +int pci_unmap_window(unsigned int offset, unsigned int len); + +/* From pciconf.c */ + +/* Flags controlling PCI/LDT configuration options */ + +typedef unsigned int pci_flags_t; + +#define PCI_FLG_NORMAL 0x00000001 +#define PCI_FLG_VERBOSE 0x00000003 +#define PCI_FLG_LDT_PREFETCH 0x00000004 +#define PCI_FLG_LDT_REV_017 0x00000008 + +void pci_configure(pci_flags_t flags); +void pci_show_configuration(void); +int pci_foreachdev(int (*fn)(pcitag_t tag)); +int pci_cacheline_log2 (void); +int pci_maxburst_log2 (void); + +int pci_find_device(uint32_t vid, uint32_t did, int enumidx, pcitag_t *tag); +int pci_find_class(uint32_t class, int enumidx, pcitag_t *tag); + +/* From pci_subr.c */ + +void pci_devinfo(pcireg_t, pcireg_t, int, char *); +void pci_conf_print(pcitag_t tag); + +void pci_tagprintf (pcitag_t tag, const char *fmt, ...) +#ifdef __long64 + __attribute__((__format__(__printf__,2,3))) +#endif + ; + + +/* + * Definitions for PCI autoconfiguration. + * + * The remainder of this file describes types and functions + * that are used only for communication among the PCI modules + * implementing autoconfiguration. + * XXX This should be split into a separate file. */ + +/* Build options. Debug levels >1 are for helping to bring up new + LDT hardware and will be annoyingly verbose otherwise. */ + +/* PCI_DEBUG enables general checking and tracing. */ +#ifndef PCI_DEBUG +#define PCI_DEBUG 0 +#endif + +/* LDT_DEBUG enables progress/error reports for LDT fabric initialization. */ +#ifndef LDT_DEBUG +#define LDT_DEBUG 0 +#endif + + +struct pci_attach_args { + pcitag_t pa_tag; + pcireg_t pa_id; + pcireg_t pa_class; +}; + +struct pci_match { + pcireg_t class, classmask; + pcireg_t id, idmask; +}; + +/* From _pci_machdep.c */ + +int pci_hwinit(pci_flags_t flags); +void pci_hwreinit(pci_flags_t flags); +int pci_device_preset (pcitag_t tag); +void pci_device_setup(pcitag_t tag); +void pci_bridge_setup(pcitag_t tag, pci_flags_t flags); +void pci_flush(void); + +void pci_break_tag(pcitag_t, int *, int *, int *); + +int pci_canscan(pcitag_t); +int pci_probe_tag(pcitag_t tag); + +pcireg_t pci_conf_read8(pcitag_t, int); +void pci_conf_write8(pcitag_t, int, pcireg_t); +pcireg_t pci_conf_read16(pcitag_t, int); +void pci_conf_write16(pcitag_t, int, pcireg_t); +pcireg_t pci_conf_read(pcitag_t, int); +void pci_conf_write(pcitag_t, int, pcireg_t); +#define pci_conf_read32 pci_conf_read +#define pci_conf_write32 pci_conf_write +int pci_conf_write_acked(pcitag_t, int, pcireg_t); + +uint8_t pci_int_line(uint8_t); + + +/* From _pci.c */ + +uint8_t pci_int_shift_0(pcitag_t); +uint8_t pci_int_map_0(pcitag_t); + + +/* From ldtinit.c */ + +#define LDT_PRIMARY 0 +#define LDT_SECONDARY 1 +unsigned pci_find_ldt_cap (pcitag_t tag, int secondary); + +void ldt_link_reset (pcitag_t tag, int delay); +int ldt_chain_init (pcitag_t tag, int bus, pci_flags_t flags); + + +/* From pci_subr.c */ + +void pci_bdfprintf(int bus, int device, int function, const char *fmt, ...) +#ifdef __long64 + __attribute__((__format__(__printf__,4,5))) +#endif + ; + + +/* PCI bus parameters */ +struct pci_bus { + unsigned char min_gnt; /* largest min grant */ + unsigned char max_lat; /* smallest max latency */ + unsigned char devsel; /* slowest devsel */ + char fast_b2b; /* support fast b2b */ + char prefetch; /* support prefetch */ + char freq66; /* support 66MHz */ + char width64; /* 64 bit bus */ + int bandwidth; /* # of .25us ticks/sec @ 33MHz */ + unsigned char ndev; /* # devices (functions) on bus */ + unsigned char def_ltim; /* default ltim counter */ + unsigned char max_ltim; /* maximum ltim counter */ + uint8_t primary; /* primary bus number */ + pcitag_t tag; /* tag for this bus */ + uint32_t min_io_addr; /* min I/O address allocated to bus */ + uint32_t max_io_addr; /* max I/O address allocated to bus */ + uint32_t min_mem_addr; /* min mem address allocated to bus */ + uint32_t max_mem_addr; /* max mem address allocated to bus */ + uint8_t inta_shift; /* base rotation of interrupt pins */ + char no_probe; /* skip businit and query probes */ +}; + +extern pcireg_t minpcimemaddr; +extern pcireg_t maxpcimemaddr; +extern pcireg_t minpciioaddr; +extern pcireg_t maxpciioaddr; + +extern struct pci_bus _pci_bus[]; +extern int _pci_nbus; +extern const int _pci_maxbus; + +#endif /* _PCIVAR_H_ */ diff --git a/cfe/cfe/ui/ui_cmddisp.c b/cfe/cfe/ui/ui_cmddisp.c new file mode 100644 index 0000000..8609f1c --- /dev/null +++ b/cfe/cfe/ui/ui_cmddisp.c @@ -0,0 +1,252 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * UI Command Dispatch File: ui_cmddisp.c + * + * This module contains routines to maintain the command table, + * parse and execute commands + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_setjmp.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "env_subr.h" +#include "cfe.h" +#include "ui_command.h" + +/* ********************************************************************* + * Types + ********************************************************************* */ + + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +static jmp_buf ui_jmpbuf; /* for getting control in exceptions */ + + + +void dumplist(queue_t *qb); +void dumplist(queue_t *qb) +{ + queue_t *q; + ui_token_t *t; + + for (q = qb->q_next; q != qb; q = q->q_next) { + + t = (ui_token_t *) q; + printf("[%s] ",&(t->token)); + } + printf("\n"); +} + + + +const char *ui_errstring(int errcode) +{ + return cfe_errortext(errcode); +} + + +int ui_showerror(int errcode,char *tmplt,...) +{ + va_list marker; + + va_start(marker,tmplt); + xvprintf(tmplt,marker); + va_end(marker); + xprintf(": %s\n",ui_errstring(errcode)); + + return errcode; +} + + + +static int ui_do_one_command(queue_t *head) +{ + int res; + ui_cmdline_t cmd; + + res = cmd_lookup(head, &cmd); + + if (res == 0) { + + res = cmd_sw_validate(&cmd,cmd.switches); + if (res != -1) { + xprintf("Invalid switch: %s\n", + cmd_sw_name(&cmd,res)); + return CFE_ERR_INV_PARAM; + } + + if (lib_setjmp(ui_jmpbuf) != 0) return -1; + res = (*cmd.func)(&cmd,cmd.argc-cmd.argidx, + &(cmd.argv[cmd.argidx])); + } + cmd_free(&cmd); + return res; +} + + +void ui_restart(int arg) +{ + if (arg == 0) arg = -1; + + lib_longjmp(ui_jmpbuf,arg); +} + +int ui_init_cmddisp(void) +{ + cmd_init(); + + return 0; +} + +int ui_showusage(ui_cmdline_t *cmd) +{ + cmd_showusage(cmd); + + return CFE_ERR_INV_COMMAND; +} + + +/* ********************************************************************* + * ui_docommands_internal(head) + * + * Process (possibly multiple) commands from a list of tokens + * + * Input parameters: + * buf - buffer + * + * Return value: + * exit status of first command that failed, or null + ********************************************************************* */ +static int ui_docommands_internal(queue_t *head) +{ + queue_t cmdqueue; + ui_command_t *cmd; + int status = CMD_ERR_BLANK; + int term; + + q_init(&cmdqueue); + + /* + * Find all the individual commands + */ + + while ((cmd = cmd_readcommand(head))) { + + if (cmd == NULL) { + return CMD_ERR_BLANK; + } + + q_enqueue(&cmdqueue,(queue_t *) cmd); + } + + /* + * Do each command + */ + + while ((cmd = (ui_command_t *) q_deqnext(&(cmdqueue)))) { + status = ui_do_one_command(&(cmd->head)); + term = cmd->term; + KFREE(cmd); + if (status == CMD_ERR_BLANK) continue; + + /* + * And causes us to stop at the first failure. + */ + if ((term == CMD_TERM_AND) && (status != 0)) break; + + /* + * OR causes us to stop at the first success. + */ + + if ((term == CMD_TERM_OR) && (status == 0)) break; + + /* + * Neither AND nor OR causes us to keep chugging away. + */ + } + + /* + * Free any remaining tokens and commands that we did not do + */ + + while ((cmd = (ui_command_t *) q_deqnext(&(cmdqueue)))) { + cmd_free_tokens(&(cmd->head)); + KFREE(cmd); + } + + return status; +} + + +int ui_docommands(char *str) +{ + queue_t cmd_list; + int res; + + /* Convert the command into a token list */ + cmd_build_list(&cmd_list,str); + + /* Walk the list and expand environment variables */ + cmd_walk_and_expand(&cmd_list); + + /* Process each command. This removes tokens from the list */ + res = ui_docommands_internal(&cmd_list); + + /* Free any leftover tokens. There should not be any. */ + cmd_free_tokens(&cmd_list); + + return res; +} diff --git a/cfe/cfe/ui/ui_command.c b/cfe/cfe/ui/ui_command.c new file mode 100644 index 0000000..79d770f --- /dev/null +++ b/cfe/cfe/ui/ui_command.c @@ -0,0 +1,990 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * UI Command Dispatch File: ui_command.c + * + * This module contains routines to maintain the command table, + * parse and execute commands + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include + +#include "lib_queue.h" + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "env_subr.h" +#include "cfe.h" + +#include "ui_command.h" + +#define MAX_EXPAND 16 + +typedef struct cmdtab_s { + struct cmdtab_s *sibling; + struct cmdtab_s *child; + char *cmdword; + int (*func)(ui_cmdline_t *,int argc,char *argv[]); + void *ref; + char *help; + char *usage; + char *switches; +} cmdtab_t; + +cmdtab_t *cmd_root; + +static void cmd_rejoin_quotes(queue_t *qb); + +#define myisalpha(x) (((x)>='A')&&((x)<='Z')&&((x)>='a')&&((x)<='z')) +#define myisdigit(x) (((x)>='0')&&((x)<='9')) + +char *varchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789_?"; + +static char *tokenbreaks = " =\t\n\'\"&|;"; +static char *spacechars = " \t"; + + + +static inline int is_white_space(ui_token_t *t) +{ + return (strchr(spacechars,t->token) != NULL); +} + +int cmd_sw_value(ui_cmdline_t *cmd,char *swname,char **swvalue) +{ + int idx; + + for (idx = 0; idx < cmd->swc; idx++) { + if (strcmp(swname,cmd->swv[idx].swname) == 0) { + *swvalue = cmd->swv[idx].swvalue; + return 1; + } + } + + return 0; +} + +int cmd_sw_posn(ui_cmdline_t *cmd,char *swname) +{ + int idx; + + for (idx = 0; idx < cmd->swc; idx++) { + if (strcmp(swname,cmd->swv[idx].swname) == 0) { + return cmd->swv[idx].swidx; + } + } + + return -1; +} + +char *cmd_sw_name(ui_cmdline_t *cmd,int swidx) +{ + if ((swidx < 0) || (swidx >= cmd->swc)) return NULL; + + return cmd->swv[swidx].swname; +} + + +int cmd_sw_isset(ui_cmdline_t *cmd,char *swname) +{ + int idx; + + for (idx = 0; idx < cmd->swc; idx++) { + if (strcmp(swname,cmd->swv[idx].swname) == 0) { + return 1; + } + } + + return 0; +} + +char *cmd_getarg(ui_cmdline_t *cmd,int argnum) +{ + argnum += cmd->argidx; + if ((argnum < 0) || (argnum >= cmd->argc)) return NULL; + return cmd->argv[argnum]; +} + +void cmd_free(ui_cmdline_t *cmd) +{ + int idx; + + for (idx = 0; idx < cmd->argc; idx++) { + KFREE(cmd->argv[idx]); + } + + for (idx = 0; idx < cmd->swc; idx++) { + KFREE(cmd->swv[idx].swname); + } + + cmd->argc = 0; + cmd->swc = 0; +} + +int cmd_sw_validate(ui_cmdline_t *cmd,char *validstr) +{ + char *vdup; + char *vptr; + char *vnext; + char atype; + char *x; + int idx; + int valid; + + if (cmd->swc == 0) return -1; + + vdup = strdup(validstr); + + for (idx = 0; idx < cmd->swc; idx++) { + vptr = vdup; + + vnext = vptr; + valid = 0; + + while (vnext) { + + /* + * Eat the next switch description from the valid string + */ + x = strchr(vptr,'|'); + if (x) { + *x = '\0'; + vnext = x+1; + } + else { + vnext = NULL; + } + + /* + * Get the expected arg type, if any + */ + x = strchr(vptr,'='); + if (x) { + atype = *(x+1); + *x = 0; + } + else { + if ((x = strchr(vptr,';'))) *x = 0; + atype = 0; + } + + /* + * See if this matches what the user typed + * XXX for now, ignore the arg type processing but + * complain if an arg is missing. + */ + + if (strcmp(vptr,cmd->swv[idx].swname) == 0) { + /* Value not needed and not supplied */ + if ((atype == 0) && (cmd->swv[idx].swvalue == NULL)) { + valid = 1; + } + /* value needed and supplied */ + if ((atype != 0) && (cmd->swv[idx].swvalue != NULL)) { + valid = 1; + } + strcpy(vdup,validstr); + break; + } + + /* + * Otherwise, next! + */ + + strcpy(vdup,validstr); + vptr = vnext; + } + + /* + * If not valid, return index of bad switch + */ + + if (valid == 0) { + KFREE(vdup); + return idx; + } + + } + + /* + * Return -1 if everything went well. A little strange, + * but it's easier this way. + */ + + KFREE(vdup); + return -1; +} + +static cmdtab_t *cmd_findword(cmdtab_t *list,char *cmdword) +{ + while (list) { + if (strcmp(cmdword,list->cmdword) == 0) return list; + list = list->sibling; + } + + return NULL; +} + + +void cmd_build_cmdline(queue_t *head, ui_cmdline_t *cmd) +{ + ui_token_t *t; + ui_token_t *next; + + memset(cmd, 0, sizeof(ui_cmdline_t)); + + t = (ui_token_t *) q_deqnext(head); + + while (t != NULL) { + if (is_white_space(t)) { + /* do nothing */ + } + else if (t->token != '-') { + if(cmd->argc < MAX_TOKENS){ + cmd->argv[cmd->argc] = lib_strdup(&(t->token)); + cmd->argc++; + } + /* Token is a switch */ + } + else { + if (cmd->swc < MAX_SWITCHES) { + cmd->swv[cmd->swc].swname = lib_strdup(&(t->token)); + + if (t->qb.q_next != head) { /* more tokens */ + next = (ui_token_t *) t->qb.q_next; + if (next->token == '=') { /* switch has value */ + KFREE(t); /* Free switch name */ + t = (ui_token_t *) q_deqnext(head); /* eat equal sign */ + KFREE(t); /* and free it */ + t = (ui_token_t *) q_deqnext(head); /* now have value */ + if (t != NULL) { + cmd->swv[cmd->swc].swvalue = lib_strdup(&(t->token)); + } + } + else { /* no value */ + cmd->swv[cmd->swc].swvalue = NULL; + } + } + /* + * swidx is the index of the argument that this + * switch precedes. So, if you have "foo -d bar", + * swidx for "-d" would be 1. + */ + cmd->swv[cmd->swc].swidx = cmd->argc; + cmd->swc++; + } + } + KFREE(t); + t = (ui_token_t *) q_deqnext(head); + } + +} + +int cmd_addcmd(char *command, + int (*func)(ui_cmdline_t *,int argc,char *argv[]), + void *ref, + char *help, + char *usage, + char *switches) +{ + cmdtab_t **list = &cmd_root; + cmdtab_t *cmd = NULL; + queue_t tokens; + queue_t *cur; + ui_token_t *t; + + cmd_build_list(&tokens,command); + cur = tokens.q_next; + + while (cur != &tokens) { + t = (ui_token_t *) cur; + if (!is_white_space(t)) { + cmd = cmd_findword(*list,&(t->token)); + if (!cmd) { + cmd = KMALLOC(sizeof(cmdtab_t)+strlen(&(t->token))+1,0); + memset(cmd,0,sizeof(cmdtab_t)); + cmd->cmdword = (char *) (cmd+1); + strcpy(cmd->cmdword,&(t->token)); + cmd->sibling = *list; + *list = cmd; + } + list = &(cmd->child); + } + cur = cur->q_next; + } + + cmd_free_tokens(&tokens); + + if (!cmd) return -1; + + cmd->func = func; + cmd->usage = usage; + cmd->ref = ref; + cmd->help = help; + cmd->switches = switches; + + return 0; +} + + + +static void _dumpindented(char *str,int amt) +{ + int idx; + char *dupstr; + char *end; + char *ptr; + + dupstr = strdup(str); + + ptr = dupstr; + + while (*ptr) { + for (idx = 0; idx < amt; idx++) printf(" "); + + end = strchr(ptr,'\n'); + + if (end) *end++ = '\0'; + else end = ptr + strlen(ptr); + + printf("%s\n",ptr); + ptr = end; + } + + KFREE(dupstr); +} + +static void _dumpswitches(char *str) +{ + char *switches; + char *end; + char *ptr; + char *semi; + char *newline; + + switches = strdup(str); + + ptr = switches; + + while (*ptr) { + end = strchr(ptr,'|'); + if (end) *end++ = '\0'; + else end = ptr + strlen(ptr); + + printf(" "); + if ((semi = strchr(ptr,';'))) { + *semi++ = '\0'; + newline = strchr(semi,'\n'); + if (newline) *newline++ = '\0'; + printf("%-12s %s\n",ptr,semi); + if (newline) _dumpindented(newline,5+12+1); + } + else { + printf("%-12s (no information)\n",ptr); + } + ptr = end; + } + + KFREE(switches); +} + +static void _dumpcmds(cmdtab_t *cmd,int level,char **words,int verbose) +{ + int idx; + int len; + + while (cmd) { + len = 0; + words[level] = cmd->cmdword; + if (cmd->func) { + for (idx = 0; idx < level; idx++) { + printf("%s ",words[idx]); + len += strlen(words[idx])+1; + } + printf("%s",cmd->cmdword); + len += strlen(cmd->cmdword); + for (idx = len; idx < 20; idx++) printf(" "); + printf("%s\n",cmd->help); + if (verbose) { + printf("\n"); + _dumpindented(cmd->usage,5); + printf("\n"); + _dumpswitches(cmd->switches); + printf("\n"); + } + } + _dumpcmds(cmd->child,level+1,words,verbose); + cmd = cmd->sibling; + } +} + +static void dumpcmds(int verbose) +{ + char *words[20]; + + _dumpcmds(cmd_root,0,words,verbose); +} + + +static void _showpossible(ui_cmdline_t *cline,cmdtab_t *cmd) +{ + int i; + + if (cline->argidx == 0) { + printf("Available commands: "); + } + else { + printf("Available \""); + for (i = 0; i < cline->argidx; i++) { + printf("%s%s",(i == 0) ? "" : " ",cline->argv[i]); + } + printf("\" commands: "); + } + + while (cmd) { + printf("%s",cmd->cmdword); + if (cmd->sibling) printf(", "); + cmd = cmd->sibling; + } + + printf("\n"); +} + +static int cmd_help(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + cmdtab_t **tab; + cmdtab_t *cword; + int idx; + + if (argc == 0) { + printf("Available commands:\n\n"); + dumpcmds(0); + printf("\n"); + printf("For more information about a command, enter 'help command-name'\n"); + } + else { + idx = 0; + tab = &cmd_root; + cword = NULL; + + for (;;) { + cword = cmd_findword(*tab,argv[idx]); + if (!cword) break; + if (cword->func != NULL) break; + idx++; + tab = &(cword->child); + if (idx >= argc) break; + } + + if (cword == NULL) { + printf("No help available for '%s'.\n\n",argv[idx]); + printf("Type 'help' for a list of commands.\n"); + return -1; + } + + if (!cword->func && (idx >= argc)) { + printf("No help available for '%s'.\n\n",cword->cmdword); + printf("Type 'help' for a list of commands.\n"); + return -1; + } + + printf("\n SUMMARY\n\n"); + _dumpindented(cword->help,5); + printf("\n USAGE\n\n"); + _dumpindented(cword->usage,5); + if (cword->switches && cword->switches[0]) { + printf("\n OPTIONS\n\n"); + _dumpswitches(cword->switches); + } + printf("\n"); + } + + return 0; +} + +void cmd_init(void) +{ + cmd_root = NULL; + + cmd_addcmd("help", + cmd_help, + NULL, + "Obtain help for CFE commands", + "help [command]\n\n" + "Without any parameters, the 'help' command will display a summary\n" + "of available commands. For more details on a command, type 'help'\n" + "and the command name.", + ""); +} + + +int cmd_lookup(queue_t *head,ui_cmdline_t *cmd) +{ + cmdtab_t **tab; + cmdtab_t *cword; + int idx; + + /* + * Reset the command line + */ + + memset(cmd,0,sizeof(ui_cmdline_t)); + + /* + * Break it up into tokens + */ + + cmd_build_cmdline(head, cmd); + + if (cmd->argc == 0) return CMD_ERR_BLANK; + + /* + * Start walking the tree looking for a function + * to execute. + */ + + idx = 0; + tab = &cmd_root; + cword = NULL; + + for (;;) { + cword = cmd_findword(*tab,cmd->argv[idx]); + if (!cword) break; + if (cword->func != NULL) break; + idx++; + tab = &(cword->child); + if (idx >= cmd->argc) break; + } + + cmd->argidx = idx; + +/* XXX - Must fix this... the error needs to walk the tree! */ + + if (cword == NULL) { + printf("Invalid command: \"%s\"\n", cmd->argv[idx]); + _showpossible(cmd,*tab); + printf("\n"); + return CMD_ERR_INVALID; + } + + if (!cword->func && (idx >= cmd->argc)) { + printf("Incomplete command: \"%s\"\n",cmd->argv[idx]); + _showpossible(cmd,*tab); + printf("\n"); + return CMD_ERR_AMBIGUOUS; + } + + cmd->argidx++; + cmd->ref = cword->ref; + cmd->usage = cword->usage; + cmd->switches = cword->switches; + cmd->func = cword->func; + + return 0; +} + + +void cmd_showusage(ui_cmdline_t *cmd) +{ + printf("\n"); + _dumpindented(cmd->usage,5); + printf("\n"); + if (cmd->switches[0]) { + _dumpswitches(cmd->switches); + printf("\n"); + } +} + + +static void cmd_eat_leading_white(queue_t *head) +{ + ui_token_t *t; + + while (!q_isempty(head)) { + t = (ui_token_t *) q_getfirst(head); + if (is_white_space(t)) { + q_dequeue(&(t->qb)); + KFREE(t); + } + else break; + } +} + +ui_command_t *cmd_readcommand(queue_t *head) +{ + char *ptr; + int insquote = FALSE; + int indquote = FALSE; + ui_command_t *cmd; + int term = CMD_TERM_EOL; + ui_token_t *t; + + cmd_eat_leading_white(head); + + if (q_isempty(head)) return NULL; + + cmd = (ui_command_t *) KMALLOC(sizeof(ui_command_t),0); + q_init(&(cmd->head)); + + while ((t = (ui_token_t *) q_deqnext(head))) { + + ptr = &(t->token); + + if (!insquote && !indquote) { + if ((*ptr == ';') || (*ptr == '\n')) { + term = CMD_TERM_SEMI; + break; + } + if ((*ptr == '&') && (*(ptr+1) == '&')) { + term = CMD_TERM_AND; + break; + } + if ((*ptr == '|') && (*(ptr+1) == '|')) { + term = CMD_TERM_OR; + break; + } + } + + if (*ptr == '\'') { + insquote = !insquote; + } + + if (!insquote) { + if (*ptr == '"') { + indquote = !indquote; + } + } + + q_enqueue(&(cmd->head),&(t->qb)); + + } + + cmd->term = term; + + /* If we got out by finding a command separator, eat the separator */ + if (term != CMD_TERM_EOL) { + KFREE(t); + } + + /* Turn quoted strings back into tokens */ + + cmd_rejoin_quotes(&(cmd->head)); + + return cmd; +} + + + +static ui_token_t *make_token(char *str,int len) +{ + ui_token_t *t = (ui_token_t *) KMALLOC(sizeof(ui_token_t) + len,0); + + memcpy(&(t->token),str,len); + (&(t->token))[len] = 0; + + return t; +} + +void cmd_build_list(queue_t *qb,char *buf) +{ + char *cur = buf, *start = NULL, *fin = NULL; + ui_token_t *t; + + q_init(qb); + + start = cur; + while(*cur != '\0'){ + if (*cur == '&' && *(cur + 1) != '&') { + /* Do nothing if we have only one & */ + } + else if (*cur == '|' && *(cur + 1) != '|') { + /* Do nothing if we have only one | */ + } + else if (((*cur == ' ')||(*cur == '\t')) && + ((*(cur - 1) == ' ')||(*(cur - 1) == '\t'))) { + /* Make one big token for white space */ + } + else { + + if (strchr(tokenbreaks,*cur)) { + if (cur != buf) { + fin = cur; + t = make_token(start,fin-start); + q_enqueue(qb,&(t->qb)); + start = cur; /* Start new token */ + } + } + else { + /* If we are on a normal character but the last character was */ + /* a special char we need to start a new token */ + + if ((cur > buf) && strchr(tokenbreaks,*(cur-1))) { + fin = cur; + t = make_token(start,fin-start); + q_enqueue(qb,&(t->qb)); + start = cur; /* Start new token */ + } + else { + /* If the last charecter wasn't special keep going with */ + /* current token */ + } + + + } + + } + cur++; + } + + fin = cur; + + if (fin-start > 0) { + t = make_token(start,fin-start); + q_enqueue(qb,&(t->qb)); + } + + return; +} + +static int is_command_separator(ui_token_t *t) +{ + char *string = &(t->token); + int sep = 0; + + switch(*string){ + case ';': + sep = 1; + break; + case '&': + if(*(string + 1) == '&') + sep = 1; + break; + case '|': + if(*(string + 1) == '|') + sep = 1; + default: + break; + } + + return(sep); +} + +static void cmd_append_tokens(queue_t *qb,char *str) +{ + queue_t *qq; + queue_t explist; + + cmd_build_list(&explist,str); + + while ((qq = q_deqnext(&explist))) { + q_enqueue(qb,qq); + } +} + +static void cmd_squash_and_append(queue_t *list,queue_t *quotelist) +{ + int maxlen = 0; + queue_t *q; + ui_token_t *t; + ui_token_t *newtok; + char *dest; + + for (q = quotelist->q_next; q != quotelist; q = q->q_next) { + maxlen += strlen(&(((ui_token_t *) q)->token)); + } + + newtok = KMALLOC(sizeof(ui_token_t) + maxlen,0); + + dest = &(newtok->token); + + while ((t = (ui_token_t *) q_deqnext(quotelist))) { + strcpy(dest,&(t->token)); + dest += strlen(dest); + KFREE(t); + } + + q_enqueue(list,&(newtok->qb)); +} + + +static void cmd_rejoin_quotes(queue_t *qb) +{ + queue_t newq; + queue_t quotedq; + queue_t *q; + ui_token_t *t; + int insquote = FALSE; + int indquote = FALSE; + + q_init(&newq); + q_init("edq); + + while ((t = (ui_token_t *) q_deqnext(qb))) { + + switch (t->token) { + case '\'': + KFREE(t); /* eat the quotes */ + + insquote = !insquote; + + if (!insquote) { + cmd_squash_and_append(&newq,"edq); + } + break; + + case '"': /* eat the quotes */ + KFREE(t); + + if (insquote == FALSE) { + indquote = !indquote; + if (!indquote) { + cmd_squash_and_append(&newq,"edq); + } + } + break; + + default: + if (insquote || indquote) { + q_enqueue("edq,&(t->qb)); + } + else { + q_enqueue(&newq,&(t->qb)); + } + + } + } + + /* + * If a dangling quoted string, just tack it on the list. + */ + + if (!q_isempty("edq)) { + cmd_squash_and_append(&newq,"edq); + } + + /* + * Put everything back on the original list. + */ + + while ((q = q_deqnext(&newq))) { + q_enqueue(qb,q); + } + + +} + +void cmd_walk_and_expand (queue_t *qb) +{ + queue_t *q; + queue_t newq; + ui_token_t *t; + int alias_check = TRUE; + int insquote = FALSE; + char *envstr; + + q_init(&newq); + + while ((t = (ui_token_t *) q_deqnext(qb))) { + if (t->token == '\'') { + alias_check = FALSE; + insquote = !insquote; + /* Check to see if we should try to expand this token */ + } + else if (!insquote) { + if (alias_check && !strchr(tokenbreaks,t->token) && + (envstr = env_getenv(&(t->token)))) { + /* Aliases: stick into token stream if no environment found */ + cmd_append_tokens(&newq,envstr); + KFREE(t); + t = NULL; + } + else if (t->token == '$') { + /* non-aliases: remove from token stream if no env found */ + envstr = env_getenv(&(t->token)+1); + if (envstr) cmd_append_tokens(&newq,envstr); + KFREE(t); + t = NULL; + } + else { + /* Drop down below, keep this token as-is and append */ + } + } + + /* + * If token was not removed, add it to the new queue + */ + + if (t) { + q_enqueue(&newq,&(t->qb)); + alias_check = is_command_separator(t); + } + + } + + /* + * Put everything back on the original list. + */ + + while ((q = q_deqnext(&newq))) { + q_enqueue(qb,q); + } + +} + +void cmd_free_tokens(queue_t *list) +{ + queue_t *q; + + while ((q = q_deqnext(list))) { + KFREE(q); + } +} + diff --git a/cfe/cfe/ui/ui_devcmds.c b/cfe/cfe/ui/ui_devcmds.c new file mode 100644 index 0000000..72ea7bb --- /dev/null +++ b/cfe/cfe/ui/ui_devcmds.c @@ -0,0 +1,101 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device Commands File: ui_devcmds.c + * + * User interface for the device manager + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "env_subr.h" +#include "ui_command.h" +#include "cfe.h" + + +extern queue_t cfe_devices; + +int ui_init_devcmds(void); + +static int ui_cmd_devnames(ui_cmdline_t *cmd,int argc,char *argv[]); + + +int ui_cmd_devnames(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + queue_t *qb; + cfe_device_t *dev; + + xprintf("Device Name Description\n"); + xprintf("------------------- ---------------------------------------------------------\n"); + + for (qb = cfe_devices.q_next; qb != &cfe_devices; qb = qb->q_next) { + dev = (cfe_device_t *) qb; + + xprintf("%19s %s\n",dev->dev_fullname, + dev->dev_description); + + } + + return 0; +} + + +int ui_init_devcmds(void) +{ + cmd_addcmd("show devices", + ui_cmd_devnames, + NULL, + "Display information about the installed devices.", + "show devices\n\n" + "This command displays the names and descriptions of the devices\n" + "CFE is configured to support.", + ""); + + return 0; +} diff --git a/cfe/cfe/ui/ui_envcmds.c b/cfe/cfe/ui/ui_envcmds.c new file mode 100644 index 0000000..9d69f36 --- /dev/null +++ b/cfe/cfe/ui/ui_envcmds.c @@ -0,0 +1,190 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Environment commands File: ui_envcmds.c + * + * User interface for environment variables + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "env_subr.h" +#include "ui_command.h" +#include "cfe.h" + + +int ui_init_envcmds(void); +static int ui_cmd_setenv(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_printenv(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_unsetenv(ui_cmdline_t *cmd,int argc,char *argv[]); + + + +static int ui_cmd_printenv(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char varname[80]; + char value[256]; + int varlen,vallen; + int idx; + + xprintf("Variable Name Value\n"); + xprintf("-------------------- --------------------------------------------------\n"); + + idx = 0; + for (;;) { + varlen = sizeof(varname); + vallen = sizeof(value); + if (env_enum(idx,varname,&varlen,value,&vallen) < 0) break; + xprintf("%20s %s\n",varname,value); + idx++; + } + + return 0; + +} + +static int ui_cmd_setenv(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *varname; + char *value; + int roflag = ENV_FLG_NORMAL; + int res; + + varname = cmd_getarg(cmd,0); + + if (!varname) { + return ui_showusage(cmd); + } + + value = cmd_getarg(cmd,1); + if (!value) { + return ui_showusage(cmd); + } + + if (!cmd_sw_isset(cmd,"-p")) { + roflag = ENV_FLG_BUILTIN; /* just in memory, not NVRAM */ + } + + if (cmd_sw_isset(cmd,"-ro")) { + roflag = ENV_FLG_READONLY; + } + + if ((res = env_setenv(varname,value,roflag)) == 0) { + if (roflag != ENV_FLG_BUILTIN) env_save(); + } + else { + return ui_showerror(res,"Could not set environment variable '%s'", + varname); + } + + return 0; +} + + +static int ui_cmd_unsetenv(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *varname; + int res; + int type; + + varname = cmd_getarg(cmd,0); + + if (!varname) { + return ui_showusage(cmd); + } + + type = env_envtype(varname); + + if ((res = env_delenv(varname)) == 0) { + if ((type >= 0) && (type != ENV_FLG_BUILTIN)) env_save(); + } + else { + return ui_showerror(res,"Could not delete environment variable '%s'", + varname); + } + + return 0; +} + + + +int ui_init_envcmds(void) +{ + + cmd_addcmd("setenv", + ui_cmd_setenv, + NULL, + "Set an environment variable.", + "setenv [-ro] [-p] varname value\n\n" + "This command sets an environment variable. By default, an environment variable\n" + "is stored only in memory and will not be retained across system restart.", + "-p;Store environment variable permanently in the NVRAM device, if present|" + "-ro;Causes variable to be read-only\n" + "(cannot be changed in the future, implies -p)"); + + cmd_addcmd("printenv", + ui_cmd_printenv, + NULL, + "Display the environment variables", + "printenv\n\n" + "This command prints a table of the environment variables and their\n" + "current values.", + ""); + + cmd_addcmd("unsetenv", + ui_cmd_unsetenv, + NULL, + "Delete an environment variable.", + "unsetenv varname\n\n" + "This command deletes an environment variable from memory and also \n" + "removes it from the NVRAM device (if present).", + ""); + + return 0; +} diff --git a/cfe/cfe/ui/ui_examcmds.c b/cfe/cfe/ui/ui_examcmds.c new file mode 100644 index 0000000..91edeee --- /dev/null +++ b/cfe/cfe/ui/ui_examcmds.c @@ -0,0 +1,713 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Memory dump commands File: ui_examcmds.c + * + * UI functions for examining data in various ways + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_console.h" + +#include "ui_command.h" +#include "cfe.h" +#include "disasm.h" + +#include "addrspace.h" +#include "exchandler.h" + + +static int ui_cmd_memdump(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_memedit(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_memfill(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_disasm(ui_cmdline_t *cmd,int argc,char *argv[]); + +#ifdef __long64 +#define XTOI(x) xtoq(x) +#else +#define XTOI(x) xtoi(x) +#endif + +int ui_init_examcmds(void); + + +#define ATYPE_SIZE_NONE 0 +#define ATYPE_SIZE_BYTE 1 +#define ATYPE_SIZE_HALF 2 +#define ATYPE_SIZE_WORD 4 +#define ATYPE_SIZE_QUAD 8 +#define ATYPE_SIZE_MASK 0x0F + +#define ATYPE_TYPE_NONE 0 +#define ATYPE_TYPE_PHYS 0x10 +#define ATYPE_TYPE_KERN 0x20 +#define ATYPE_TYPE_MASK 0xF0 + +static long prev_addr = 0; /* initialized below in ui_init_examcmds */ +static int prev_length = 256; +static int prev_dlength = 16; +static int prev_wtype = ATYPE_SIZE_WORD | ATYPE_TYPE_KERN; + +static int getaddrargs(ui_cmdline_t *cmd,int *curtype,long *addr,int *length) +{ + int atype = *curtype; + long newaddr; + int newlen; + char *x; + long wlen; + + if (cmd_sw_isset(cmd,"-b")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_BYTE; + } + else if (cmd_sw_isset(cmd,"-h")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_HALF; + } + else if (cmd_sw_isset(cmd,"-w")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_WORD; + } + else if (cmd_sw_isset(cmd,"-q")) { + atype &= ~ATYPE_SIZE_MASK; + atype |= ATYPE_SIZE_QUAD; + } + + wlen = atype & ATYPE_SIZE_MASK; + if (wlen == 0) wlen = 1; /* bytes are the default */ + + if (cmd_sw_isset(cmd,"-p")) { + atype &= ~ATYPE_TYPE_MASK; + atype |= ATYPE_TYPE_PHYS; + } + else if (cmd_sw_isset(cmd,"-v")) { + atype &= ~ATYPE_TYPE_MASK; + atype |= ATYPE_TYPE_KERN; + } + + *curtype = atype; + + if (addr) { + x = cmd_getarg(cmd,0); + if (x) { + if (strcmp(x,".") == 0) newaddr = *addr; + else { + /* + * hold on to your lunch, this is really, really bad! + * Make 64-bit addresses expressed as 8-digit numbers + * sign extend automagically. Saves typing, but is very + * gross. + */ + int longaddr = 0; + longaddr = strlen(x); + if (memcmp(x,"0x",2) == 0) longaddr -= 2; + longaddr = (longaddr > 8) ? 1 : 0; + + if (longaddr) newaddr = (long) xtoq(x); + else newaddr = (long) xtoi(x); + } + *addr = newaddr & ~(wlen - 1); /* align to natural boundary */ + } + } + + if (length) { + x = cmd_getarg(cmd,1); + if (x) { + newlen = (long) xtoi(x); + *length = newlen; + } + } + + return 0; + +} + +static int stuffmem(long addr,int wlen,char *tail) +{ + char *tok; + int count = 0; + uint8_t b; + uint16_t h; + uint32_t w; + uint64_t q; + int res = 0; + + addr &= ~(wlen-1); + + while ((tok = gettoken(&tail))) { + switch (wlen) { + default: + case 1: + b = (uint8_t) xtoq(tok); + if ((res = mem_poke(addr, b, MEM_BYTE))) { + /*Did not edit*/ + return res; + } + break; + case 2: + h = (uint16_t) xtoq(tok); + if ((res = mem_poke(addr, h, MEM_HALFWORD))) { + /*Did not edit*/ + return res; + } + break; + case 4: + w = (uint32_t) xtoq(tok); + if ((res = mem_poke(addr, w, MEM_WORD))) { + /*Did not edit*/ + return res; + } + break; + case 8: + q = (uint64_t) xtoq(tok); + if ((res = mem_poke(addr, q, MEM_QUADWORD))) { + /*Did not edit*/ + return res; + } + break; + } + + addr += wlen; + count++; + } + + return count; +} + +static int dumpmem(long addr,long dispaddr,int length,int wlen) +{ + int idx,x; + uint8_t b; + uint16_t h; + uint32_t w; + uint64_t q; + int res = 0; + + /* + * The reason we save the line in this union is to provide the + * property that the dump command will only touch the + * memory once. This might be useful when looking at + * device registers. + */ + + union { + uint8_t bytes[16]; + uint16_t halves[8]; + uint32_t words[4]; + uint64_t quads[2]; + } line; + + addr &= ~(wlen-1); + + for (idx = 0; idx < length; idx += 16) { + xprintf("%P%c ",dispaddr+idx,(dispaddr != addr) ? '%' : ':'); + switch (wlen) { + default: + case 1: + for (x = 0; x < 16; x++) { + if (idx+x < length) { + if ((res = mem_peek(&b, (addr+idx+x), MEM_BYTE))) { + return res; + } + line.bytes[x] = b; + xprintf("%02X ",b); + } + else { + xprintf(" "); + } + } + break; + case 2: + for (x = 0; x < 16; x+=2) { + if (idx+x < length) { + if ((res = mem_peek(&h, (addr+idx+x), MEM_HALFWORD))) { + return res; + } + line.halves[x/2] = h; + xprintf("%04X ",h); + } + else { + xprintf(" "); + } + } + break; + case 4: + for (x = 0; x < 16; x+=4) { + if (idx+x < length) { + + if ((res = mem_peek(&w , (addr+idx+x), MEM_WORD))) { + return res; + } + line.words[x/4] = w; + xprintf("%08X ",w); + } + else { + xprintf(" "); + } + } + break; + case 8: + for (x = 0; x < 16; x+=8) { + if (idx+x < length) { + if ((res = mem_peek(&q, (addr+idx+x), MEM_QUADWORD))) { + return res; + } + line.quads[x/8] = q; + xprintf("%016llX ",q); + } + else { + xprintf(" "); + } + } + break; + } + + xprintf(" "); + for (x = 0; x < 16; x++) { + if (idx+x < length) { + b = line.bytes[x]; + if ((b < 32) || (b > 127)) xprintf("."); + else xprintf("%c",b); + } + else { + xprintf(" "); + } + } + xprintf("\n"); + } + + return 0; +} + +static int ui_cmd_memedit(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + uint8_t b; + uint16_t h; + uint32_t w; + uint64_t q; + + long addr; + char *vtext; + int wlen; + int count; + int idx = 1; + int stuffed = 0; + int res = 0; + + getaddrargs(cmd,&prev_wtype,&prev_addr,NULL); + + wlen = prev_wtype & ATYPE_SIZE_MASK; + + vtext = cmd_getarg(cmd,idx++); + + addr = prev_addr; + + while (vtext) { + count = stuffmem(addr,wlen,vtext); + if (count < 0) { + ui_showerror(count,"Could not modify memory"); + return count; /* error */ + } + addr += count*wlen; + prev_addr += count*wlen; + stuffed += count; + vtext = cmd_getarg(cmd,idx++); + } + + if (stuffed == 0) { + char line[256]; + char prompt[32]; + + xprintf("Type '.' to exit, '-' to back up, '=' to dump memory.\n"); + for (;;) { + + addr = prev_addr; + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + xprintf("%P%c ",prev_addr,(addr != prev_addr) ? '%' : ':'); + + switch (wlen) { + default: + case 1: + if ((res = mem_peek(&b, addr, MEM_BYTE))) { + return res; + } + xsprintf(prompt,"[%02X]: ", b); + break; + case 2: + if ((res = mem_peek(&h, addr, MEM_HALFWORD))) { + return res; + } + xsprintf(prompt,"[%04X]: ",h); + break; + case 4: + if ((res = mem_peek(&w, addr, MEM_WORD))) { + return res; + } + xsprintf(prompt,"[%08X]: ",w); + break; + case 8: + if ((res = mem_peek(&q, addr, MEM_QUADWORD))) { + return res; + } + xsprintf(prompt,"[%016llX]: ",q); + break; + } + + console_readline(prompt,line,sizeof(line)); + if (line[0] == '-') { + prev_addr -= wlen; + continue; + } + if (line[0] == '=') { + dumpmem(prev_addr,prev_addr,16,wlen); + continue; + } + if (line[0] == '.') { + break; + } + if (line[0] == '\0') { + prev_addr += wlen; + continue; + } + count = stuffmem(addr,wlen,line); + if (count < 0) return count; + if (count == 0) break; + prev_addr += count*wlen; + } + } + + return 0; +} + +static int ui_cmd_memfill(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr; + char *atext; + int wlen; + int idx = 2; + int len; + uint64_t pattern; + uint8_t *b_ptr; + uint16_t *h_ptr; + uint32_t *w_ptr; + uint64_t *q_ptr; + int res; + + getaddrargs(cmd,&prev_wtype,&prev_addr,&len); + + atext = cmd_getarg(cmd,idx++); + if (!atext) return ui_showusage(cmd); + pattern = xtoq(atext); + + addr = prev_addr; + + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + wlen = prev_wtype & ATYPE_SIZE_MASK; + + switch (wlen) { + case 1: + b_ptr = (uint8_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(b_ptr)), pattern, MEM_BYTE))) { + /*Did not edit*/ + return 0; + } + b_ptr++; + len--; + } + break; + case 2: + h_ptr = (uint16_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(h_ptr)), pattern, MEM_HALFWORD))) { + return 0; + } + h_ptr++; + len--; + } + break; + case 4: + w_ptr = (uint32_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(w_ptr)), pattern, MEM_WORD))) { + return -1; + } + w_ptr++; + len--; + } + break; + case 8: + q_ptr = (uint64_t *) addr; + while (len > 0) { + if ((res = mem_poke( ((long)(q_ptr)), pattern, MEM_QUADWORD))) { + return 0; + } + q_ptr++; + len--; + } + break; + } + + return 0; +} + + +#define FILL(ptr,len,pattern) printf("Pattern: %016llX\n",pattern); \ + for (idx = 0; idx < len; idx++) ptr[idx] = pattern +#define CHECK(ptr,len,pattern) for (idx = 0; idx < len; idx++) { \ + if (ptr[idx]!=pattern) {printf("Mismatch at %016llX: Expected %016llX got %016llX", \ + (uint64_t) (uintptr_t) &(ptr[idx]),pattern,ptr[idx]); \ + error = 1; loopmode = 0;break;} \ + } + +#define MEMTEST(ptr,len,pattern) if (!error) { FILL(ptr,len,pattern) ; CHECK(ptr,len,pattern); } + +static int ui_cmd_memtest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr = 0; + int len = 0; + int wtype = 0; + int wlen; + int idx = 0; + uint64_t *ptr; + int error = 0; + int loopmode = 0; + int pass =0; + + getaddrargs(cmd,&wtype,&addr,&len); + + wlen = 8; + addr &= ~(wlen-1); + + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + if (cmd_sw_isset(cmd,"-loop")) { + loopmode = 1; + } + + len /= wlen; + + ptr = (uint64_t *) addr; + pass = 0; + for (;;) { + if (loopmode) { + printf("Pass %d\n",pass); + if (console_status()) break; + } + MEMTEST(ptr,len,(idx*8)); + MEMTEST(ptr,len, 0); + MEMTEST(ptr,len,0xFFFFFFFFFFFFFFFF); + MEMTEST(ptr,len,0x5555555555555555); + MEMTEST(ptr,len,0xAAAAAAAAAAAAAAAA); + MEMTEST(ptr,len,0xFF00FF00FF00FF00); + MEMTEST(ptr,len,0x00FF00FF00FF00FF); + if (!loopmode) break; + pass++; + } + + return 0; +} + +static int ui_cmd_memdump(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr; + int res; + + getaddrargs(cmd,&prev_wtype,&prev_addr,&prev_length); + + addr = prev_addr; + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + res = dumpmem(addr, + prev_addr, + prev_length, + prev_wtype & ATYPE_SIZE_MASK); + + if (res < 0) { + ui_showerror(res,"Could not display memory"); + } + else { + prev_addr += prev_length; + } + + return res; +} + +static int ui_cmd_disasm(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + long addr; + char buf[512]; + int idx; + uint32_t inst; + int res; + + getaddrargs(cmd,&prev_wtype,&prev_addr,&prev_dlength); + + prev_addr &= ~3; + + addr = prev_addr; + if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { + addr = UNCADDR(addr); + } + + for (idx = 0; idx < prev_dlength; idx++) { + if ((res = mem_peek(&inst, addr, MEM_WORD))) { + ui_showerror(res,"Could not disassemble memory"); + return res; + } + disasm_inst(buf,sizeof(buf),inst,(uint64_t) prev_addr); + xprintf("%P%c %08x %s\n",prev_addr,(addr != prev_addr) ? '%' : ':',inst,buf); + addr += 4; + prev_addr += 4; + } + + return 0; +} + +int ui_init_examcmds(void) +{ + cmd_addcmd("u", + ui_cmd_disasm, + NULL, + "Disassemble instructions.", + "u [addr [length]]\n\n" + "This command disassembles instructions at the specified address.\n" + "CFE will display standard register names and symbolic names for\n" + "certain CP0 registers. The 'u' command remembers the last address\n" + "that was disassembled so you can enter 'u' again with no parameters\n" + "to continue a previous request.\n", + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + + cmd_addcmd("d", + ui_cmd_memdump, + NULL, + "Dump memory.", + "d [-b|-h|-w|-q] [addr [length]]\n\n" + "This command displays data from memory as bytes, halfwords, words,\n" + "or quadwords. ASCII text, if present, will appear to the right of\n" + "the hex data. The dump command remembers the previous word size,\n" + "dump length and last displayed address, so you can enter 'd' again\n" + "to continue a previous dump request.", + "-b;Dump memory as bytes|" + "-h;Dump memory as halfwords (16-bits)|" + "-w;Dump memory as words (32-bits)|" + "-q;Dump memory as quadwords (64-bits)|" + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + + cmd_addcmd("e", + ui_cmd_memedit, + NULL, + "Modify contents of memory.", + "e [-b|-h|-w|-q] [addr [data...]]\n\n" + "This command modifies the contents of memory. If you do not specify\n" + "data on the command line, CFE will prompt for it. When prompting for\n" + "data you may enter '-' to back up, '=' to dump memory at the current\n" + "location, or '.' to exit edit mode.", + "-b;Edit memory as bytes|" + "-h;Edit memory as halfwords (16-bits)|" + "-w;Edit memory as words (32-bits)|" + "-q;Edit memory as quadwords (64-bits)|" + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + cmd_addcmd("f", + ui_cmd_memfill, + NULL, + "Fill contents of memory.", + "f [-b|-h|-w|-q] addr length pattern\n\n" + "This command modifies the contents of memory. You can specify the\n" + "starting address, length, and pattern of data to fill (in hex)\n", + "-b;Edit memory as bytes|" + "-h;Edit memory as halfwords (16-bits)|" + "-w;Edit memory as words (32-bits)|" + "-q;Edit memory as quadwords (64-bits)|" + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address"); + + cmd_addcmd("memtest", + ui_cmd_memtest, + NULL, + "Test memory.", + "memtest [options] addr length\n\n" + "This command tests memory. It is a very crude test, so don't\n" + "rely on it for anything really important. Addr and length are in hex\n", + "-p;Address is an uncached physical address|" + "-v;Address is a kernel virtual address|" + "-loop;Loop till keypress"); + + + prev_addr = KERNADDR(0); + + return 0; +} + + + + + + + + + + + diff --git a/cfe/cfe/ui/ui_flash.c b/cfe/cfe/ui/ui_flash.c new file mode 100644 index 0000000..d3ce7c1 --- /dev/null +++ b/cfe/cfe/ui/ui_flash.c @@ -0,0 +1,554 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash Update commands File: ui_flash.c + * + * The routines in this file are used for updating the + * flash with new firmware. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_error.h" + +#include "ui_command.h" +#include "cfe.h" + +#include "cfe_fileops.h" +#include "cfe_boot.h" +#include "bsp_config.h" + +#include "cfe_loader.h" + +#include "net_ebuf.h" +#include "net_ether.h" +#include "net_api.h" + +#include "cfe_flashimage.h" + +#include "addrspace.h" +#include "url.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* + * Of course, these things really belong somewhere else. + */ + +#define FLASH_STAGING_BUFFER CFG_FLASH_STAGING_BUFFER_ADDR +#ifdef _FLASHPROG_ +#define FLASH_STAGING_BUFFER_SIZE (1024*1024*16) +#else +#define FLASH_STAGING_BUFFER_SIZE CFG_FLASH_STAGING_BUFFER_SIZE +#endif + + +/* ********************************************************************* + * Exerns + ********************************************************************* */ + +extern int cfe_iocb_dispatch(cfe_iocb_t *iocb); + +int ui_init_flashcmds(void); +static int ui_cmd_flash(ui_cmdline_t *cmd,int argc,char *argv[]); + + + +/* ********************************************************************* + * ui_init_flashcmds() + * + * Initialize the flash commands, add them to the table. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok, else error + ********************************************************************* */ + +int ui_init_flashcmds(void) +{ + cmd_addcmd("flash", + ui_cmd_flash, + NULL, + "Update a flash memory device", + "flash [options] filename [flashdevice]\n\n" + "Copies data from a source file name or device to a flash memory device.\n" + "The source device can be a disk file (FAT filesystem), a remote file\n" + "(TFTP) or a flash device. The destination device may be a flash or eeprom.\n" +#if !CFG_EMBEDDED_PIC + "If the destination device is your boot flash (usually flash0), the flash\n" + "command will restart the firmware after the flash update is complete\n" +#endif + "", + "-noerase;Don't erase flash before writing|" + "-offset=*;Begin programming at this offset in the flash device|" + "-size=*;Size of source device when programming from flash to flash|" + "-noheader;Override header verification, flash binary without checking"); + + + return 0; +} + +/* ********************************************************************* + * flash_crc32(buf,len) + * + * Yes, this is an Ethernet CRC. I'm lazy. + * + * Input parameters: + * buf - buffer to CRC + * len - length of data + * + * Return value: + * CRC-32 + ********************************************************************* */ + +#define CRC32_POLY 0xEDB88320UL /* CRC-32 Poly */ +static unsigned int +flash_crc32(const unsigned char *databuf, unsigned int datalen) +{ + unsigned int idx, bit, data, crc = 0xFFFFFFFFUL; + + for (idx = 0; idx < datalen; idx++) { + for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) { + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CRC32_POLY : 0); + } + } + + return crc; +} + +/* ********************************************************************* + * flash_validate(ptr) + * + * Validate the flash header to make sure we can program it. + * + * Input parameters: + * ptr - pointer to flash header + * outptr - pointer to data that we should program + * outsize - size of data we should program + * + * Return value: + * 0 if ok + * else error occured + ********************************************************************* */ + +#define GET32(x) (((uint32_t) (x[0] << 24)) | \ + ((uint32_t) (x[1] << 16)) | \ + ((uint32_t) (x[2] << 8)) | \ + ((uint32_t) (x[3] << 0))) + +static int flash_validate(uint8_t *ptr,int insize,uint8_t **outptr,int *outsize) +{ + cfe_flashimage_t *hdr = (cfe_flashimage_t *) ptr; + uint32_t size; + uint32_t flags; + uint32_t hdrcrc; + uint32_t calccrc; + + if (memcmp(hdr->seal,CFE_IMAGE_SEAL,sizeof(hdr->seal)) != 0) { + printf("Invalid header seal. This is not a CFE flash image.\n"); + return -1; + } + + printf("Flash image contains CFE version %d.%d.%d for board '%s'\n", + hdr->majver,hdr->minver,hdr->ecover,hdr->boardname); + + size = GET32(hdr->size); + flags = GET32(hdr->flags); + hdrcrc = GET32(hdr->crc); + printf("Flash image is %d bytes, flags %08X, CRC %08X\n",size,flags,hdrcrc); + + if (strcmp(CFG_BOARDNAME,hdr->boardname) != 0) { + printf("This flash image is not appropriate for board type '%s'\n",CFG_BOARDNAME); + return -1; + } + + if ((size == 0) || (size > FLASH_STAGING_BUFFER_SIZE) || + ((size + sizeof(cfe_flashimage_t)) < insize)) { + printf("Flash image size is bogus!\n"); + return -1; + } + + calccrc = flash_crc32(ptr + sizeof(cfe_flashimage_t),size); + + if (calccrc != hdrcrc) { + printf("CRC is incorrect. Calculated CRC is %08X\n",calccrc); + return -1; + } + + *outptr = ptr + sizeof(cfe_flashimage_t); + *outsize = size; + return 0; +} + +/* ********************************************************************* + * ui_cmd_flash(cmd,argc,argv) + * + * The 'flash' command lives here. Program the boot flash, + * or if a device name is specified, program the alternate + * flash device. + * + * Input parameters: + * cmd - command table entry + * argc,argv - parameters + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + + +static int ui_cmd_flash(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + uint8_t *ptr; + int fh; + int res; +#if !CFG_EMBEDDED_PIC + int retlen; +#endif + char *fname; + char *flashdev; + cfe_loadargs_t la; + int amtcopy; + int devtype; + int srcdevtype; + int chkheader; + int sfd; + int copysize; + flash_info_t flashinfo; + int offset = 0; + int noerase = 0; + char *x; + int size = 0; + + /* + * Get the address of the staging buffer. We can't + * allocate the space from the heap to store the + * new flash image, because the heap may not be big + * enough. So, grab some unallocated memory + * at the 1MB line (we could also calculate + * something, but this will do for now). + * We assume the flash will be somewhere between + * 1KB (yeah, right) and 4MB. + */ + +#if CFG_RUNFROMKSEG0 + ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); +#else + ptr = (uint8_t *) UNCADDR(FLASH_STAGING_BUFFER); +#endif + + /* + * Parse command line parameters + */ + + fname = cmd_getarg(cmd,0); + + if (!fname) { + return ui_showusage(cmd); + } + + flashdev = cmd_getarg(cmd,1); + if (!flashdev) flashdev = "flash0.0"; + + /* + * Make sure it's a flash device. + */ + + res = cfe_getdevinfo(flashdev); + if (res < 0) { + return ui_showerror(CFE_ERR_DEVNOTFOUND,flashdev); + } + + devtype = res & CFE_DEV_MASK; + + if ((res != CFE_DEV_FLASH) && (res != CFE_DEV_NVRAM)) { + xprintf("Device '%s' is not a flash or eeprom device.\n",flashdev); + return CFE_ERR_INV_PARAM; + } + + /* + * We shouldn't really allow this, but there are some circumstances + * where you might want to bypass the header check and shoot + * yourself in the foot. + * Switch normally not supplied, so chkheader will be TRUE. + */ + + chkheader = !cmd_sw_isset(cmd,"-noheader"); + + /* + * Check for some obscure options here. + */ + + noerase = cmd_sw_isset(cmd,"-noerase"); + + if (cmd_sw_value(cmd,"-offset",&x)) { + offset = atoi(x); + } + + if (cmd_sw_value(cmd,"-size",&x)) { + size = atoi(x); + } + + /* + * Read the new flash image from the source device + */ + + srcdevtype = cfe_getdevinfo(fname) & CFE_DEV_MASK; + + xprintf("Reading %s: ",fname); + + switch (srcdevtype) { + case CFE_DEV_FLASH: + sfd = cfe_open(fname); + if (sfd < 0) { + return ui_showerror(sfd,"Could not open source device"); + } + memset(ptr,0xFF,FLASH_STAGING_BUFFER_SIZE); + + /* + * If the flash device can be used for NVRAM, + * then the max size of or flash is the + * offset of the flash info. Otherwise + * it is the full staging buffer size. + * XXX: if it's larger, we lose. + */ + + if (cfe_ioctl(sfd,IOCTL_FLASH_GETINFO, + (unsigned char *) &flashinfo, + sizeof(flash_info_t), + &res,0) != 0) { + flashinfo.flash_size = FLASH_STAGING_BUFFER_SIZE; + } + + if (size > 0) { + xprintf("(size=0x%X) ",size); + } + else { + size = flashinfo.flash_size; + } + + /* Make sure we don't overrun the staging buffer */ + + if (size > FLASH_STAGING_BUFFER_SIZE) { + size = FLASH_STAGING_BUFFER_SIZE; + } + + /* Read the flash device here. */ + + res = cfe_read(sfd,ptr,size); + + cfe_close(sfd); + if (res < 0) { + return ui_showerror(res,"Could not read from flash"); + } + chkheader = FALSE; /* no header to check */ + /* + * Search for non-0xFF byte at the end. This will work because + * flashes get erased to all FF's, we pre-fill our buffer to FF's, + */ + while (res > 0) { + if (ptr[res-1] != 0xFF) break; + res--; + } + break; + + case CFE_DEV_SERIAL: + la.la_filesys = "raw"; + la.la_filename = NULL; + la.la_device = fname; + la.la_address = (intptr_t) ptr; + la.la_options = 0; + la.la_maxsize = FLASH_STAGING_BUFFER_SIZE; + la.la_flags = LOADFLG_SPECADDR; + + res = cfe_load_program("srec",&la); + + if (res < 0) { + ui_showerror(res,"Failed."); + return res; + } + break; + + default: + + res = ui_process_url(fname, cmd, &la); + if (res < 0) { + ui_showerror(res,"Invalid file name %s",fname); + return res; + } + + la.la_address = (intptr_t) ptr; + la.la_options = 0; + la.la_maxsize = FLASH_STAGING_BUFFER_SIZE; + la.la_flags = LOADFLG_SPECADDR; + + res = cfe_load_program("raw",&la); + + if (res < 0) { + ui_showerror(res,"Failed."); + return res; + } + break; + + } + + xprintf("Done. %d bytes read\n",res); + + copysize = res; + + /* + * Verify the header and file's CRC. + */ + if (chkheader) { + if (flash_validate(ptr,res,&ptr,©size) < 0) return -1; + } + + if (copysize == 0) return 0; /* 0 bytes, don't flash */ + + /* + * Open the destination flash device. + */ + + fh = cfe_open(flashdev); + if (fh < 0) { + xprintf("Could not open device '%s'\n",flashdev); + return CFE_ERR_DEVNOTFOUND; + } + + if (cfe_ioctl(fh,IOCTL_FLASH_GETINFO, + (unsigned char *) &flashinfo, + sizeof(flash_info_t), + &res,0) == 0) { + /* Truncate write if source size is greater than flash size */ + if ((copysize + offset) > flashinfo.flash_size) { + copysize = flashinfo.flash_size; + } + } + + /* + * If overwriting the boot flash, we need to use the special IOCTL + * that will force a reboot after writing the flash. + */ + + if (flashinfo.flash_base == 0x1FC00000) { /* XXX MIPS-SPECIFIC */ +#if CFG_EMBEDDED_PIC + xprintf("\n\n** DO NOT TURN OFF YOUR MACHINE UNTIL THE FLASH UPDATE COMPLETES!! **\n\n"); +#else +#if CFG_NETWORK + if (net_getparam(NET_DEVNAME)) { + xprintf("Closing network.\n"); + net_uninit(); + } +#endif + xprintf("Rewriting boot flash device '%s'\n",flashdev); + xprintf("\n\n**DO NOT TURN OFF YOUR MACHINE UNTIL IT REBOOTS!**\n\n"); + cfe_ioctl(fh,IOCTL_FLASH_WRITE_ALL, ptr,copysize,&retlen,0); + /* should not return */ + return CFE_ERR; +#endif + } + + /* + * Otherwise: it's not the flash we're using right + * now, so we can be more verbose about things, and + * more importantly, we can return to the command + * prompt without rebooting! + */ + + /* + * Erase the flash, if the device requires it. Our new flash + * driver does the copy/merge/erase for us. + */ + + if (!noerase) { + if ((devtype == CFE_DEV_FLASH) && !(flashinfo.flash_flags & FLASH_FLAG_NOERASE)) { + flash_range_t range; + range.range_base = offset; + range.range_length = copysize; + xprintf("Erasing flash..."); + if (cfe_ioctl(fh,IOCTL_FLASH_ERASE_RANGE, + (uint8_t *) &range,sizeof(range),NULL,0) != 0) { + printf("Failed to erase the flash\n"); + cfe_close(fh); + return CFE_ERR_IOERR; + } + } + } + + /* + * Program the flash + */ + + xprintf("Programming..."); + + amtcopy = cfe_writeblk(fh,offset,ptr,copysize); + + if (copysize == amtcopy) { + xprintf("done. %d bytes written\n",amtcopy); + res = 0; + } + else { + ui_showerror(amtcopy,"Failed."); + res = CFE_ERR_IOERR; + } + + /* + * done! + */ + + cfe_close(fh); + + return res; +} + diff --git a/cfe/cfe/ui/ui_loadcmds.c b/cfe/cfe/ui/ui_loadcmds.c new file mode 100644 index 0000000..a1df159 --- /dev/null +++ b/cfe/cfe/ui/ui_loadcmds.c @@ -0,0 +1,366 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Program Loader commands File: ui_loadcmds.c + * + * User interface for program loader + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" + +#include "ui_command.h" +#include "cfe.h" + +#include "net_ebuf.h" +#include "net_ether.h" +#include "net_api.h" + +#include "cfe_fileops.h" +#include "cfe_boot.h" + +#include "bsp_config.h" +#include "cfe_loader.h" +#include "cfe_autoboot.h" + +#include "url.h" + + +int ui_init_loadcmds(void); +static int ui_cmd_load(ui_cmdline_t *cmd,int argc,char *argv[]); + +#if CFG_NETWORK +static int ui_cmd_save(ui_cmdline_t *cmd,int argc,char *argv[]); +#endif + +static int ui_cmd_autoboot(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_boot(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_batch(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_go(ui_cmdline_t *cmd,int argc,char *argv[]); + + +extern cfe_loadargs_t cfe_loadargs; + +static long getaddr(char *str) +{ + /* + * hold on to your lunch, this is really, really bad! + * Make 64-bit addresses expressed as 8-digit numbers + * sign extend automagically. Saves typing, but is very + * gross. Not very portable, either. + */ + int longaddr = 0; + long newaddr; + + longaddr = strlen(str); + if (memcmp(str,"0x",2) == 0) longaddr -= 2; + longaddr = (longaddr > 8) ? 1 : 0; + + if (longaddr) newaddr = (long) xtoq(str); + else newaddr = (long) xtoi(str); + + return newaddr; +} + + + +int ui_init_loadcmds(void) +{ + +#if CFG_NETWORK + cmd_addcmd("save", + ui_cmd_save, + NULL, + "Save a region of memory to a remote file via TFTP", + "save [-options] host:filename startaddr length\n\n", + ""); +#endif + + cmd_addcmd("load", + ui_cmd_load, + NULL, + "Load an executable file into memory without executing it", + "load [-options] host:filename|dev:filename\n\n" + "This command loads an executable file into memory, but does not\n" + "execute it. It can be used for loading data files, overlays or\n" + "other programs needed before the 'boot' command is used. By\n" + "default, 'load' will load a raw binary at virtual address 0x20000000.", + "-elf;Load the file as an ELF executable|" + "-srec;Load the file as ASCII S-records|" + "-raw;Load the file as a raw binary|" +#if CFG_ZLIB + "-z;Load compessed file|" +#endif + "-loader=*;Specify CFE loader name|" + "-tftp;Load the file using the TFTP protocol|" + "-fatfs;Load the file from a FAT file system|" + "-rawfs;Load the file from an unformatted file system|" +#if (CFG_TCP) && (CFG_HTTPFS) + "-http;Load the file using the HTTP protocol|" +#endif + "-fs=*;Specify CFE file system name|" + "-max=*;Specify the maximum number of bytes to load (raw only)|" + "-addr=*;Specify the load address (hex) (raw only)"); + + cmd_addcmd("boot", + ui_cmd_boot, + NULL, + "Load an executable file into memory and execute it", + "boot [-options] host:filename|dev:filename\n\n" + "This command loads and executes a program from a boot device\n" + "By default, 'boot' will load a raw binary at virtual \n" + "address 0x20000000 and then jump to that address", + "-elf;Load the file as an ELF executable|" + "-srec;Load the file as ASCII S-records|" + "-raw;Load the file as a raw binary|" +#if CFG_ZLIB + "-z;Load compessed file|" +#endif + "-loader=*;Specify CFE loader name|" + "-tftp;Load the file using the TFTP protocol|" + "-fatfs;Load the file from a FAT file system|" + "-rawfs;Load the file from an unformatted file system|" +#if (CFG_TCP) && (CFG_HTTPFS) + "-http;Load the file using the HTTP protocol|" +#endif + "-fs=*;Specify CFE file system name|" + "-max=*;Specify the maximum number of bytes to load (raw only)|" + "-addr=*;Specify the load address (hex) (raw only)|" + "-noclose;Don't close network link before executing program"); + + cmd_addcmd("go", + ui_cmd_go, + NULL, + "Start a previously loaded program.", + "go [address]\n\n" + "The 'go' command will start a program previously loaded with \n" + "the 'load' command. You can override the start address by" + "specifying it as a parameter to the 'go' command.", + "-noclose;Don't close network link before executing program"); + + cmd_addcmd("batch", + ui_cmd_batch, + NULL, + "Load a batch file into memory and execute it", + "batch [-options] host:filename|dev:filename\n\n" + "This command loads and executes a batch file from a boot device", +#if CFG_ZLIB + "-z;Load compessed file|" +#endif + "-tftp;Load the file using the TFTP protocol|" + "-fatfs;Load the file from a FAT file system|" + "-rawfs;Load the file from an unformatted file system|" + "-fs=*;Specify CFE file system name"); + + + cmd_addcmd("autoboot", + ui_cmd_autoboot, + NULL, + "Automatic system bootstrap.", + "autoboot [dev]\n\n" + "The 'autoboot' command causes an automatic system bootstrap from\n" + "a predefined list of devices and boot files. This list is \n" + "specific to the board and port of CFE. To try autobooting from\n" + "a specific device, you can specify the CFE device name on the command line.", + "-forever;Loop over devices until boot is successful|" + "-interruptible;Scan console between devices, drop to prompt if key pressed"); + + return 0; +} + + +static int ui_cmd_autoboot(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int res; + char *x; + int flags = 0; + + if (cmd_sw_isset(cmd,"-forever")) flags |= CFE_AUTOFLG_TRYFOREVER; + if (cmd_sw_isset(cmd,"-interruptible")) flags |= CFE_AUTOFLG_POLLCONSOLE; + + x = cmd_getarg(cmd,0); + res = cfe_autoboot(x,flags); + + return res; +} + +static int ui_cmd_go(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *arg; + + arg = cmd_getarg(cmd,0); + if (arg) { + cfe_loadargs.la_entrypt = getaddr(arg); + } + + if (cmd_sw_isset(cmd,"-noclose")) { + cfe_loadargs.la_flags |= LOADFLG_NOCLOSE; + } + + cfe_go(&cfe_loadargs); + + return 0; +} + + + +static int ui_cmd_bootcommon(ui_cmdline_t *cmd,int argc,char *argv[],int flags) +{ + int res; + char *arg; + cfe_loadargs_t *la = &cfe_loadargs; + char copy[200]; + + la->la_flags = flags; + + arg = cmd_getarg(cmd,0); + strncpy(copy,arg,sizeof(copy)); + + if (!arg) { + xprintf("No program name specified\n"); + return -1; + } + + res = ui_process_url(arg,cmd,la); + if (res < 0) return res; + + /* + * Pick up the remaining command line parameters for use as + * arguments to the loaded program. + */ + + la->la_options = cmd_getarg(cmd,1); + + /* + * Note: we might not come back here if we really launch the program. + */ + + xprintf("Loader:%s Filesys:%s Dev:%s File:%s Options:%s\n", + la->la_loader,la->la_filesys,la->la_device,la->la_filename,la->la_options); + + res = cfe_boot(la->la_loader,la); + + /* + * Give the bad news. + */ + + if (res < 0) xprintf("Could not load %s: %s\n",copy,cfe_errortext(res)); + + return res; +} + + +static int ui_cmd_load(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int flags = LOADFLG_NOISY; + + return ui_cmd_bootcommon(cmd,argc,argv,flags); +} + + + + +static int ui_cmd_boot(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int flags = LOADFLG_NOISY | LOADFLG_EXECUTE; + + return ui_cmd_bootcommon(cmd,argc,argv,flags); +} + +static int ui_cmd_batch(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int flags = LOADFLG_NOISY | LOADFLG_EXECUTE | LOADFLG_BATCH; + + return ui_cmd_bootcommon(cmd,argc,argv,flags); +} + +#if CFG_NETWORK +static int ui_cmd_save(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *x; + uint8_t *start,*end; + int len; + char *fname; + int res; + + fname = cmd_getarg(cmd,0); + + if ((x = cmd_getarg(cmd,1))) { + start = (uint8_t *) getaddr(x); + } + else { + return ui_showusage(cmd); + } + + if ((x = cmd_getarg(cmd,2))) { + len = xtoi(x); + } + else { + return ui_showusage(cmd); + } + + end = start+len; + + res = cfe_savedata("tftp","",fname,start,end); + + if (res < 0) { + return ui_showerror(res,"Could not dump data to network"); + } + else { + xprintf("%d bytes written to %s\n",res,fname); + } + + return 0; +} +#endif + + + + diff --git a/cfe/cfe/ui/ui_memcmds.c b/cfe/cfe/ui/ui_memcmds.c new file mode 100644 index 0000000..b48af34 --- /dev/null +++ b/cfe/cfe/ui/ui_memcmds.c @@ -0,0 +1,171 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Memory Map commands File: ui_memcmds.c + * + * Memory Manager user interface + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_arena.h" + +#include "ui_command.h" + +#include "cfe_mem.h" + +#include "cfe.h" + + +const static char * const cfe_arenatypes[] = { + "Reserved", + "DRAM (available)", + "Memory Controller (unused)", + "DRAM (in use by firmware)", + "ROM", + "I/O Registers", + "Not available", + "L2 Cache", + "LDT/PCI", + NULL}; + +extern arena_t cfe_arena; + + + +int ui_init_memcmds(void); + +static int ui_cmd_physmap(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_heapstats(ui_cmdline_t *cmd,int argc,char *argv[]); + + +int ui_init_memcmds(void) +{ + cmd_addcmd("show memory", + ui_cmd_physmap, + NULL, + "Display the system physical memory map.", + "show memory [-a]\n\n" + "This command displays the arena, or system physical memory map\n" + "You can use this command to determine the areas of RAM that will\n" + "be made available to operating systems.\n", + "-a;Display all entries in the map, not just the blocks\n" + "of available memory."); + + cmd_addcmd("show heap", + ui_cmd_heapstats, + NULL, + "Display information about CFE's heap", + "show heap\n\n" + "This is a debugging command that can be used to determine the health\n" + "of CFE's internal memory manager.", + ""); + + return 0; +} + +static int ui_cmd_heapstats(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int res; + memstats_t stats; + + res = KMEMSTATS(&stats); + + xprintf("\n"); + xprintf("Total bytes: %d\n",stats.mem_totalbytes); + xprintf("Free bytes: %d\n",stats.mem_freebytes); + xprintf("Free nodes: %d\n",stats.mem_freenodes); + xprintf("Allocated bytes: %d\n",stats.mem_allocbytes); + xprintf("Allocated nodes: %d\n",stats.mem_allocnodes); + xprintf("Largest free node: %d\n",stats.mem_largest); + xprintf("Heap status: %s\n",(res == 0) ? "CONSISTENT" : "CORRUPT!"); + xprintf("\n"); + + return res; +} + + +#define PHYSMAP_FLG_ALL 1 +#define PHYSMAP_FLG_AVAIL 2 + +static int ui_cmd_physmap(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + arena_node_t *node; + queue_t *qb; + arena_t *arena = &cfe_arena; + int flags = 0; + + if (cmd_sw_isset(cmd,"-a")) { + flags |= PHYSMAP_FLG_ALL; + } + else { + flags = PHYSMAP_FLG_AVAIL; + } + + + xprintf("Range Start Range End Range Size Description\n"); + xprintf("------------ ------------ -------------- --------------------\n"); + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + node = (arena_node_t *) qb; + + if ((flags & PHYSMAP_FLG_ALL) || + ((flags & PHYSMAP_FLG_AVAIL) && (node->an_type == MEMTYPE_DRAM_AVAILABLE))) { + + xprintf("%012llX-%012llX (%012llX) %s\n", + node->an_address, + node->an_address+node->an_length-1, + node->an_length, + cfe_arenatypes[node->an_type]); + } + + } + + return 0; +} + diff --git a/cfe/cfe/ui/ui_misccmds.c b/cfe/cfe/ui/ui_misccmds.c new file mode 100644 index 0000000..156da6a --- /dev/null +++ b/cfe/cfe/ui/ui_misccmds.c @@ -0,0 +1,178 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Miscellaneous commands File: ui_misccmds.c + * + * Some small but useful commands + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "cfe_ioctl.h" +#include "cfe_devfuncs.h" +#include "ui_command.h" +#include "cfe.h" + + +static int ui_cmd_loop(ui_cmdline_t *cmd,int argc,char *argv[]); +#ifdef _FUNCSIM_ +static int ui_cmd_exit(ui_cmdline_t *cmd,int argc,char *argv[]); +#endif +static int ui_cmd_console(ui_cmdline_t *cmd,int argc,char *argv[]); + +extern int cfe_docommands(char *buf); + +int ui_init_misccmds(void); + +int ui_init_misccmds(void) +{ + + cmd_addcmd("loop", + ui_cmd_loop, + NULL, + "Loop a command", + "loop \"command\" [-count=*]\n" + "The 'loop' command causes the specified command or list of commands\n" + "to be repeated 'count' times or forever, or until a character is typed", + "-count=*;Specifies number of iterations|" + "-forever;Loops forever"); + +#ifdef _FUNCSIM_ + cmd_addcmd("exit", + ui_cmd_exit, + NULL, + "exit from the functional simulator", + "exit [n]\n\n" + "This command is useful only when running under the functional\n" + "simulator. It causes the simulator to exit and return to the\n" + "operating system. If specified, 'n' will be placed in $4 as a\n" + "return code.", + ""); +#endif + + cmd_addcmd("set console", + ui_cmd_console, + NULL, + "Change the active console device", + "set console device-name\n\n" + "Changes the console device to the specified device name. The console\n" + "must be a serial-style device. Be careful not to change the console\n" + "to a device that is not connected!", + ""); + + return 0; +} + +static int ui_cmd_loop(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int count = 10; + char *x; + int res; + int forever; + + if (cmd_sw_value(cmd,"-count",&x)) count = atoi(x); + + forever = cmd_sw_isset(cmd,"-forever"); + + x = cmd_getarg(cmd,0); + if (!x) return ui_showusage(cmd); + + res = 0; + while (count || forever) { + if (console_status()) break; + res = ui_docommands(x); + if (res != 0) break; + count--; + } + + return res; +} + + +#ifdef _FUNCSIM_ +static int ui_cmd_exit(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int val = 0; + char *x; + + x = cmd_getarg(cmd,0); + if (x) val = atoi(x); + + __asm __volatile ("move $4,%0 ; li $2,1 ; syscall 0xca" : "=r"(val)); + + return -1; +} +#endif + + +static int ui_cmd_console(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int res; + char *dev; + + dev = cmd_getarg(cmd,0); + if (!dev) return -1; /* XXX usage */ + + res = cfe_getdevinfo(dev); + if (res < 0) { + xprintf("Device '%s' is not valid\n",dev); + return CFE_ERR_DEVNOTFOUND; + } + + if ((res & CFE_DEV_MASK) != CFE_DEV_SERIAL) { + xprintf("Device '%s' is not the appropriate type to be a console\n", + dev); + return CFE_ERR_WRONGDEVTYPE; + } + + cfe_set_console(dev); + + return 0; +} diff --git a/cfe/cfe/ui/ui_netcmds.c b/cfe/cfe/ui/ui_netcmds.c new file mode 100644 index 0000000..891e127 --- /dev/null +++ b/cfe/cfe/ui/ui_netcmds.c @@ -0,0 +1,710 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Network commands File: ui_netcmds.c + * + * Network user interface + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_ioctl.h" + +#include "cfe_error.h" + +#include "env_subr.h" +#include "ui_command.h" +#include "cfe.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_api.h" + +#include "cfe_fileops.h" + +#include "bsp_config.h" + +#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0) +#define isdigit(d) (((d) >= '0') && ((d) <= '9')) + +int ui_init_netcmds(void); + +#if CFG_NETWORK +static int ui_cmd_ifconfig(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_arp(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_ping(ui_cmdline_t *cmd,int argc,char *argv[]); +#if CFG_TCP +extern int ui_init_tcpcmds(void); +#endif +#endif + +typedef struct netparam_s { + const char *str; + int num; +} netparam_t; + +const static netparam_t loopbacktypes[] = { + {"off",ETHER_LOOPBACK_OFF}, + {"internal",ETHER_LOOPBACK_INT}, + {"external",ETHER_LOOPBACK_EXT}, + {0,NULL}}; + +const static netparam_t speedtypes[] = { + {"auto",ETHER_SPEED_AUTO}, + {"10hdx",ETHER_SPEED_10HDX}, + {"10fdx",ETHER_SPEED_10FDX}, + {"100hdx",ETHER_SPEED_100HDX}, + {"100fdx",ETHER_SPEED_100FDX}, + {"1000hdx",ETHER_SPEED_1000HDX}, + {"1000fdx",ETHER_SPEED_1000FDX}, + {0,NULL}}; + + +int ui_init_netcmds(void) +{ +#if CFG_NETWORK + cmd_addcmd("ifconfig", + ui_cmd_ifconfig, + NULL, + "Configure the Ethernet interface", + "ifconfig device [options..]\n\n" + "Activates and configures the specified Ethernet interface and sets its\n" + "IP address, netmask, and other parameters. The -auto switch can be used\n" + "to set this information via DHCP.", + "-auto;Configure interface automatically via DHCP|" + "-off;Deactivate the specified interface|" + "-addr=*;Specifies the IP address of the interface|" + "-mask=*;Specifies the subnet mask for the interface|" + "-gw=*;Specifies the gateway address for the interface|" + "-dns=*;Specifies the name server address for the interface|" + "-domain=*;Specifies the default domain for name service queries|" + "-speed=*;Sets the interface speed (auto,10fdx,10hdx,\n100fdx,\n" + "100hdx,1000fdx,1000hdx)|" + "-loopback=*;Sets the loopback mode (off,internal,external) " + "External\nloopback causes the phy to be placed in loopback mode|" + "-hwaddr=*;Sets the hardware address (overrides environment)"); + + cmd_addcmd("arp", + ui_cmd_arp, + NULL, + "Display or modify the ARP Table", + "arp [-d] [ip-address] [dest-address]\n\n" + "Without any parameters, the arp command will display the contents of the\n" + "arp table. With two parameters, arp can be used to add permanent arp\n" + "entries to the table (permanent arp entries do not time out)", + "-d;Delete the specified ARP entry. If specified, ip-address\n" + "may be * to delete all entries."); + + cmd_addcmd("ping", + ui_cmd_ping, + NULL, + "Ping a remote IP host.", + "ping [-t] remote-host\n\n" + "This command sends an ICMP ECHO message to a remote host and waits for \n" + "a reply. The network interface must be configured and operational for\n" + "this command to work. If the interface is configured for loopback mode\n" + "the packet will be sent through the network interface, so this command\n" + "can be used for a simple network test.", + "-t;Ping forever, or until the ENTER key is struck|" + "-x;Exit immediately on first error (use with -f or -t)|" + "-f;Flood ping (use carefully!) - ping as fast as possible|" + "-s=*;Specify the number of ICMP data bytes|" + "-c=*;Specify number of packets to echo|" + "-A;don't abort even if key is pressed|" + "-E;Require all packets sent to be returned, for successful return status"); + +#if CFG_TCP + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + //ui_init_tcpcmds(); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ +#endif + + +#endif + + return 0; +} + + +#if CFG_NETWORK +static int parsexdigit(char str) +{ + int digit; + + if ((str >= '0') && (str <= '9')) digit = str - '0'; + else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10; + else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10; + else return -1; + + return digit; +} + + +static int parsehwaddr(char *str,uint8_t *hwaddr) +{ + int digit1,digit2; + int idx = 6; + + while (*str && (idx > 0)) { + digit1 = parsexdigit(*str); + if (digit1 < 0) return -1; + str++; + if (!*str) return -1; + + if ((*str == ':') || (*str == '-')) { + digit2 = digit1; + digit1 = 0; + } + else { + digit2 = parsexdigit(*str); + if (digit2 < 0) return -1; + str++; + } + + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + + if (*str == '-') str++; + if (*str == ':') str++; + } + return 0; +} + + + +static int ui_ifdown(void) +{ + char *devname; + + devname = (char *) net_getparam(NET_DEVNAME); + if (devname) { + xprintf("Device %s has been deactivated.\n",devname); + net_uninit(); + net_setnetvars(); + } + + return 0; +} + +static void ui_showifconfig(void) +{ + char *devname; + uint8_t *addr; + + devname = (char *) net_getparam(NET_DEVNAME); + if (devname == NULL) { + xprintf("Network interface has not been configured\n"); + return; + } + + xprintf("Device %s: ",devname); + + addr = net_getparam(NET_HWADDR); + if (addr) xprintf(" hwaddr %a",addr); + + addr = net_getparam(NET_IPADDR); + if (addr) { + if (ip_addriszero(addr)) xprintf(", ipaddr not set"); + else xprintf(", ipaddr %I",addr); + } + + addr = net_getparam(NET_NETMASK); + if (addr) { + if (ip_addriszero(addr)) xprintf(", mask not set"); + else xprintf(", mask %I",addr); + } + + xprintf("\n"); + xprintf(" "); + + addr = net_getparam(NET_GATEWAY); + if (addr) { + if (ip_addriszero(addr)) xprintf("gateway not set"); + else xprintf("gateway %I",addr); + } + + addr = net_getparam(NET_NAMESERVER); + if (addr) { + if (ip_addriszero(addr)) xprintf(", nameserver not set"); + else xprintf(", nameserver %I",addr); + } + + addr = net_getparam(NET_DOMAIN); + if (addr) { + xprintf(", domain %s",addr); + } + + xprintf("\n"); +} + +/* Foxconn add start by Cliff Wang, 03/23/2010 */ +#if 0 +static int ui_ifconfig_auto(ui_cmdline_t *cmd,char *devname) +{ + int err; + dhcpreply_t *reply = NULL; + char *x; + uint8_t hwaddr[6]; + + net_uninit(); + + err = net_init(devname); + if (err < 0) { + xprintf("Could not activate device %s: %s\n", + devname,cfe_errortext(err)); + return err; + } + + if (cmd_sw_value(cmd,"-hwaddr",&x)) { + if (parsehwaddr(x,hwaddr) != 0) { + xprintf("Invalid hardware address: %s\n",x); + net_uninit(); + return CFE_ERR_INV_PARAM; + } + else { + net_setparam(NET_HWADDR,hwaddr); + } + } + + err = dhcp_bootrequest(&reply); + + if (err < 0) { + xprintf("DHCP registration failed on device %s\n",devname); + net_uninit(); + return CFE_ERR_NETDOWN; + } + + net_setparam(NET_IPADDR,reply->dr_ipaddr); + net_setparam(NET_NETMASK,reply->dr_netmask); + net_setparam(NET_GATEWAY,reply->dr_gateway); + net_setparam(NET_NAMESERVER,reply->dr_nameserver); + net_setparam(NET_DOMAIN,reply->dr_domainname); + + dhcp_set_envvars(reply); + + if (reply) dhcp_free_reply(reply); + + ui_showifconfig(); + net_setnetvars(); + return 0; +} +#endif +/* Foxconn add end by Cliff Wang, 03/23/2010 */ + +static int ui_ifconfig_getsw(ui_cmdline_t *cmd,char *swname,char *descr,uint8_t *addr) +{ + char *x; + + x = NULL; + + if (cmd_sw_value(cmd,swname,&x) == 0) return 0; + + if ((x == NULL) || (parseipaddr(x,addr) < 0)) { + xprintf("Invalid %s: %s\n",descr,x ? x : "(none)"); + return -1; + } + + return 1; +} + +static int ui_ifconfig_lookup(char *name,char *val,const netparam_t *list) +{ + const netparam_t *p = list; + + while (p->str) { + if (strcmp(p->str,val) == 0) return p->num; + p++; + } + + xprintf("Invalid parameter for %s: Valid options are: "); + + p = list; + while (p->str) { + xprintf("%s ",p->str); + p++; + } + + xprintf("\n"); + return -1; +} + + +#define FLG_IPADDR 1 +#define FLG_NETMASK 2 +#define FLG_GATEWAY 4 +#define FLG_NAMESERVER 8 +#define FLG_DOMAIN 16 +#define FLG_LOOPBACK 32 +#define FLG_SPEED 64 +#define FLG_HWADDR 128 + +static int ui_cmd_ifconfig(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *devname; + int flags = 0; + uint8_t ipaddr[IP_ADDR_LEN]; + uint8_t netmask[IP_ADDR_LEN]; + uint8_t gateway[IP_ADDR_LEN]; + uint8_t nameserver[IP_ADDR_LEN]; + uint8_t hwaddr[6]; + int speed = ETHER_SPEED_AUTO; + int loopback = ETHER_LOOPBACK_OFF; + char *domain = NULL; + int res; + char *x; + + if (argc < 1) { + ui_showifconfig(); + return 0; + } + + devname = cmd_getarg(cmd,0); + + if (cmd_sw_isset(cmd,"-off")) { + return ui_ifdown(); + } + + /* Foxconn add start by Cliff Wang, 03/23/2010 */ +#if 0 + if (cmd_sw_isset(cmd,"-auto")) { + return ui_ifconfig_auto(cmd,devname); + } +#endif + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + res = ui_ifconfig_getsw(cmd,"-addr","interface IP address",ipaddr); + if (res < 0) return CFE_ERR_INV_PARAM; + if (res > 0) { + flags |= FLG_IPADDR; + } + + res = ui_ifconfig_getsw(cmd,"-mask","netmask",netmask); + if (res < 0) return CFE_ERR_INV_PARAM; + if (res > 0) { + flags |= FLG_NETMASK; + } + + res = ui_ifconfig_getsw(cmd,"-gw","gateway IP address",gateway); + if (res < 0) return CFE_ERR_INV_PARAM; + if (res > 0) { + flags |= FLG_GATEWAY; + } + + res = ui_ifconfig_getsw(cmd,"-dns","name server IP address",nameserver); + if (res < 0) return CFE_ERR_INV_PARAM; + if (res > 0) { + flags |= FLG_NAMESERVER; + } + + if (cmd_sw_value(cmd,"-domain",&domain)) { + if (domain) flags |= FLG_DOMAIN; + } + + if (cmd_sw_value(cmd,"-speed",&x)) { + speed = ui_ifconfig_lookup("-speed",x,speedtypes); + if (speed >= 0) flags |= FLG_SPEED; + else return CFE_ERR_INV_PARAM; + } + + if (cmd_sw_value(cmd,"-loopback",&x)) { + loopback = ui_ifconfig_lookup("-loopback",x,loopbacktypes); + if (loopback >= 0) flags |= FLG_LOOPBACK; + else return CFE_ERR_INV_PARAM; + } + + if (cmd_sw_value(cmd,"-hwaddr",&x)) { + if (parsehwaddr(x,hwaddr) != 0) { + xprintf("Invalid hardware address: %s\n",x); + return CFE_ERR_INV_PARAM; + } + else { + flags |= FLG_HWADDR; + } + } + + /* + * If the network is running and the device name is + * different, uninit the net first. + */ + + x = (char *) net_getparam(NET_DEVNAME); + + if ((x != NULL) && (strcmp(x,devname) != 0)) { + net_uninit(); + } + + /* + * Okay, initialize the network if it is not already on. If it + * is OFF, the "net_devname" parameter will be NULL. + */ + + if (x == NULL) { + res = net_init(devname); /* turn interface on */ + if (res < 0) { + ui_showerror(res,"Could not activate network interface '%s'",devname); + return res; + } + } + + /* + * Set the parameters + */ + + if (flags & FLG_HWADDR) net_setparam(NET_HWADDR,hwaddr); + if (flags & FLG_IPADDR) net_setparam(NET_IPADDR,ipaddr); + if (flags & FLG_NETMASK) net_setparam(NET_NETMASK,netmask); + if (flags & FLG_GATEWAY) net_setparam(NET_GATEWAY,gateway); + if (flags & FLG_NAMESERVER) net_setparam(NET_NAMESERVER,nameserver); + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + if (flags & FLG_DOMAIN) net_setparam(NET_DOMAIN,(uint8_t *) domain); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + if (flags & FLG_SPEED) net_setparam(NET_SPEED,(uint8_t *) &speed); + if (flags & FLG_LOOPBACK) net_setparam(NET_LOOPBACK,(uint8_t *) &loopback); + + ui_showifconfig(); + net_setnetvars(); + + return 0; +} + + +static int ui_cmd_arp(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int idx; + uint8_t ipaddr[IP_ADDR_LEN]; + uint8_t hwaddr[ENET_ADDR_LEN]; + char *x; + int once = 0; + + if (cmd_sw_isset(cmd,"-d")) { + if ((x = cmd_getarg(cmd,0)) == NULL) { + return ui_showusage(cmd); + } + + if (strcmp(x,"*") == 0) { + while (arp_enumerate(0,ipaddr,hwaddr) >= 0) { + arp_delete(ipaddr); + } + } + else { + if (parseipaddr(x,ipaddr) < 0) { + xprintf("Invalid IP address: %s\n",x); + return CFE_ERR_INV_PARAM; + } + arp_delete(ipaddr); + } + return 0; + } + + /* + * Get the IP address. If NULL, display the table. + */ + + x = cmd_getarg(cmd,0); + if (x == NULL) { + idx = 0; + while (arp_enumerate(idx,ipaddr,hwaddr) >= 0) { + if (once == 0) { + xprintf("Hardware Address IP Address\n"); + xprintf("----------------- ---------------\n"); + once = 1; + } + xprintf("%a %I\n",hwaddr,ipaddr); + idx++; + } + if (idx == 0) xprintf("No ARP entries.\n"); + return 0; + } + + if (parseipaddr(x,ipaddr) < 0) { + xprintf("Invalid IP address: %s\n",x); + return CFE_ERR_INV_PARAM; + } + + /* + * Get the hardware address. + */ + + x = cmd_getarg(cmd,1); + if (x == NULL) { + return ui_showusage(cmd); + } + + if (parsehwaddr(x,hwaddr) < 0) { + xprintf("Invalid hardware address: %s\n",x); + return CFE_ERR_INV_PARAM; + } + + arp_add(ipaddr,hwaddr); + + return 0; +} + +#define IP_HDR_LENGTH 20 +#define ICMP_HDR_LENGTH 8 +#define PING_HDR_LENGTH (IP_HDR_LENGTH+ICMP_HDR_LENGTH) +#define MAX_PKT_LENGTH 1500 + +static int ui_cmd_ping(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *host; + uint8_t hostaddr[IP_ADDR_LEN]; + int res; + int seq = 0; + int forever = 0; + int count = 1; + int ttlcount = 1; + int countreturned = 0; + int size = 56; + int flood = 0; + int retval = 0; + int exitonerror = 0; + int needexact = 0; + int noabort = 0; + char *x; + + host = cmd_getarg(cmd,0); + if (!host) return -1; + + if (cmd_sw_isset(cmd,"-t")) { + forever = 1; + } + + /* Per traditional Unix usage, the size argument to ping is + the number of ICMP data bytes. The frame on the wire will also + include the ethernet, IP and ICMP headers (14, 20, and + 8 bytes respectively) and ethernet trailer (CRC, 4 bytes). */ + if (cmd_sw_value(cmd,"-s",&x)) { + size = atoi(x); + if (size < 0) + size = 0; + if (size > MAX_PKT_LENGTH - PING_HDR_LENGTH) + size = MAX_PKT_LENGTH - PING_HDR_LENGTH; + } + + if (cmd_sw_isset(cmd,"-f")) { + flood = 1; + forever = 1; + } + + if (cmd_sw_isset(cmd,"-x")) { + exitonerror = 1; + } + + if (cmd_sw_value(cmd,"-c",&x)) { + count = atoi(x); + ttlcount = count; + forever = 0; + } + + if (cmd_sw_isset(cmd,"-A")) { + noabort = 1; + } + + if (cmd_sw_isset(cmd,"-E")) { + needexact = 1; + } + + if (isdigit(*host)) { + if (parseipaddr(host,hostaddr) < 0) { + xprintf("Invalid IP address: %s\n",host); + return -1; + } + } + else { + res = dns_lookup(host,hostaddr); + if (res < 0) { + return ui_showerror(res,"Could not resolve IP address of host %s",host); + } + } + + if (forever) xprintf("Press ENTER to stop pinging\n"); + + do { + res = icmp_ping(hostaddr,seq,size); + + if (res < 0) { + xprintf("Could not transmit echo request\n"); + retval = CFE_ERR_IOERR; + break; + } + else if (res == 0) { + xprintf("%s (%I) is not responding (seq=%d)\n",host,hostaddr,seq); + retval = CFE_ERR_TIMEOUT; + if (exitonerror) break; + } + else { + countreturned++; + if (!flood || ((seq % 10000) == 0)) { + if (forever || (ttlcount > 1)) { + xprintf("%s (%I) is alive (seq=%d)\n",host,hostaddr,seq); + } + else xprintf("%s (%I) is alive\n",host,hostaddr); + } + } + + if ((forever || (count > 1)) && !flood) { + if (res > 0) cfe_sleep(CFE_HZ); + } + + seq++; + count--; + + } while ((forever || (count > 0)) && (noabort || !console_status())); + + xprintf("%s (%I): %d packets sent, %d received\n",host,hostaddr, + ttlcount-count,countreturned); + return (needexact ? (countreturned != ttlcount) : (countreturned == 0)); +} + +#endif diff --git a/cfe/cfe/ui/ui_pcicmds.c b/cfe/cfe/ui/ui_pcicmds.c new file mode 100644 index 0000000..8875f8e --- /dev/null +++ b/cfe/cfe/ui/ui_pcicmds.c @@ -0,0 +1,282 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * PCI Commands File: ui_pcicmds.c + * + * PCI user interface routines + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "env_subr.h" +#include "ui_command.h" +#include "cfe.h" + +#include "pcivar.h" +#include "pcireg.h" + +#include "bsp_config.h" + +int ui_init_pcicmds(void); + +#if CFG_PCI +static int pci_print_summary(pcitag_t tag) +{ + pcireg_t id, class; + char devinfo[256]; + + class = pci_conf_read(tag, PCI_CLASS_REG); + id = pci_conf_read(tag, PCI_ID_REG); + + pci_devinfo(id, class, 1, devinfo); + pci_tagprintf (tag, "%s\n", devinfo); + + return 0; +} + +static int pci_print_concise(pcitag_t tag) +{ + pci_tagprintf (tag, "\n"); + pci_conf_print(tag); + + return 0; +} + +static int ui_cmd_pci(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *argp; + + if (cmd_sw_isset(cmd,"-init")) { + pci_configure(PCI_FLG_LDT_PREFETCH | PCI_FLG_NORMAL); + return 0; + } + + argp = cmd_getarg(cmd,0); + + if (argp == NULL) { + if (cmd_sw_isset(cmd,"-v")) { + pci_foreachdev(pci_print_concise); + } + else { + pci_foreachdev(pci_print_summary); + } + } + else { + /* parse the triplet */ + int bus, dev, func; + pcitag_t tag; + char *p; + + bus = dev = func = 0; + p = argp; + + while (*p >= '0' && *p <= '9') { + bus = bus*10 + (*p - '0'); + p++; + } + if (*p != '/') + goto fail; + p++; + while (*p >= '0' && *p <= '9') { + dev = dev*10 + (*p - '0'); + p++; + } + if (*p != '/') + goto fail; + p++; + while (*p >= '0' && *p <= '9') { + func = func*10 + (*p - '0'); + p++; + } + if (*p != '\000') + goto fail; + + tag = pci_make_tag(bus,dev,func); + + pci_print_concise(tag); + } + + return 0; + +fail: + printf("invalid PCI triplet %s\n", argp); + return -1; +} + + +static uint64_t parse_hex(const char *num) +{ + uint64_t x = 0; + unsigned int digit; + + if ((*num == '0') && (*(num+1) == 'x')) num += 2; + + while (*num) { + if ((*num >= '0') && (*num <= '9')) { + digit = *num - '0'; + } + else if ((*num >= 'A') && (*num <= 'F')) { + digit = 10 + *num - 'A'; + } + else if ((*num >= 'a') && (*num <= 'f')) { + digit = 10 + *num - 'a'; + } + else { + break; + } + x *= 16; + x += digit; + num++; + } + + return x; +} + +static int ui_cmd_map_pci(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + unsigned long offset, size; + uint64_t paddr; + int l2ca, endian; + int enable; + int result; + + enable = !cmd_sw_isset(cmd, "-off"); + if (enable) { + offset = parse_hex(cmd_getarg(cmd, 0)); + size = parse_hex(cmd_getarg(cmd, 1)); + paddr = parse_hex(cmd_getarg(cmd, 2)); + l2ca = cmd_sw_isset(cmd,"-l2ca"); + endian = cmd_sw_isset(cmd, "-matchbits"); + result = pci_map_window(paddr, offset, size, l2ca, endian); + } + else { + offset = parse_hex(cmd_getarg(cmd, 0)); + size = parse_hex(cmd_getarg(cmd, 1)); + result = pci_unmap_window(offset, size); + } + + return result; +} +#endif + +#ifdef CFG_VGACONSOLE + +extern int vga_biosinit(void); +extern int vga_probe(void); +extern void vgaraw_dump(char *tail); + +static int ui_cmd_vgainit(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int res; + + if (vga_probe() == 0) { + res = vga_biosinit(); + xprintf("vgabios_init returns %d\n",res); + } + else + xprintf("vga_probe found no suitable adapter\n"); + + return 0; +} + +static int ui_cmd_vgadump(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *x; + + x = cmd_getarg(cmd,0); + if (x == NULL) x = ""; + vgaraw_dump(x); + + return 0; +} +#endif /* CFG_VGACONSOLE */ + + +int ui_init_pcicmds(void) +{ + +#if CFG_PCI + cmd_addcmd("show pci", + ui_cmd_pci, + NULL, + "Display information about PCI buses and devices", + "show pci [-v] [bus/dev/func]\n\n" + "Displays information about PCI and LDT buses and devices in the\n" + "system. If you specify a bus/dev/func triplet, only that device\n" + " will be displayed.", + "-v;Display verbose information|" + "-init;Reinitialize and rescan the PCI bus"); + cmd_addcmd("map pci", + ui_cmd_map_pci, + NULL, + "Define a BAR0 window available to PCI devices", + "map pci offset size paddr [-off] [-l2ca] [-matchbits]\n\n" + "Map the region of size bytes starting at paddr to appear\n" + "at offset relative to BAR0\n", + "-off;Remove the region|" + "-l2ca;Make L2 cachable|" + "-matchbits;Use match bits policy"); + +#ifdef CFG_VGACONSOLE + cmd_addcmd("vga init", + ui_cmd_vgainit, + NULL, + "Initialize the VGA adapter.", + "vgainit", + ""); + cmd_addcmd("vga dumpbios", + ui_cmd_vgadump, + NULL, + "Dump the VGA BIOS to the console", + "vga dumpbios", + ""); +#endif /* CFG_VGACONSOLE */ +#endif + return 0; +} diff --git a/cfe/cfe/ui/ui_tcpcmds.c b/cfe/cfe/ui/ui_tcpcmds.c new file mode 100644 index 0000000..e092021 --- /dev/null +++ b/cfe/cfe/ui/ui_tcpcmds.c @@ -0,0 +1,828 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * TCP protocol commands File: ui_tcpcmds.c + * + * This file contains commands that make use of the TCP protocol + * in CFE, assuming it's configured. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +#include "cfe_error.h" +#include "cfe_console.h" + +#include "ui_command.h" +#include "cfe.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" + +#include "bsp_config.h" + +#if CFG_TCP +#include "net_ebuf.h" +#include "net_api.h" +#endif + + +/* ********************************************************************* + * Configuration + ********************************************************************* */ + +/* ********************************************************************* + * prototypes + ********************************************************************* */ + +#if CFG_TCP + +int ui_init_tcpcmds(void); + +static int ui_cmd_rlogin(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_connect(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_listen(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_tcpconstest(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_ttcp(ui_cmdline_t *cmd,int argc,char *argv[]); +#define isdigit(d) (((d) >= '0') && ((d) <= '9')) + + +/* ********************************************************************* + * ui_init_tcpcmds() + * + * Add TCP-specific commands to the command table + * + * Input parameters: + * nothing + * + * Return value: + * 0 + ********************************************************************* */ + + +int ui_init_tcpcmds(void) +{ + + cmd_addcmd("rlogin", + ui_cmd_rlogin, + NULL, + "mini rlogin client.", + "rlogin hostname [username]\n\n" + "Connects to a remote system using the RLOGIN protocol. The remote" + "system must have appropriate permissions in place (usually via the" + "file '.rhosts') for CFE to connect. To terminate the session, type" + "a tilde (~) character followed by a period (.)", + ""); + + cmd_addcmd("tcp connect", + ui_cmd_connect, + NULL, + "TCP connection test.", + "tcp connect hostname [portnum]", + "-q;sink output, don't display on terminal|" + "-d;Send junk data to discard|" + "-nodelay;set nodelay option on socket|" + "-srcport=*;Specify the source port"); + + cmd_addcmd("tcp listen", + ui_cmd_listen, + NULL, + "port listener.", + "tcp listen portnum", + "-q;sink output, don't display on terminal|" + "-d;Send junk data to discard|" + "-nodelay;set nodelay option on socket"); + + + cmd_addcmd("tcp constest", + ui_cmd_tcpconstest, + NULL, + "tcp console test.", + "tcp constest device", + ""); + + cmd_addcmd("ttcp", + ui_cmd_ttcp, + NULL, + "TCP test command.", + "ttcp -t [-options] host\n" + "ttcp -r [-options]\n\n", + "-t;Source a pattern to the network|" + "-r;Sink (discard) data from the network|" + "-D;Don't buffer TCP writes (TCP_NODELAY)|" + "-n=*;Number of buffers to send (-t only) (default 2048)|" + "-l=*;Size of buffer to send/receive (default 2048)|" + "-p=*;Port number to use (default 5001)"); + + return 0; +} + + + + + +static unsigned long rand(void) +{ + static unsigned long seed = 1; + long x, hi, lo, t; + + x = seed; + hi = x / 127773; + lo = x % 127773; + t = 16807 * lo - 2836 * hi; + if (t <= 0) t += 0x7fffffff; + seed = t; + return t; +} + + +static int ui_cmd_rlogin(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int s; + uint8_t hostaddr[IP_ADDR_LEN]; + char *host; + int res; + int connflag; + int rxdata; + int sport; + uint8_t data[100]; + int tilde; + char *username; + uint8_t *p; + + /* + * Process args + */ + + host = cmd_getarg(cmd,0); + if (!host) return ui_showusage(cmd); + + username = cmd_getarg(cmd,1); + if (!username) username = ""; + + /* + * Look up remote host + */ + + if (isdigit(*host)) { + if (parseipaddr(host,hostaddr) < 0) { + xprintf("Invalid IP address: %s\n",host); + return -1; + } + } + else { + res = dns_lookup(host,hostaddr); + if (res < 0) { + return ui_showerror(res,"Could not resolve IP address of host %s",host); + } + } + + /* + * Create TCP socket and bind to a port number less than 1023 + * See RFC1282 for more info about this + */ + + s = tcp_socket(); + + if (s < 0) { + return ui_showerror(s,"Could not create TCP socket"); + } + + res = 0; + tilde = 0; + for (sport = 1023; sport > 513; sport--) { + res = tcp_bind(s,sport); + if (res == 0) break; + } + + if (sport == 513) { + ui_showerror(res,"No ports available for RLOGIN"); + return res; + } + + /* + * Establish a connection. Our sockets default to nonblocking + * so we want to switch to blocking temporarily to + * let the tcp_connect routine do this by itself. + */ + + tcp_setflags(s,0); + res = tcp_connect(s,hostaddr,513); + if (res < 0) { + ui_showerror(res,"Could not connect to host %I",hostaddr); + tcp_close(s); + return res; + } + + + /* + * Construct the initial RLOGIN sequence to include + * our user name and terminal type + */ + + p = data; + *p++ = '\0'; + p += sprintf(p,"%s",username) + 1; + p += sprintf(p,"%s",username) + 1; + p += sprintf(p,"vt100/38400") + 1; + + tcp_send(s,data,p-&data[0]); + + res = tcp_recv(s,data,1); /* receive result code */ + if (res <= 0) { + goto remdisc; + } + + /* + * Switch back to nonblocking I/O for the loop + */ + + tcp_setflags(s,TCPFLG_NBIO); + + /* + * Begin processing loop + */ + + connflag = TRUE; + for (;;) { + + /* + * Test connection status + */ + + tcp_status(s,&connflag,&rxdata,NULL); + if (connflag != TCPSTATUS_CONNECTED) { + goto remdisc; + } + + /* + * Process received data + */ + + if (rxdata != 0) { + res = tcp_recv(s,data,sizeof(data)); + if (res > 0) { + console_write(data,res); + } + if (res < 0) { + ui_showerror(res,"TCP read error"); + break; + } + } + + /* + * Process transmitted data + */ + + if (console_status()) { + console_read(data,1); + if (tilde == 1) { + if (data[0] == '.') break; + tcp_send(s,data,1); + } + else { + if (data[0] == '~') tilde = 1; + else tcp_send(s,data,1); + } + } + + /* + * Give the background a chance + */ + + POLL(); + } + + printf("Disconnecting..."); + tcp_close(s); + printf("done.\n"); + return 0; + +remdisc: + printf("Remote host is no longer connected.\n"); + tcp_close(s); + return 0; +} + + + +static int ui_cmd_connect(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int s; + uint8_t hostaddr[IP_ADDR_LEN]; + char *host; + char *port; + int res; + int connflag; + int rxdata; + uint8_t data[100]; + int quiet; + int discard; + int total = 0; + int total2 = 0; + char b = 0; + cfe_timer_t t; + char *bigbuf; + int nodelay; + char *sport = NULL; + + bigbuf = KMALLOC(4096,0); + for (res = 0; res < 4096; res++) bigbuf[res] = 'A'+(res%26); + + quiet = cmd_sw_isset(cmd,"-q"); + discard = cmd_sw_isset(cmd,"-d"); + nodelay = cmd_sw_isset(cmd,"-nodelay"); + + host = cmd_getarg(cmd,0); + if (!host) return -1; + + port = cmd_getarg(cmd,1); + if (!port) port = "23"; + + if (strcmp(port,"discard") == 0) port = "9"; + else if (strcmp(port,"chargen") == 0) port = "19"; + else if (strcmp(port,"echo") == 0) port = "7"; + + if (isdigit(*host)) { + if (parseipaddr(host,hostaddr) < 0) { + xprintf("Invalid IP address: %s\n",host); + return -1; + } + } + else { + res = dns_lookup(host,hostaddr); + if (res < 0) { + return ui_showerror(res,"Could not resolve IP address of host %s",host); + } + } + + + s = tcp_socket(); + + if (s < 0) { + return ui_showerror(s,"Could not create TCP socket"); + } + + if (cmd_sw_value(cmd,"-srcport",&sport)) { + res = tcp_bind(s,atoi(sport)); + if (res < 0) { + ui_showerror(res,"Could not bind to port %s",sport); + tcp_close(s); + return res; + } + } + + res = tcp_connect(s,hostaddr,atoi(port)); + if (res < 0) { + ui_showerror(res,"Could not connect to host %I",hostaddr); + tcp_close(s); + return res; + } + + TIMER_SET(t,CFE_HZ*30); + connflag = 0; + while (!TIMER_EXPIRED(t)) { + POLL(); + tcp_status(s,&connflag,NULL,NULL); + if (connflag == TCPSTATUS_CONNECTING) continue; + break; + } + + if (connflag != TCPSTATUS_CONNECTED) { + printf("Could not connect to remote host\n"); + tcp_close(s); + return -1; + } + else { + printf("Connected to remote host.\n"); + } + + + if (nodelay) tcp_setflags(s,TCPFLG_NODELAY); + + connflag = TRUE; + for (;;) { + tcp_status(s,&connflag,&rxdata,NULL); + if (connflag != TCPSTATUS_CONNECTED) { + printf("Remote host is no longer connected.\n"); + break; + } + if (rxdata != 0) { + res = tcp_recv(s,data,sizeof(data)); + if (res > 0) { + if (quiet) { + total += res; + if (total > 1000000) { + total -= 1000000; + printf("."); + } + } + else { + console_write(data,res); + } + } + if (res < 0) { + ui_showerror(res,"TCP read error"); + } + } + if (console_status()) { + console_read(data,1); + if (data[0] == 1) break; + else if (data[0] == 3) break; + else if (data[0] == 4) { + for (res = 0; res < 100; res++) data[res] = 'A'+(res%26); + tcp_send(s,data,100); + } + else if (data[0] == 5) tcp_send(s,bigbuf,2048); + else if (data[0] == 2) tcp_debug(s,0); + else tcp_send(s,data,1); + } + if (discard) { + res = rand() % sizeof(data); + memset(data,b,res); + b++; + res = tcp_send(s,data,res); + if (res > 0) { + total2 += res; + if (total2 > 1000000) { + total2 -= 1000000; + printf("+"); + } + } + + } + + POLL(); + } + + printf("Disconnecting..."); + tcp_close(s); + printf("done.\n"); + + KFREE(bigbuf); + + return 0; +} + + +static int ui_cmd_listen(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int s; + char *port; + int res; + int connflag; + int rxdata; + uint8_t data[100]; + int quiet; + int discard; + int total = 0; + int total2 = 0; + char b = 0; + char *bigbuf; + uint16_t p; + uint16_t remport; + uint8_t remaddr[IP_ADDR_LEN]; + int nodelay; + + bigbuf = KMALLOC(4096,0); + for (res = 0; res < 4096; res++) bigbuf[res] = 'A'+(res%26); + + quiet = cmd_sw_isset(cmd,"-q"); + discard = cmd_sw_isset(cmd,"-d"); + nodelay = cmd_sw_isset(cmd,"-nodelay"); + + port = cmd_getarg(cmd,0); + if (!port) port = "1234"; + p = atoi(port); + + s = tcp_socket(); + + if (s < 0) { + return ui_showerror(s,"Could not create TCP socket"); + } + + res = tcp_listen(s,p); + if (res < 0) { + ui_showerror(res,"Could not set socket to listen"); + tcp_close(s); + return res; + } + + printf("Listening..."); + connflag = FALSE; + for (;;) { + if (console_status()) break; + tcp_status(s,&connflag,NULL,NULL); + if (connflag == TCPSTATUS_CONNECTED) break; + POLL(); + } + + if (connflag != TCPSTATUS_CONNECTED) { + printf("No connection received from remote host\n"); + tcp_close(s); + return -1; + } + + tcp_peeraddr(s,remaddr,&remport); + printf("Connection from port %u on %I\n",remport,remaddr); + + if (nodelay) tcp_setflags(s,TCPFLG_NODELAY); + + connflag = TRUE; + for (;;) { + tcp_status(s,&connflag,&rxdata,NULL); + if (connflag != TCPSTATUS_CONNECTED) { + printf("Remote host is no longer connected.\n"); + break; + } + if (rxdata != 0) { + res = tcp_recv(s,data,sizeof(data)); + if (res > 0) { + if (quiet) { + total += res; + if (total > 1000000) { + total -= 1000000; + printf("."); + } + } + else { + console_write(data,res); + } + } + if (res < 0) { + ui_showerror(res,"TCP read error"); + } + } + if (console_status()) { + console_read(data,1); + if (data[0] == 1) break; + if (data[0] == 3) break; + if (data[0] == 4) { + for (res = 0; res < 100; res++) data[res] = 'A'+(res%26); + tcp_send(s,data,100); + } + if (data[0] == 5) tcp_send(s,bigbuf,2048); + if (data[0] == 2) tcp_debug(s,0); + else tcp_send(s,data,1); + } + if (discard) { + res = rand() % sizeof(data); + memset(data,b,res); + b++; + res = tcp_send(s,data,res); + if (res > 0) { + total2 += res; + if (total2 > 1000000) { + total2 -= 1000000; + printf("+"); + } + } + + } + + POLL(); + } + + + printf("Disconnecting..."); + tcp_close(s); + printf("done.\n"); + + KFREE(bigbuf); + + return 0; +} + + +static int ui_cmd_tcpconstest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *x; + int fh; + int res; + uint8_t data[100]; + + x = cmd_getarg(cmd,0); + if (!x) return ui_showusage(cmd); + + fh = cfe_open(x); + if (fh < 0) return ui_showerror(fh,"Could not open device %s",x); + + for (;;) { + if (console_status()) break; + res = cfe_read(fh,data,sizeof(data)); + if (res < 0) { + ui_showerror(res,"could not read data"); + break; + } + console_write(data,res); + } + + cfe_close(fh); + + return 0; +} + +static int ui_cmd_ttcp(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int s; + uint8_t hostaddr[IP_ADDR_LEN]; + char *host; + int res; + int totalbytes = 0; + int totalbufs = 0; + cfe_timer_t start_time; + cfe_timer_t stop_time; + cfe_timer_t t; + int connflag; + char *bigbuf; + int nodelay; + int numbuf; + int buflen; + int txmode,rxmode; + uint16_t port; + + char *x; + + if (cmd_sw_value(cmd,"-n",&x)) numbuf = atoi(x); + else numbuf = 2048; + + if (cmd_sw_value(cmd,"-l",&x)) buflen = atoi(x); + else buflen = 2048; + + if (cmd_sw_value(cmd,"-p",&x)) port = atoi(x); + else port = 5001; + + if ((numbuf == 0) || (buflen == 0)) return ui_showusage(cmd); + + + bigbuf = KMALLOC(buflen,0); + for (res = 0; res < buflen; res++) bigbuf[res] = 'A'+(res%26); + + txmode = cmd_sw_isset(cmd,"-t"); + rxmode = cmd_sw_isset(cmd,"-r"); + + if (!(txmode ^ rxmode)) { + return ui_showerror(-1,"You must specify one of -t or -r"); + } + + nodelay = cmd_sw_isset(cmd,"-D"); + + if (txmode) { + host = cmd_getarg(cmd,0); + if (!host) return ui_showusage(cmd); + + if (isdigit(*host)) { + if (parseipaddr(host,hostaddr) < 0) { + return ui_showerror(-1,"Invalid IP address: %s\n",host); + } + } + else { + res = dns_lookup(host,hostaddr); + if (res < 0) { + return ui_showerror(res,"Could not resolve IP address of host %s",host); + } + } + } + + + s = tcp_socket(); + + if (s < 0) { + return ui_showerror(s,"Could not create TCP socket"); + } + + + if (txmode) { + res = tcp_connect(s,hostaddr,port); + if (res < 0) { + ui_showerror(res,"Could not connect to host %I",hostaddr); + tcp_close(s); + return res; + } + + TIMER_SET(t,CFE_HZ*30); + connflag = 0; + while (!TIMER_EXPIRED(t)) { + POLL(); + tcp_status(s,&connflag,NULL,NULL); + if (connflag == TCPSTATUS_CONNECTING) continue; + break; + } + + if (connflag != TCPSTATUS_CONNECTED) { + printf("Could not connect to remote host\n"); + tcp_close(s); + return -1; + } + else { + printf("Connected to remote host.\n"); + } + } + + if (rxmode) { + printf("Waiting for connection on port %d: ",port); + tcp_listen(s,port); + for (;;) { + if (console_status()) break; + tcp_status(s,&connflag,NULL,NULL); + if (connflag == TCPSTATUS_CONNECTED) break; + POLL(); + } + if (connflag != TCPSTATUS_CONNECTED) { + printf("No connection received from remote host\n"); + tcp_close(s); + return -1; + } + printf("done.\n"); + } + + + if (nodelay) tcp_setflags(s,TCPFLG_NODELAY); /* also sets blocking */ + else tcp_setflags(s,0); + + start_time = cfe_ticks; + + if (rxmode) { + while (1) { + POLL(); + res = tcp_recv(s,bigbuf,buflen); + if (res != buflen) break; + totalbytes += res; + totalbufs++; + } + } + else { + while (numbuf > 0) { + POLL(); + res = tcp_send(s,bigbuf,buflen); + if (res != buflen) break; + numbuf--; + totalbytes += res; + totalbufs++; + } + } + + stop_time = cfe_ticks; + + tcp_close(s); + + if ((res < 0) && !rxmode) { + ui_showerror(res,"Network I/O error"); + } + else { + printf("%d bytes transferred via %d calls in %lld ticks\n", + totalbytes,totalbufs,stop_time-start_time); + } + + + KFREE(bigbuf); + + return 0; + +} + +#endif /* CFG_TCP */ diff --git a/cfe/cfe/ui/ui_test_disk.c b/cfe/cfe/ui/ui_test_disk.c new file mode 100644 index 0000000..9e3e5f9 --- /dev/null +++ b/cfe/cfe/ui/ui_test_disk.c @@ -0,0 +1,439 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Commands to test block devices File: ui_test_disk.c + * + * Commands to manipulate block devices live here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "cfe_ioctl.h" +#include "cfe_devfuncs.h" +#include "ui_command.h" +#include "cfe.h" + +#include "cfe_fileops.h" +#include "cfe_bootblock.h" +#include "cfe_boot.h" + +static int ui_cmd_disktest(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_fstest(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_copydisk(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_bootblock(ui_cmdline_t *cmd,int argc,char *argv[]); + +int ui_init_disktestcmds(void); + +int ui_init_disktestcmds(void) +{ + + cmd_addcmd("test disk", + ui_cmd_disktest, + NULL, + "Do a disk test, read/write sectors on the disk", + "test disk device-name [-random | sector# | {-w sector offset byte}]", + "-random;|" + "-w;Write a byte at offset in sector.**DANGER!! BE CAREFUL WHICH DEVICE YOU WRITE TO.**"); + + cmd_addcmd("test fatfs", + ui_cmd_fstest, + NULL, + "Do a FAT file system test", + "test fatfs device-name", + ""); + + cmd_addcmd("copydisk", + ui_cmd_copydisk, + NULL, + "Copy a remote disk image to a local disk device via TFTP", + "copydisk host:filename device-name [offset]", + ""); + + cmd_addcmd("show boot", + ui_cmd_bootblock, + NULL, + "Display boot block from device,", + "show boot device-name\n\n" + "This command displays the boot block on the specified device. The\n" + "device-name parameter identifies a block device (disk, tape, CD-ROM)\n" + "to be scanned for boot blocks. The first boot block found will be\n" + "displayed.", + ""); + return 0; +} + + +static unsigned long rand(void) +{ + static unsigned long seed = 1; + long x, hi, lo, t; + + x = seed; + hi = x / 127773; + lo = x % 127773; + t = 16807 * lo - 2836 * hi; + if (t <= 0) t += 0x7fffffff; + seed = t; + return t; +} + + +static int ui_cmd_bootblock(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int fh; + char *tok; + struct boot_block bootblock; + int res; + int idx; + int sec; + uint32_t checksum; + uint32_t checksumd; + uint32_t calcsum; + uint32_t secsize; + uint64_t secoffset; + uint8_t *code; + + tok = cmd_getarg(cmd,0); + if (!tok) return -1; + + fh = cfe_open(tok); + if (fh < 0) { + xprintf("Could not open device; %d\n",fh); + return -1; + } + for (sec = 0; sec < BOOT_BLOCK_MAXLOC; sec++) { + res = cfe_readblk(fh,sec * BOOT_BLOCK_BLOCKSIZE, + (unsigned char *) &bootblock,sizeof(bootblock)); + + if (bootblock.bb_magic != BOOT_MAGIC_NUMBER) { + continue; + } + xprintf("Found boot block in sector %d\n", sec); + if (res != sizeof(bootblock)) { + xprintf("Could not read boot block\n"); + cfe_close(fh); + return -1; + } + + xprintf("Boot block data:\n"); + for (idx = 59; idx < 64; idx++) { + xprintf(" %d: %016llX\n",idx,bootblock.bb_data[idx]); + } + xprintf("\n"); + + xprintf("Boot block version is %d\n", + (uint32_t) ((bootblock.bb_hdrinfo & BOOT_HDR_VER_MASK) >> BOOT_HDR_VER_SHIFT)); + xprintf("Boot block flags are %02X\n", + (uint32_t) ((bootblock.bb_hdrinfo & BOOT_HDR_FLAGS_MASK) >> 56)); + checksum = ((uint32_t) (bootblock.bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK)); + checksumd = ((uint32_t) ((bootblock.bb_secsize & BOOT_DATA_CHECKSUM_MASK) >> BOOT_DATA_CHECKSUM_SHIFT)); + bootblock.bb_hdrinfo &= ~BOOT_HDR_CHECKSUM_MASK; + secsize = ((uint32_t) (bootblock.bb_secsize & BOOT_SECSIZE_MASK)); + secoffset = bootblock.bb_secstart; + + xprintf("Boot code is %d bytes at %016llX\n",secsize,secoffset); + + CHECKSUM_BOOT_DATA(&(bootblock.bb_magic),BOOT_BLOCK_SIZE,&calcsum); + + if (checksum != calcsum) { + xprintf("Header checksum does not match Blk=%08X Calc=%08X\n", + checksum,calcsum); + } + else { + xprintf("Header checksum is ok\n"); + } + + code = KMALLOC(secsize,0); + if (code) { + res = cfe_readblk(fh,secoffset,code,secsize); + if (res != secsize) { + xprintf("Could not read boot code\n"); + cfe_close(fh); + KFREE(code); + return -1; + } + CHECKSUM_BOOT_DATA(code,secsize,&calcsum); + if (calcsum == checksumd) xprintf("Boot code checksum is ok\n"); + else xprintf("Boot code checksum is incorrect (Calc=%08X, Blk=%08X)\n", + calcsum,checksumd); + KFREE(code); + } + break; + } + if (sec == BOOT_BLOCK_MAXLOC) { + xprintf("No valid boot blocks found in the first %d sectors\n", + BOOT_BLOCK_MAXLOC); + } + cfe_close(fh); + + return 0; +} + + + + + +extern int fatfs_fileop_dir(void *fsctx); + +static int ui_cmd_fstest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *tok; + char *fname; + fileio_ctx_t *fsctx; + void *filectx; + uint8_t buffer[1000]; + int res; + int total; + + tok = cmd_getarg(cmd,0); + if (!tok) return -1; + + fname = cmd_getarg(cmd,1); + + res = fs_init("fat",&fsctx,tok); + if (res < 0) { + xprintf("Could not init file system: %s\n",cfe_errortext(res)); + return res; + } + + if (!fname) { + fatfs_fileop_dir(fsctx->fsctx); + } + else { + res = fs_open(fsctx,&filectx,fname,FILE_MODE_READ); + if (res < 0) { + xprintf("Could not open %s: %s\n",fname,cfe_errortext(res)); + } + else { + + total = 0; + for (;;) { + res = fs_read(fsctx,filectx,buffer,sizeof(buffer)); + if (res < 0) break; + total += res; + if (res != sizeof(buffer)) break; + xprintf("."); + } + if (res < 0) xprintf("read error %s\n",cfe_errortext(res)); + else xprintf("Total bytes read: %d\n",total); + fs_close(fsctx,filectx); + } + } + + fs_uninit(fsctx); + return 0; +} + +static int ui_cmd_copydisk(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *fname; + fileio_ctx_t *fsctx; + void *filectx; + char *devname; + uint8_t buffer[1024]; + int fh; + int res; + int total; + int count; + int offset; + char *toffset; + + fname = cmd_getarg(cmd,0); + if (!fname) return ui_showusage(cmd); + + devname = cmd_getarg(cmd,1); + if (!devname) return ui_showusage(cmd); + + toffset = cmd_getarg(cmd,2); + if (!toffset) offset = 0; else offset = atoi(toffset); + + if ((cfe_getdevinfo(devname) & CFE_DEV_MASK) != CFE_DEV_DISK) { + xprintf("Device %s is not a disk.\n",devname); + return CFE_ERR_INV_PARAM; + } + + fh = cfe_open(devname); + if (fh < 0) { + return ui_showerror(fh,"Could not open device %s",devname); + } + + res = fs_init("tftp",&fsctx,""); + if (res < 0) { + return ui_showerror(res,"Could not init file system"); + } + + res = fs_open(fsctx,&filectx,fname,FILE_MODE_READ); + if (res < 0) { + return ui_showerror(res,"Could not open %s",fname); + } + else { + total = 0; + count = 0; + for (;;) { + res = fs_read(fsctx,filectx,buffer,sizeof(buffer)); + if (res < 0) break; + if (res > 0) cfe_writeblk(fh,total+offset*512,buffer,res); + total += res; + if (res != sizeof(buffer)) break; + count++; + if (count == 256) { + xprintf("."); + count = 0; + } + } + if (res < 0) xprintf("read error %s\n",cfe_errortext(res)); + else xprintf("Total bytes read: %d\n",total); + fs_close(fsctx,filectx); + } + + fs_uninit(fsctx); + cfe_close(fh); + return 0; +} + +static int ui_cmd_disktest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int fh; + char *tok; + char *tok2; + char *tok3; + char *tok4; + cfe_offset_t offset; + uint64_t sectors; + int secsize; + long secnum = 0; + unsigned char buffer[2048]; + int res; + int idx,idx2; + int count = 0; + uint8_t byte; + int secoffset = 0; + + tok = cmd_getarg(cmd,0); + if (!tok) return -1; + + tok2 = cmd_getarg(cmd,1); + tok3 = cmd_getarg(cmd,2); + tok4 = cmd_getarg(cmd,3); + + fh = cfe_open(tok); + if (fh <= 0) { + xprintf("Could not open device: %s\n",cfe_errortext(fh)); + return fh; + } + + xprintf("device opened ok\n"); + + sectors = 0; secsize = 0; + cfe_ioctl(fh,IOCTL_BLOCK_GETTOTALBLOCKS,(uint8_t *) §ors,sizeof(sectors),&res,0); + cfe_ioctl(fh,IOCTL_BLOCK_GETBLOCKSIZE,(uint8_t *) &secsize,sizeof(secsize),&res,0); + printf("Total sectors: %lld Sector size: %d\n",sectors,secsize); + if (secsize == 0) secsize = 512; + if (sectors == 0) sectors = 100000; + + if (tok2) { + secnum = atoi(tok2); + offset = (cfe_offset_t) secnum * (cfe_offset_t) secsize; + if (cmd_sw_isset(cmd,"-w")) { + secoffset = atoi(tok3); + byte = (uint8_t) xtoq(tok4); + res = cfe_writeblk(fh,offset+secoffset,&byte,1); + if (res != 1) { + xprintf("Write failed\n"); + return -1; + } + } + res = cfe_readblk(fh,offset,buffer,secsize); + if (res != secsize) { + xprintf("disk error: %d sector %d\n",res,secnum); + } + else { + for (idx = 0; idx < secsize; idx+=16) { + xprintf("%04X: ",idx); + for (idx2 = 0; idx2 < 16; idx2++) { + xprintf("%02X ",buffer[idx+idx2]); + } + for (idx2 = 0; idx2 < 16; idx2++) { + if ((buffer[idx+idx2] < 32) || + (buffer[idx+idx2] > 127)) { + xprintf("."); + } + else { + xprintf("%c",buffer[idx+idx2]); + } + } + xprintf("\n"); + } + } + } + else { + if (cmd_sw_isset(cmd,"-random")) { + while (!console_status()) { + secnum++; + secnum = rand() % sectors; + offset = (cfe_offset_t) secnum * (cfe_offset_t) secsize; + res = cfe_readblk(fh,offset,buffer,secsize); + if (res != secsize) { + xprintf("disk error: %d sector %d\n",res,secnum); + break; + } + count++; + if ((count % 1000) == 0) xprintf("%d ",count); + } + } + } + + cfe_close(fh); + + return 0; +} + + + diff --git a/cfe/cfe/ui/ui_test_ether.c b/cfe/cfe/ui/ui_test_ether.c new file mode 100644 index 0000000..9a0b328 --- /dev/null +++ b/cfe/cfe/ui/ui_test_ether.c @@ -0,0 +1,202 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Ethernet test commands File: ui_test_ether.c + * + * User interface commands to test Ethernet devices + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "cfe_ioctl.h" +#include "cfe_devfuncs.h" +#include "ui_command.h" +#include "cfe.h" + +typedef struct netparam_s { + const char *str; + int num; +} netparam_t; + +const static netparam_t speedtypes[] = { + {"auto",ETHER_SPEED_AUTO}, + {"10hdx",ETHER_SPEED_10HDX}, + {"10fdx",ETHER_SPEED_10FDX}, + {"100hdx",ETHER_SPEED_100HDX}, + {"100fdx",ETHER_SPEED_100FDX}, + {"1000hdx",ETHER_SPEED_1000HDX}, + {"1000fdx",ETHER_SPEED_1000FDX}, + {0,NULL}}; + + +int ui_init_ethertestcmds(void); + +static int ui_cmd_ethertest(ui_cmdline_t *cmd,int argc,char *argv[]); + +int ui_init_ethertestcmds(void) +{ + cmd_addcmd("test ether", + ui_cmd_ethertest, + NULL, + "Do an ethernet test, reading packets from the net", + "test ether device-name", + "-speed=*;Specify speed|" + "-q;Be quiet|" + "-send=*;Transmit packets" + ); + + return 0; +} + + +static int ui_ifconfig_lookup(char *name,char *val,const netparam_t *list) +{ + const netparam_t *p = list; + + while (p->str) { + if (strcmp(p->str,val) == 0) return p->num; + p++; + } + + xprintf("Invalid parameter for %s: Valid options are: "); + + p = list; + while (p->str) { + xprintf("%s ",p->str); + p++; + } + + xprintf("\n"); + return -1; +} + +static int ui_cmd_ethertest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *tok; + int fh; + uint8_t packet[2048]; + int res; + int idx; + int speed = ETHER_SPEED_AUTO; + char *x; + int count = 0; + int quiet; + + tok = cmd_getarg(cmd,0); + if (!tok) return -1; + + if (cmd_sw_value(cmd,"-speed",&x)) { + speed = ui_ifconfig_lookup("-speed",x,speedtypes); + if (speed < 0) return CFE_ERR_INV_PARAM; + } + + quiet = cmd_sw_isset(cmd,"-q"); + + + fh = cfe_open(tok); + if (fh < 0) { + xprintf("Could not open device: %s\n",cfe_errortext(fh)); + return fh; + } + + if (speed != ETHER_SPEED_AUTO) { + xprintf("Setting speed to %d...\n",speed); + cfe_ioctl(fh,IOCTL_ETHER_SETSPEED,(uint8_t *) &speed,sizeof(speed),&idx,0); + } + + + if (cmd_sw_value(cmd,"-send",&x)) { + count = atoi(x); + memset(packet,0xEE,sizeof(packet)); + memcpy(packet,"\xFF\xFF\xFF\xFF\xFF\xFF\x40\x00\x00\x10\x00\x00\x12\x34",16); + res = 0; + for (idx = 0; idx < count; idx++) { + res = cfe_write(fh,packet,128); + if (res < 0) break; + } + if (res) { + ui_showerror(res,"Could not transmit packet"); + } + cfe_close(fh); + return 0; + } + + xprintf("Receiving... press enter to stop\n"); + while (!console_status()) { + res = cfe_read(fh,packet,sizeof(packet)); + if (res == 0) continue; + if (res < 0) { + xprintf("Read error: %s\n",cfe_errortext(res)); + break; + } + + if (!quiet) { + xprintf("%4d ",res); + if (res > 32) res = 32; + + for (idx = 0; idx < res; idx++) { + xprintf("%02X",packet[idx]); + if ((idx == 5) || (idx == 11) || (idx == 13)) xprintf(" "); + } + + xprintf("\n"); + } + + count++; + if (quiet && !(count % 1000)) printf("."); + } + + printf("Total packets received: %d\n",count); + + cfe_close(fh); + + return 0; +} + diff --git a/cfe/cfe/ui/ui_test_flash.c b/cfe/cfe/ui/ui_test_flash.c new file mode 100644 index 0000000..841d3fa --- /dev/null +++ b/cfe/cfe/ui/ui_test_flash.c @@ -0,0 +1,260 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Flash Test commands File: ui_test_flash.c + * + * Some commands to test the flash device interface. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_ioctl.h" + +#include "cfe_error.h" + +#include "ui_command.h" + +int ui_init_flashtestcmds(void); + +static int ui_cmd_flashtest(ui_cmdline_t *cmd,int argc,char *argv[]); +//static int ui_cmd_readnvram(ui_cmdline_t *cmd,int argc,char *argv[]); +//static int ui_cmd_erasenvram(ui_cmdline_t *cmd,int argc,char *argv[]); + +int ui_init_flashtestcmds(void) +{ + cmd_addcmd("show flash", + ui_cmd_flashtest, + NULL, + "Display information about a flash device.", + "show flash [-sectors]", + "-sectors;Display sector information"); + +#if 0 + cmd_addcmd("nvram read", + ui_cmd_readnvram, + NULL, + "read the NVRAM", + "test nvram devname offset", + ""); + + cmd_addcmd("nvram erase", + ui_cmd_erasenvram, + NULL, + "erase the NVRAM", + "erasenvram devname", + "-pattern"); +#endif + + + return 0; +} + + +static char *flashtypes[] = { + "Unknown","SRAM","ROM","Flash" +}; + + +static int ui_cmd_flashtest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + flash_info_t info; + int fd; + int retlen; + int res = 0; + int idx; + flash_sector_t sector; + nvram_info_t nvraminfo; + char *devname; + int showsectors; + + devname = cmd_getarg(cmd,0); + if (!devname) return ui_showusage(cmd); + + showsectors = cmd_sw_isset(cmd,"-sectors"); + + fd = cfe_open(devname); + if (fd < 0) { + ui_showerror(fd,"Could not open flash device %s",devname); + return fd; + } + + res = cfe_ioctl(fd,IOCTL_FLASH_GETINFO,(uint8_t *) &info,sizeof(flash_info_t),&retlen,0); + if (res == 0) { + printf("FLASH: Base %016llX size %08X type %02X(%s) flags %08X\n", + info.flash_base,info.flash_size,info.flash_type,flashtypes[info.flash_type], + info.flash_flags); + } + else { + printf("FLASH: Could not determine flash information\n"); + } + + res = cfe_ioctl(fd,IOCTL_NVRAM_GETINFO,(uint8_t *) &nvraminfo,sizeof(nvram_info_t),&retlen,0); + if (res == 0) { + printf("NVRAM: Offset %08X Size %08X EraseFlg %d\n", + nvraminfo.nvram_offset,nvraminfo.nvram_size,nvraminfo.nvram_eraseflg); + } + else { + printf("NVRAM: Not supported by this flash\n"); + } + + if (showsectors && (info.flash_type == FLASH_TYPE_FLASH)) { + printf("Flash sector information:\n"); + + idx = 0; + for (;;) { + sector.flash_sector_idx = idx; + res = cfe_ioctl(fd,IOCTL_FLASH_GETSECTORS,(uint8_t *) §or,sizeof(flash_sector_t),&retlen,0); + if (res != 0) { + printf("ioctl error\n"); + break; + } + if (sector.flash_sector_status == FLASH_SECTOR_INVALID) break; + printf(" Sector %d offset %08X size %d\n", + sector.flash_sector_idx, + sector.flash_sector_offset, + sector.flash_sector_size); + idx++; + } + } + + cfe_close(fd); + return 0; + +} + + +#if 0 +static int ui_cmd_readnvram(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *dev; + char *tok; + int fd; + int offset = 0; + int res; + uint8_t buf[512]; + int idx; + + dev = cmd_getarg(cmd,0); + if (!dev) return ui_showusage(cmd); + + tok = cmd_getarg(cmd,1); + if (tok) offset = xtoi(tok); + else offset = 0; + + fd = cfe_open(dev); + if (fd < 0) { + ui_showerror(fd,"could not open NVRAM"); + return fd; + } + + res = cfe_readblk(fd,offset,buf,512); + printf("Offset %d Result %d\n",offset,res); + for (idx = 0; idx < 512; idx++) { + if ((idx % 16) == 0) printf("\n"); + printf("%02X ",buf[idx]); + } + printf("\n"); + + cfe_close(fd); + return 0; + +} + +static int ui_cmd_erasenvram(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *dev; + int fd; + uint8_t buffer[2048]; + int res; + char *tok; + int offset; + int length; + uint8_t data; + + dev = cmd_getarg(cmd,0); + if (!dev) return ui_showusage(cmd); + + offset = 0; + if ((tok = cmd_getarg(cmd,1))) offset = xtoi(tok); + length = 512; + + if ((tok = cmd_getarg(cmd,2))) length = xtoi(tok); + if (length > 2048) length = 2048; + + data = 0xFF; + if ((tok = cmd_getarg(cmd,3))) data = xtoi(tok); + + fd = cfe_open(dev); + if (fd < 0) { + ui_showerror(fd,"could not open NVRAM"); + return fd; + } + + if (cmd_sw_isset(cmd,"-pattern")) { + memset(buffer,0,sizeof(buffer)); + for (res = 0; res < 2048; res++) { + buffer[res] = res & 0xFF; + } + } + else memset(buffer,data,sizeof(buffer)); + + printf("Fill offset %04X length %04X\n",offset,length); + + res = cfe_writeblk(fd,offset,buffer,length); + + printf("write returned %d\n",res); + + cfe_close(fd); + return 0; + +} +#endif + diff --git a/cfe/cfe/ui/ui_test_uart.c b/cfe/cfe/ui/ui_test_uart.c new file mode 100644 index 0000000..3eeaef0 --- /dev/null +++ b/cfe/cfe/ui/ui_test_uart.c @@ -0,0 +1,117 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * UART Test commands File: ui_test_uart.c + * + * Some commands to test the uart device interface. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_ioctl.h" + +#include "cfe_error.h" + +#include "ui_command.h" + +int ui_init_uarttestcmds(void); + +static int ui_cmd_uarttest(ui_cmdline_t *cmd,int argc,char *argv[]); + +int ui_init_uarttestcmds(void) +{ + cmd_addcmd("test uart", + ui_cmd_uarttest, + NULL, + "Echo characters to a UART", + "test uart [devname]", + ""); + return 0; +} + + +static int ui_cmd_uarttest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int fd; + char *x; + char ch; + int res; + char buffer[64]; + + x = cmd_getarg(cmd,0); + if (!x) return ui_showusage(cmd); + + fd = cfe_open(x); + if (fd < 0) { + ui_showerror(fd,"could not open %s",x); + return fd; + } + + printf("Device open. Stuff you type here goes there. Type ~ to exit.\n"); + for (;;) { + if (console_status()) { + console_read(&ch,1); + res = cfe_write(fd,&ch,1); + if (res < 0) break; + if (ch == '~') break; + } + if (cfe_inpstat(fd)) { + res = cfe_read(fd,buffer,sizeof(buffer)); + if (res > 0) console_write(buffer,res); + if (res < 0) break; + } + POLL(); + } + + cfe_close(fd); + return 0; +} + diff --git a/cfe/cfe/ui/ui_tftpd.c b/cfe/cfe/ui/ui_tftpd.c new file mode 100755 index 0000000..6cd2e4e --- /dev/null +++ b/cfe/cfe/ui/ui_tftpd.c @@ -0,0 +1,119 @@ +/*************************************************************************** +*** +*** Copyright 2005 Hon Hai Precision Ind. Co. Ltd. +*** All Rights Reserved. +*** No portions of this material shall be reproduced in any form without the +*** written permission of Hon Hai Precision Ind. Co. Ltd. +*** +*** All information contained in this document is Hon Hai Precision Ind. +*** Co. Ltd. company private, proprietary, and trade secret property and +*** are protected by international intellectual property laws and treaties. +*** +****************************************************************************/ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_error.h" + +#include "ui_command.h" +#include "cfe.h" + +#include "cfe_fileops.h" +#include "cfe_boot.h" +#include "bsp_config.h" + +#include "cfe_loader.h" + +#include "net_ebuf.h" +#include "net_ether.h" +#include "net_api.h" + +#include "cfe_flashimage.h" + +#include "addrspace.h" +#include "initdata.h" +#include "url.h" + +#include "tftpd.h" + +int ui_init_tftpdcmds(void); + +static int tftpd_state = TFTPD_STATE_OFF; + +extern int tftp_recv_timeout; + +int get_tftpd_state(void) +{ + return tftpd_state; +} + +int set_tftpd_state(int state) +{ + tftpd_state = state; + return 0; +} + +static int ui_cmd_tftpd(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int ret; + + xprintf("enter ui_cmd_tftpd \n"); + + if( (argc==1) && strcmp(argv[0], "nmrp") == 0 ) + { + xprintf("Start TFTP server for nmrp \n"); + ret = ui_docommand("flashimage nmrp"); + if (ret == CFE_ERR_TIMEOUT || ret == CFE_ERR_BADIMAGE || ret == CFE_ERR_IOERR || (ret == -24)) + { + //printf("Upgrade image failed!\n"); + return -1; + } + else + { + //printf("Upgrade image success!\n"); + return 0; + } + + + } + else + { + xprintf("Start TFTP server\n"); + /* Extend the TFTP server timeout */ + tftp_recv_timeout = 99999; + + while (1) + { + /* Foxconn modified start pling 12/04/2008 */ + //ret = ui_docommand("flash -writechksum : flash1.trx"); + ret = ui_docommand("flashimage :"); + /* Foxconn modified end pling 12/04/2008 */ + if (ret == CFE_ERR_TIMEOUT || ret == CFE_ERR_BADIMAGE || ret == CFE_ERR_IOERR) + continue; + else + break; + } + ui_docommand("reset"); + return 0; + } + +} +int ui_init_tftpdcmds(void) +{ + cmd_addcmd("tftpd", + ui_cmd_tftpd, + NULL, + "Start TFTP server", + "tftpd", + ""); + + return 0; +} diff --git a/cfe/cfe/ui/ui_toyclock.c b/cfe/cfe/ui/ui_toyclock.c new file mode 100644 index 0000000..7fdcf49 --- /dev/null +++ b/cfe/cfe/ui/ui_toyclock.c @@ -0,0 +1,275 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * SWARM toy clock commands File: ui_toyclock.c + * + * time-of-year clock + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_error.h" + +#include "ui_command.h" +#include "cfe.h" + +#include "bsp_config.h" + +/* ********************************************************************* + * prototypes + ********************************************************************* */ + +int ui_init_toyclockcmds(void); + +static int ui_cmd_showtime(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_settime(ui_cmdline_t *cmd,int argc,char *argv[]); +static int ui_cmd_setdate(ui_cmdline_t *cmd,int argc,char *argv[]); + +/* ********************************************************************* + * ui_init_toyclockcmds() + * + * Add toy clock commands to the command table + * + * Input parameters: + * nothing + * + * Return value: + * 0 + ********************************************************************* */ +int ui_init_toyclockcmds(void) +{ + + cmd_addcmd("show time", + ui_cmd_showtime, + NULL, + "Display current time according to RTC", + "show time", + ""); + + cmd_addcmd("set time", + ui_cmd_settime, + NULL, + "Set current time", + "set time hh:mm:ss", + ""); + + cmd_addcmd("set date", + ui_cmd_setdate, + NULL, + "Set current date", + "set date mm/dd/yyyy", + ""); + + return 0; +} + +/* ********************************************************************* + * User interface commands + ********************************************************************* */ + +static int ui_cmd_settime(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *line; + char *p; + int hr,min,sec; + int fd; + uint8_t buf[12]; + int res=0; + + if ((line = cmd_getarg(cmd,0)) == NULL) { + return ui_showusage(cmd); + } + + /* convert colons to spaces for the gettoken routine */ + while ((p = strchr(line,':'))) *p = ' '; + + /* parse and check command-line args */ + hr = -1; min = -1; sec = -1; + + p = gettoken(&line); + if (p) hr = atoi(p); + p = gettoken(&line); + if (p) min = atoi(p); + p = gettoken(&line); + if (p) sec = atoi(p); + + if ((hr < 0) || (hr > 23) || + (min < 0) || (min >= 60) || + (sec < 0) || (sec >= 60)) { + return ui_showusage(cmd); + } + + /* + * hour-minute-second-month-day-year1-year2-(time/date flag) + * time/date flag (offset 7) is used to let device know what + * is being set. + */ + buf[0] = hr; + buf[1] = min; + buf[2] = sec; + buf[7] = 0x00; /*SET_TIME = 0x00, SET_DATE = 0x01*/ + + fd = cfe_open("clock0"); + if (fd < 0) { + ui_showerror(fd,"could not open clock device"); + return fd; + } + + res = cfe_write(fd,buf,8); + if (res < 0) { + ui_showerror(res,"could not set time"); + } + cfe_close(fd); + return 0; +} + +static int ui_cmd_setdate(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + char *line; + char *p; + int dt,mo,yr,y2k; + int fd; + uint8_t buf[12]; + int res=0; + + if ((line = cmd_getarg(cmd,0)) == NULL) { + return ui_showusage(cmd); + } + + /* convert colons to spaces for the gettoken routine */ + + while ((p = strchr(line,'/'))) *p = ' '; + + /* parse and check command-line args */ + + dt = -1; mo = -1; yr = -1; + + p = gettoken(&line); + if (p) mo = atoi(p); + p = gettoken(&line); + if (p) dt = atoi(p); + p = gettoken(&line); + if (p) yr = atoi(p); + + if ((mo <= 0) || (mo > 12) || + (dt <= 0) || (dt > 31) || + (yr < 1900) || (yr > 2099)) { + return ui_showusage(cmd); + } + + y2k = (yr >= 2000) ? 0x20 : 0x19; + yr %= 100; + + /* + * hour-minute-second-month-day-year1-year2-(time/date flag) + * time/date flag (offset 7) is used to let device know what + * is being set. + */ + buf[3] = mo; + buf[4] = dt; + buf[5] = yr; + buf[6] = y2k; + buf[7] = 0x01; /*SET_TIME = 0x00, SET_DATE = 0x01*/ + + fd = cfe_open("clock0"); + if (fd < 0) { + ui_showerror(fd,"could not open clock device"); + return fd; + } + + res = cfe_write(fd,buf,8); + if (res < 0) { + ui_showerror(res,"could not set date"); + } + + cfe_close(fd); + return 0; +} + + +static int ui_cmd_showtime(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + uint8_t hr,min,sec; + uint8_t mo,day,yr,y2k; + int res=0; + int fd; + uint8_t buf[12]; + + fd = cfe_open("clock0"); + if (fd < 0) { + ui_showerror(fd,"could not open clock device"); + return fd; + } + res = cfe_read(fd,buf,8); + if (res < 0) { + ui_showerror(res,"could not get time/date"); + } + cfe_close(fd); + + hr = buf[0]; + min = buf[1]; + sec = buf[2]; + mo = buf[3]; + day = buf[4]; + yr = buf[5]; + y2k = buf[6]; + + printf("Current date & time is: "); + printf("%02X/%02X/%02X%02X %02X:%02X:%02X\n",mo,day,y2k,yr,hr,min,sec); + + return 0; +} + + + + + + + diff --git a/cfe/cfe/ui/url.c b/cfe/cfe/ui/url.c new file mode 100644 index 0000000..80dc7b0 --- /dev/null +++ b/cfe/cfe/ui/url.c @@ -0,0 +1,357 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Program and file loading URLs File: url.c + * + * Functions to process URLs for loading software. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. Neither the "Broadcom + * Corporation" name nor any trademark or logo of Broadcom + * Corporation may be used to endorse or promote products + * derived from this software without the prior written + * permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "bsp_config.h" +#include "cfe_loader.h" +#include "cfe_autoboot.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_fileops.h" +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" +#include "net_api.h" + +#include "ui_command.h" + +#include "url.h" + +static long getaddr(char *str) +{ + /* + * hold on to your lunch, this is really, really bad! + * Make 64-bit addresses expressed as 8-digit numbers + * sign extend automagically. Saves typing, but is very + * gross. Not very portable, either. + */ + int longaddr = 0; + long newaddr; + + longaddr = strlen(str); + if (memcmp(str,"0x",2) == 0) longaddr -= 2; + longaddr = (longaddr > 8) ? 1 : 0; + + if (longaddr) newaddr = (long) xtoq(str); + else newaddr = (long) xtoi(str); + + return newaddr; +} + +static int process_oldstyle(char *str, + ui_cmdline_t *cmd, + cfe_loadargs_t *la) +{ + char *file; + char *devname; + char *filesys = NULL; + char *loader = la->la_loader; + char *x; + int info; + char *colon; + + colon = strchr(str,':'); + + if (!colon) { + return CFE_ERR_DEVNOTFOUND; + } + + devname = str; /* will be used to check protocol later */ + *colon = '\0'; + file = colon + 1; /* Ugly, we might put the colon back! */ + + /* + * Try to determine the load protocol ("filesystem") + * first by using the command line, and + * if not that try to figure it out automagically + */ + + if (cmd_sw_isset(cmd,"-fatfs")) filesys = "fat"; + if (cmd_sw_isset(cmd,"-tftp")) filesys = "tftp"; + if (cmd_sw_isset(cmd,"-rawfs")) filesys = "raw"; +#if (CFG_TCP) && (CFG_HTTPFS) + if (cmd_sw_isset(cmd,"-http")) filesys = "http"; +#endif + if (cmd_sw_value(cmd,"-fs",&x)) filesys = x; + + /* + * Automagic configuration + */ + + /* + * Determine the device type from the "host" name. If we look + * up the host name and it appears to be an invalid CFE device + * name, then it's probably a TFTP host name. + * + * This is where we guess based on the device type what + * sort of load method we're going to use. + */ + + info = devname ? cfe_getdevinfo(devname) : -1; + if (info >= 0) { + switch (info & CFE_DEV_MASK) { + case CFE_DEV_NETWORK: + if (!filesys) filesys = "tftp"; + if (!loader) loader = "raw"; + break; + case CFE_DEV_DISK: + if (!filesys) filesys = "raw"; + if (!loader) loader = "raw"; + break; + case CFE_DEV_FLASH: + if (!filesys) filesys = "raw"; + if (!loader) loader = "raw"; + break; + case CFE_DEV_SERIAL: + if (!filesys) filesys = "raw"; + if (!loader) loader = "srec"; + break; + default: + break; + } + la->la_device = devname; + la->la_filename = file; + } + else { + /* + * It's probably a network boot. Default to TFTP + * if not overridden + */ +#if CFG_NETWORK + la->la_device = (char *) net_getparam(NET_DEVNAME); +#else + la->la_device = NULL; +#endif + *colon = ':'; /* put the colon back */ + la->la_filename = devname; + if (!filesys) filesys = "tftp"; + if (!loader) loader = "raw"; + } + + /* + * Remember our file system and loader. + */ + + la->la_filesys = filesys; + la->la_loader = loader; + + return 0; +} + + +#if CFG_URLS +static int process_url(char *str, + ui_cmdline_t *cmd, + cfe_loadargs_t *la) +{ + char *p; + char *protocol; + int idx,len; + int network = 0; + const fileio_dispatch_t *fdisp; + + /* + * All URLs have the string "://" in them somewhere + * If that's not there, try the old syntax. + */ + + len = strlen(str); + p = str; + + for (idx = 0; idx < len-3; idx++) { + if (memcmp(p,"://",3) == 0) break; + p++; + } + + if (idx == (len-3)) { + return process_oldstyle(str,cmd,la); + } + + /* + * Break the string apart into protocol, host, file + */ + + protocol = str; + *p = '\0'; + p += 3; + + /* + * Determine if this is a network loader. If that is true, + * the meaning of the "device" field is different. Ugh. + */ + + fdisp = cfe_findfilesys(protocol); + if (fdisp && (fdisp->loadflags & FSYS_TYPE_NETWORK)) network = 1; + + /* + * Depending on the protocol we parse the file name one of two ways: + * + * protocol://hostname/filename + * + * For network devices: + * + * the "device" is the current Ethernet device. + * The filename is the //hostname/filename from the URL. + * + * For non-network devices: + * + * The "device" is the CFE device name from the URL 'hostname' field + * The filename is from the URL filename field. + */ + + la->la_filesys = protocol; + + if (network) { +#if CFG_NETWORK + la->la_device = (char *) net_getparam(NET_DEVNAME); +#else + la->la_device = NULL; +#endif + la->la_filename = p; + } + else { + la->la_device = p; + p = strchr(p,'/'); + if (p) { + *p++ = '\0'; + la->la_filename = p; + } + else { + la->la_filename = NULL; + } + } + + if (!la->la_loader) la->la_loader = "raw"; + + return 0; +} +#endif + + + +int ui_process_url(char *url,ui_cmdline_t *cmd,cfe_loadargs_t *la) +{ + int res; + char *x; + + /* + * Skip leading whitespace + */ + + while (*url && ((*url == ' ') || (*url == '\t'))) url++; + + /* + * Process command-line switches to determine the loader stack + */ + + la->la_loader = NULL; + if (cmd_sw_isset(cmd,"-elf")) la->la_loader = "elf"; + if (cmd_sw_isset(cmd,"-srec")) la->la_loader = "srec"; + if (cmd_sw_isset(cmd,"-raw")) la->la_loader = "raw"; + if (cmd_sw_value(cmd,"-loader",&x)) la->la_loader = x; + +#if CFG_ZLIB + if (cmd_sw_isset(cmd,"-z")) { + la->la_flags |= LOADFLG_COMPRESSED; + } +#endif + + /* + * Parse the file name into its pieces. + */ + +#if CFG_URLS + res = process_url(url,cmd,la); + if (res < 0) return res; +#else + res = process_oldstyle(url,cmd,la); + if (res < 0) return res; +#endif + + + /* + * This is used only by "boot" and "load" - to avoid this code + * don't include these switches in the command table. + */ + + if (cmd_sw_value(cmd,"-max",&x)) { + la->la_maxsize = atoi(x); + } + + if (cmd_sw_value(cmd,"-addr",&x)) { + la->la_address = getaddr(x); + la->la_flags |= LOADFLG_SPECADDR; + } + + if (cmd_sw_isset(cmd,"-noclose")) { + la->la_flags |= LOADFLG_NOCLOSE; + } + +#if 0 + printf("--- Loader parameters:\n"); + printf(" Filename = %s\n",la->la_filename); + printf(" Filesys = %s\n",la->la_filesys); + printf(" Device = %s\n",la->la_device); + printf(" Options = %s\n",la->la_options); + printf(" Loader = %s\n",la->la_loader); + printf(" Flags = %08X\n",la->la_flags); + printf(" address = %08X\n",la->la_address); + printf(" maxsize = %08X\n",la->la_maxsize); + printf(" entrypt = %08X\n",la->la_entrypt); +#endif + + return 0; +} + + + diff --git a/cfe/cfe/ui/url.h b/cfe/cfe/ui/url.h new file mode 100644 index 0000000..268c7f8 --- /dev/null +++ b/cfe/cfe/ui/url.h @@ -0,0 +1,52 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Program and file loading URLs File: url.h + * + * Functions to process URLs for loading software. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. Neither the "Broadcom + * Corporation" name nor any trademark or logo of Broadcom + * Corporation may be used to endorse or promote products + * derived from this software without the prior written + * permission of Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ +#ifndef _URL_H_ +#define _URL_H_ 1 + +int ui_process_url(char *URL, ui_cmdline_t *cmd,cfe_loadargs_t *la); + +#endif /* _URL_H_ */ diff --git a/cfe/cfe/usb/Makefile b/cfe/cfe/usb/Makefile new file mode 100644 index 0000000..fa38870 --- /dev/null +++ b/cfe/cfe/usb/Makefile @@ -0,0 +1,8 @@ + +# +# Makefile for USB stuff +# + + +ALLOBJS += usbmain.o ohci.o usbd.o usbdevs.o usbhub.o usbdebug.o usbhid.o usbmass.o usbserial.o usbeth.o +CFLAGS += -DCFG_USB=1 diff --git a/cfe/cfe/usb/README b/cfe/cfe/usb/README new file mode 100644 index 0000000..28ac9bf --- /dev/null +++ b/cfe/cfe/usb/README @@ -0,0 +1,183 @@ + +------------------------------------------------------------------------ +This directory contains a basic description of the CFE USB stack, +its current status and features, and what might be done in the +future to improve it. +------------------------------------------------------------------------ + +Question: A USB stack in CFE? But why? + +Answer: Why not? It's not terribly useful on the BCM1250, since we + don't expect many of you to use USB in your boards, but there IS + a USB host controller on the SWARM (BCM1250 reference design). + Besides, CFE is actually being used for other non-SiByte + Broadcom chips, and some of those _do_ have USB on them. + +------------------------------------------------------------------------ + +Source Files +------------ + +ohci.c OHCI USB Host Controller Driver, tested on a BCM1250 + with an Opti FireLink PCI USB controller + +ohci.h Register definitions for ohci.c + +usbchap9.h USB "Chapter 9" definitions (Descriptors, etc.) + +usbd.c USB Basic Request and pipe management routines, to + manage usb devices, do simple requests on the + control pipe, open and manage pipes, etc. + +usbd.h Prototypes and data structures for usbd.c + +usbdevs.c USB Device Driver list - devices we recognize + are listed here - if you add a new USB device, + you can add its class or vendor ID entries + into the table here. + +usbdebug.c Some descriptor dump routines live here. + +usbhub.c Class driver for USB hubs. Because hubs are also + a major player in device discovery, much of the + USB device tree management also lives here. + +usbhid.c Class driver for keyboards and mice. Right now + not much is done with them except echo characters. + +usbmass.c Class driver for USB mass-storage devices. We only + support the "bulk-only-no-interrupt" protocol. + This driver also includes a top half so that + it can be accessed as a CFE mass-storage device. + +usbmain.c Top-level interface into CFE. The "usb start" + command is instantiated here, as well as a + "usb show" command to display attached USB devices. + +usbhack.c Main program for the test harness, which lets you + develop OHCI code under Linux without hacking on + either CFE or the kernel. See the comments in this + file for more information. + +usbhack.h A dumping ground for CFE definitions not otherwise + provided by the standard include files. + +usbhack.mk GNU makefile for the test harness + +------------------------------------------------------------------------ + +Overview +-------- + +The host controller driver is abstracted through a small set of +primitives defined in usbd.h - at present only the OHCI driver +is implemented, but there will eventually be support for the +ScanLogic SL11H part on the BCM1250CPCI board - this is a simple +"generic-bus" (non-pci) host controller. I doubt we'll ever +need EHCI/UHCI, since they are present mostly in Intel chipsets. + +All events are polled by this driver. There are two polling functions +that should be called periodically: + + usb_poll(usbbus_t *bus); + usb_daemon(usbbus_t *bus); + +The "poll" routine handles interrupts from the devices themselves. +The "daemon" routine monitors the bus for topology changes and +instantiates an exploration if something changes. Sometimes "daemon" +needs to do USB I/O, requiring calls to usb_poll() to get the data +to go in/out via the controller, hence the two routines. You should +be careful not to all usb_poll() during polling. + + +Device Drivers +-------------- + +USB Device drivers are currently extremely simple: There are +only two methods that need be exported to the device driver table: + +attach() Called when the device is "discovered" +detach() Called when the device is "removed" + +When a device is removed, pending transfer requests will be +canceled with a "canceled" status. + +There is no standard for the top side (user API side) of the +device driver, that is up to the device class. The bottom half +should make use of the calls in usbd.c + +When a device driver is attached via its attach() method, +it will be in the "addressed" state according to the USB spec. +The exploration code takes care of assigning the USB address +to the device. Devices not otherwise recognized by this code will +be left in the addressed state without any active configurations. + +The descriptors are read by the exploration code and are made +available to the usb_find_cfg_descr() call - you can use this +function to obtain the endpoint and interface descriptors for +your device and then call usb_set_configuration() to activate +the configuration. + +When your detach() method is called, the device should be considered +already gone, so do not attempt to do any I/O to it. Just clean +up the mess and return. + + +------------------------------------------------------------------------ + +What works? +----------- + +* OHCI on a BCM1250 via the Opti Firelink USB controller + +* The OHCI root hub emulation + +* External hubs, and hubs integrated into other devices like + keyboards. + +* Interrupt transfers + +* Transfers (basic requests) on endpoint 0 + +* Basic device discovery and removal + +* Bulk endpoints and transfers + +* Some endpoint stalls are handled. + + +------------------------------------------------------------------------ + +What doesn't work? What is not implemented? +-------------------------------------------- + +* The root hub implementation is really shaky, especially in + matters of plug-and-play (device insertion/removal events, + etc.) Don't be surprised if removing a device from the + root hub causes CFE to freeze. + +* There is no error recovery code whatsoever. This kind of goes + with the above root hub issue. + +* Noncoherent DMA is relatively untested. + +* Isochronous endpoints are completely unimplemented (and will probably + remain that way) + +* Power management (for example, power budget in hubs) is unimplemented. + (this should be easy) + +* Interrupt endpoints are all on the 10ms endpoint in the interrupt + tree (endpoints should be placed at the location to guarantee + bandwidth at 'bInterval' ms) - no bandwidth management is being + done at the moment, but this is pretty simple. + +* The OHCI driver cannot be stopped/unloaded. + + + + + + + + diff --git a/cfe/cfe/usb/ohci.c b/cfe/cfe/usb/ohci.c new file mode 100644 index 0000000..c002091 --- /dev/null +++ b/cfe/cfe/usb/ohci.c @@ -0,0 +1,2126 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * OHCI device driver File: ohci.c + * + * Open Host Controller Interface low-level routines + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_ +#include +#include +#include +#include +#include +#include "usbhack.h" +#define CPUCFG_COHERENT_DMA 1 /* hack runs on a PC, PCs are coherent */ +#else +#include "lib_types.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "lib_physio.h" +#include "addrspace.h" +#include "cpu_config.h" /* for CPUCFG_COHERENT_DMA */ +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" +#include "ohci.h" + + +/* ********************************************************************* + * Macros for dealing with hardware + * + * This is all yucky stuff that needs to be made more + * processor-independent. It's mostly here now to help us with + * our test harness. + ********************************************************************* */ + +#if defined(_CFE_) && defined(__MIPSEB) +#define BSWAP32(x) __swap32(x) +static inline uint32_t __swap32(uint32_t x) +{ + uint32_t y; + + y = ((x & 0xFF) << 24) | + ((x & 0xFF00) << 8) | + ((x & 0xFF0000) >> 8) | + ((x & 0xFF000000) >> 24); + + return y; +} +#else +#define BSWAP32(x) (x) +#endif + + +#ifndef _CFE_ +extern uint32_t vtop(void *ptr); +extern void *ptov(uint32_t x); +#define OHCI_VTOP(ptr) vtop(ptr) +#define OHCI_PTOV(ptr) ptov(ptr) +#define OHCI_WRITECSR(softc,x,y) \ + *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t)))) = (y) +#define OHCI_READCSR(softc,x) \ + *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t)))) +#else +#define OHCI_VTOP(ptr) ((uint32_t)PHYSADDR((long)(ptr))) + +#if CPUCFG_COHERENT_DMA +#define OHCI_PTOV(ptr) ((void *)(KERNADDR(ptr))) +#else +#define OHCI_PTOV(ptr) ((void *)(UNCADDR(ptr))) +#endif + +#define OHCI_WRITECSR(softc,x,y) \ + phys_write32(((softc)->ohci_regs + (x)),(y)) +#define OHCI_READCSR(softc,x) \ + phys_read32(((softc)->ohci_regs + (x))) +#endif + +#if CPUCFG_COHERENT_DMA +#define OHCI_INVAL_RANGE(s,l) +#define OHCI_FLUSH_RANGE(s,l) +#else /* not coherent */ +#define CFE_CACHE_INVAL_RANGE 32 /* XXX belongs in include file */ +#define CFE_CACHE_FLUSH_RANGE 64 +extern void _cfe_flushcache(int,uint8_t *,uint8_t *); +#define OHCI_INVAL_RANGE(s,l) _cfe_flushcache(CFE_CACHE_INVAL_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l)) +#define OHCI_FLUSH_RANGE(s,l) _cfe_flushcache(CFE_CACHE_FLUSH_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l)) +#endif + + +/* ********************************************************************* + * Bit-reverse table - this table consists of the numbers + * at its index, listed in reverse. So, the reverse of 0000 0010 + * is 0100 0000. + ********************************************************************* */ + +const static int ohci_revbits[OHCI_INTTABLE_SIZE] = { + 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, + 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, + 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, + 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f +}; + + +/* ********************************************************************* + * Macros to convert from "hardware" endpoint and transfer + * descriptors (ohci_ed_t, ohci_td_t) to "software" + * data structures (ohci_transfer_t, ohci_endpoint_t). + * + * Basically, there are two tables, indexed by the same value + * By subtracting the base of one pool from a pointer, we get + * the index into the other table. + * + * We *could* have included the ed and td in the software + * data structures, but placing all the hardware stuff in one + * pool will make it easier for hardware that does not handle + * coherent DMA, since we can be less careful about what we flush + * and what we invalidate. + ********************************************************************* */ + +#define ohci_td_from_transfer(softc,transfer) \ + ((softc)->ohci_hwtdpool + ((transfer) - (softc)->ohci_transfer_pool)) + +#define ohci_transfer_from_td(softc,td) \ + ((softc)->ohci_transfer_pool + ((td) - (softc)->ohci_hwtdpool)) + +#define ohci_ed_from_endpoint(softc,endpoint) \ + ((softc)->ohci_hwedpool + ((endpoint) - (softc)->ohci_endpoint_pool)) + +#define ohci_endpoint_from_ed(softc,ed) \ + ((softc)->ohci_endpoint_pool + ((ed) - (softc)->ohci_hwedpool)) + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + +static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur); +static void ohci_roothub_statchg(ohci_softc_t *softc); +extern usb_hcdrv_t ohci_driver; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +int ohcidebug = 0; +void ohci_dumprhstat(uint32_t reg); +void ohci_dumpportstat(int idx,uint32_t reg); +void ohci_dumptd(ohci_td_t *td); +void ohci_dumptdchain(ohci_td_t *td); +void ohci_dumped(ohci_ed_t *ed); +void ohci_dumpedchain(ohci_ed_t *ed); + + +/* ********************************************************************* + * Some debug routines + ********************************************************************* */ + +#if 1 +void ohci_dumprhstat(uint32_t reg) +{ + printf("HubStatus: %08X ",reg); + + if (reg & M_OHCI_RHSTATUS_LPS) printf("LocalPowerStatus "); + if (reg & M_OHCI_RHSTATUS_OCI) printf("OverCurrent "); + if (reg & M_OHCI_RHSTATUS_DRWE) printf("DeviceRemoteWakeupEnable "); + if (reg & M_OHCI_RHSTATUS_LPSC) printf("LocalPowerStatusChange "); + if (reg & M_OHCI_RHSTATUS_OCIC) printf("OverCurrentIndicatorChange "); + printf("\n"); + +} + +void ohci_dumpportstat(int idx,uint32_t reg) +{ + printf("Port %d: %08X ",idx,reg); + if (reg & M_OHCI_RHPORTSTAT_CCS) printf("Connected "); + if (reg & M_OHCI_RHPORTSTAT_PES) printf("PortEnabled "); + if (reg & M_OHCI_RHPORTSTAT_PSS) printf("PortSuspended "); + if (reg & M_OHCI_RHPORTSTAT_POCI) printf("PortOverCurrent "); + if (reg & M_OHCI_RHPORTSTAT_PRS) printf("PortReset "); + if (reg & M_OHCI_RHPORTSTAT_PPS) printf("PortPowered "); + if (reg & M_OHCI_RHPORTSTAT_LSDA) printf("LowSpeed "); + if (reg & M_OHCI_RHPORTSTAT_CSC) printf("ConnectStatusChange "); + if (reg & M_OHCI_RHPORTSTAT_PESC) printf("PortEnableStatusChange "); + if (reg & M_OHCI_RHPORTSTAT_PSSC) printf("PortSuspendStatusChange "); + if (reg & M_OHCI_RHPORTSTAT_OCIC) printf("OverCurrentIndicatorChange "); + if (reg & M_OHCI_RHPORTSTAT_PRSC) printf("PortResetStatusChange "); + printf("\n"); +} + +void ohci_dumptd(ohci_td_t *td) +{ + uint32_t ctl; + static char *pids[4] = {"SETUP","OUT","IN","RSVD"}; + + ctl = BSWAP32(td->td_control); + + printf("[%08X] ctl=%08X (DP=%s,DI=%d,T=%d,EC=%d,CC=%d%s) cbp=%08X be=%08X next=%08X\n", + OHCI_VTOP(td), + ctl, + pids[G_OHCI_TD_PID(ctl)], + G_OHCI_TD_DI(ctl), + G_OHCI_TD_DT(ctl), + G_OHCI_TD_EC(ctl), + G_OHCI_TD_CC(ctl), + (ctl & M_OHCI_TD_SHORTOK) ? ",R" : "", + BSWAP32(td->td_cbp), + BSWAP32(td->td_be), + BSWAP32(td->td_next_td)); +} + +void ohci_dumptdchain(ohci_td_t *td) +{ + int idx = 0; + for (;;) { + printf("%d:[%08X] ctl=%08X cbp=%08X be=%08X next=%08X\n", + idx, + OHCI_VTOP(td), + BSWAP32(td->td_control), + BSWAP32(td->td_cbp), + BSWAP32(td->td_be), + BSWAP32(td->td_next_td)); + if (!td->td_next_td) break; + td = (ohci_td_t *) OHCI_PTOV(BSWAP32(td->td_next_td)); + idx++; + } +} + +void ohci_dumped(ohci_ed_t *ed) +{ + uint32_t ctl; + static char *pids[4] = {"FTD","OUT","IN","FTD"}; + + ctl = BSWAP32(ed->ed_control), + + printf("[%08X] Ctl=%08X (MPS=%d%s%s%s,EN=%d,FA=%d,D=%s) Tailp=%08X headp=%08X next=%08X %s\n", + OHCI_VTOP(ed), + ctl, + G_OHCI_ED_MPS(ctl), + (ctl & M_OHCI_ED_LOWSPEED) ? ",LS" : "", + (ctl & M_OHCI_ED_SKIP) ? ",SKIP" : "", + (ctl & M_OHCI_ED_ISOCFMT) ? ",ISOC" : "", + G_OHCI_ED_EN(ctl), + G_OHCI_ED_FA(ctl), + pids[G_OHCI_ED_DIR(ctl)], + BSWAP32(ed->ed_tailp), + BSWAP32(ed->ed_headp), + BSWAP32(ed->ed_next_ed), + BSWAP32(ed->ed_headp) & M_OHCI_ED_HALT ? "HALT" : ""); + if ((ed->ed_headp & M_OHCI_ED_PTRMASK) == 0) return; + ohci_dumptdchain(OHCI_PTOV(BSWAP32(ed->ed_headp) & M_OHCI_ED_PTRMASK)); +} + +void ohci_dumpedchain(ohci_ed_t *ed) +{ + int idx = 0; + for (;;) { + printf("---\nED#%d -> ",idx); + ohci_dumped(ed); + if (!ed->ed_next_ed) break; + if (idx > 50) break; + ed = (ohci_ed_t *) OHCI_PTOV(BSWAP32(ed->ed_next_ed)); + idx++; + } +} + +#endif + + +static void eptstats(ohci_softc_t *softc) +{ + int cnt; + ohci_endpoint_t *e; + cnt = 0; + + e = softc->ohci_endpoint_freelist; + while (e) { e = e->ep_next; cnt++; } + printf("%d left, %d inuse\n",cnt,OHCI_EDPOOL_SIZE-cnt); +} + +/* ********************************************************************* + * _ohci_allocept(softc) + * + * Allocate an endpoint data structure from the pool, and + * make it ready for use. The endpoint is NOT attached to + * the hardware at this time. + * + * Input parameters: + * softc - our OHCI controller + * + * Return value: + * pointer to endpoint or NULL + ********************************************************************* */ + +static ohci_endpoint_t *_ohci_allocept(ohci_softc_t *softc) +{ + ohci_endpoint_t *e; + ohci_ed_t *ed; + + if (ohcidebug > 2) { + printf("AllocEpt: ");eptstats(softc); + } + + e = softc->ohci_endpoint_freelist; + + if (!e) { + printf("No endpoints left!\n"); + return NULL; + } + + softc->ohci_endpoint_freelist = e->ep_next; + + ed = ohci_ed_from_endpoint(softc,e); + + ed->ed_control = BSWAP32(M_OHCI_ED_SKIP); + ed->ed_tailp = BSWAP32(0); + ed->ed_headp = BSWAP32(0); + ed->ed_next_ed = BSWAP32(0); + + e->ep_phys = OHCI_VTOP(ed); + e->ep_next = NULL; + + return e; +} + +/* ********************************************************************* + * _ohci_allocxfer(softc) + * + * Allocate a transfer descriptor. It is prepared for use + * but not attached to the hardware. + * + * Input parameters: + * softc - our OHCI controller + * + * Return value: + * transfer descriptor, or NULL + ********************************************************************* */ + +static ohci_transfer_t *_ohci_allocxfer(ohci_softc_t *softc) +{ + ohci_transfer_t *t; + ohci_td_t *td; + + if (ohcidebug > 2) { + int cnt; + cnt = 0; + t = softc->ohci_transfer_freelist; + while (t) { t = t->t_next; cnt++; } + printf("AllocXfer: %d left, %d inuse\n",cnt,OHCI_TDPOOL_SIZE-cnt); + } + + t = softc->ohci_transfer_freelist; + + if (!t) { + printf("No more transfer descriptors!\n"); + return NULL; + } + + softc->ohci_transfer_freelist = t->t_next; + + td = ohci_td_from_transfer(softc,t); + + td->td_control = BSWAP32(0); + td->td_cbp = BSWAP32(0); + td->td_next_td = BSWAP32(0); + td->td_be = BSWAP32(0); + + t->t_ref = NULL; + t->t_next = NULL; + + return t; +} + +/* ********************************************************************* + * _ohci_freeept(softc,e) + * + * Free an endpoint, returning it to the pool. + * + * Input parameters: + * softc - our OHCI controller + * e - endpoint descriptor to return + * + * Return value: + * nothing + ********************************************************************* */ + +static void _ohci_freeept(ohci_softc_t *softc,ohci_endpoint_t *e) +{ + if (ohcidebug > 2) { + int cnt; + ohci_endpoint_t *ee; + cnt = 0; + ee = softc->ohci_endpoint_freelist; + while (ee) { ee = ee->ep_next; cnt++; } + printf("FreeEpt[%p]: %d left, %d inuse\n",e,cnt,OHCI_EDPOOL_SIZE-cnt); + } + + e->ep_next = softc->ohci_endpoint_freelist; + softc->ohci_endpoint_freelist = e; +} + +/* ********************************************************************* + * _ohci_freexfer(softc,t) + * + * Free a transfer descriptor, returning it to the pool. + * + * Input parameters: + * softc - our OHCI controller + * t - transfer descriptor to return + * + * Return value: + * nothing + ********************************************************************* */ + +static void _ohci_freexfer(ohci_softc_t *softc,ohci_transfer_t *t) +{ + t->t_next = softc->ohci_transfer_freelist; + softc->ohci_transfer_freelist = t; +} + +/* ********************************************************************* + * _ohci_initpools(softc) + * + * Allocate and initialize the various pools of things that + * we use in the OHCI driver. We do this by allocating some + * big chunks from the heap and carving them up. + * + * Input parameters: + * softc - our OHCI controller + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int _ohci_initpools(ohci_softc_t *softc) +{ + int idx; + + /* + * Do the transfer descriptor pool + */ + + softc->ohci_transfer_pool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_transfer_t),0); + softc->ohci_hwtdpool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_td_t),OHCI_TD_ALIGN); + + /* + * In the case of noncoherent DMA, make these uncached addresses. + * This way all our descriptors will be uncached. Makes life easier, as we + * do not need to worry about flushing descriptors, etc. + */ + +#if (!CPUCFG_COHERENT_DMA) + softc->ohci_hwtdpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwtdpool))); +#endif + + if (!softc->ohci_transfer_pool || !softc->ohci_hwtdpool) { + printf("Could not allocate transfer descriptors\n"); + return -1; + } + + softc->ohci_transfer_freelist = NULL; + + for (idx = 0; idx < OHCI_TDPOOL_SIZE; idx++) { + _ohci_freexfer(softc,softc->ohci_transfer_pool+idx); + } + + /* + * Do the endpoint descriptor pool + */ + + softc->ohci_endpoint_pool = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_endpoint_t),0); + + softc->ohci_hwedpool = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_ed_t),OHCI_ED_ALIGN); + +#if (!CPUCFG_COHERENT_DMA) + softc->ohci_hwedpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwedpool))); +#endif + + if (!softc->ohci_endpoint_pool || !softc->ohci_hwedpool) { + printf("Could not allocate transfer descriptors\n"); + return -1; + } + + softc->ohci_endpoint_freelist = NULL; + + for (idx = 0; idx < OHCI_EDPOOL_SIZE; idx++) { + _ohci_freeept(softc,softc->ohci_endpoint_pool+idx); + } + + /* + * Finally the host communications area + */ + + softc->ohci_hcca = KMALLOC(sizeof(ohci_hcca_t),sizeof(ohci_hcca_t)); + +#if (!CPUCFG_COHERENT_DMA) + softc->ohci_hcca = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hcca))); +#endif + + memset(softc->ohci_hcca,0,sizeof(ohci_hcca_t)); + + return 0; +} + + +/* ********************************************************************* + * ohci_start(bus) + * + * Start the OHCI controller. After this routine is called, + * the hardware will be operational and ready to accept + * descriptors and interrupt calls. + * + * Input parameters: + * bus - bus structure, from ohci_create + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int ohci_start(usbbus_t *bus) +{ + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + uint32_t frameint; + uint32_t reg; + int idx; + + /* + * Force a reset to the controller, followed by a short delay + */ + + OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET)); + usb_delay_ms(bus,OHCI_RESET_DELAY); + + /* Host controller state is now "RESET" */ + + /* + * We need the frame interval later, so get a copy of it now. + */ + frameint = G_OHCI_FMINTERVAL_FI(OHCI_READCSR(softc,R_OHCI_FMINTERVAL)); + + /* + * Reset the host controller. When you set the HCR bit + * if self-clears when the reset is complete. + */ + + OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_HCR); + for (idx = 0; idx < 10000; idx++) { + if (!(OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR)) break; + } + + if (OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR) { + /* controller never came out of reset */ + return -1; + } + + /* + * Host controller state is now "SUSPEND". We must exit + * from this state within 2ms. (5.1.1.4) + * + * Set up pointers to data structures. + */ + + OHCI_WRITECSR(softc,R_OHCI_HCCA,OHCI_VTOP(softc->ohci_hcca)); + OHCI_WRITECSR(softc,R_OHCI_CONTROLHEADED,softc->ohci_ctl_list->ep_phys); + OHCI_WRITECSR(softc,R_OHCI_BULKHEADED,softc->ohci_bulk_list->ep_phys); + + /* + * Our driver is polled, turn off interrupts + */ + + OHCI_WRITECSR(softc,R_OHCI_INTDISABLE,M_OHCI_INT_ALL); + + /* + * Set up the control register. + */ + + reg = OHCI_READCSR(softc,R_OHCI_CONTROL); + + reg = M_OHCI_CONTROL_PLE | M_OHCI_CONTROL_CLE | M_OHCI_CONTROL_BLE | + M_OHCI_CONTROL_IE | + V_OHCI_CONTROL_CBSR(K_OHCI_CBSR_41) | + V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_OPERATIONAL); + + OHCI_WRITECSR(softc,R_OHCI_CONTROL,reg); + + + /* + * controller state is now OPERATIONAL + */ + + reg = OHCI_READCSR(softc,R_OHCI_FMINTERVAL); + reg &= M_OHCI_FMINTERVAL_FIT; + reg ^= M_OHCI_FMINTERVAL_FIT; + reg |= V_OHCI_FMINTERVAL_FSMPS(OHCI_CALC_FSMPS(frameint)) | + V_OHCI_FMINTERVAL_FI(frameint); + OHCI_WRITECSR(softc,R_OHCI_FMINTERVAL,reg); + + reg = frameint * 9 / 10; /* calculate 90% */ + OHCI_WRITECSR(softc,R_OHCI_PERIODICSTART,reg); + + usb_delay_ms(softc->ohci_bus,10); + + /* + * Remember how many ports we have + */ + + reg = OHCI_READCSR(softc,R_OHCI_RHDSCRA); + softc->ohci_ndp = G_OHCI_RHDSCRA_NDP(reg); + + + /* + * Enable port power + */ + + OHCI_WRITECSR(softc,R_OHCI_RHSTATUS,M_OHCI_RHSTATUS_LPSC); + usb_delay_ms(softc->ohci_bus,10); + + return 0; +} + + +/* ********************************************************************* + * _ohci_setupepts(softc) + * + * Set up the endpoint tree, as described in the OHCI manual. + * Basically the hardware knows how to scan lists of lists, + * so we build a tree where each level is pointed to by two + * parent nodes. We can choose our scanning rate by attaching + * endpoints anywhere within this tree. + * + * Input parameters: + * softc - our OHCI controller + * + * Return value: + * 0 if ok + * else error (out of descriptors) + ********************************************************************* */ + +static int _ohci_setupepts(ohci_softc_t *softc) +{ + int idx; + ohci_endpoint_t *e; + ohci_ed_t *ed; + ohci_endpoint_t *child; + + /* + * Set up the list heads for the isochronous, control, + * and bulk transfer lists. They don't get the same "tree" + * treatment that the interrupt devices get. + * + * For the purposes of CFE, it's probably not necessary + * to be this fancy. The only device we're planning to + * talk to is the keyboard and some hubs, which should + * have pretty minimal requirements. It's conceivable + * that this firmware may find a new home in other + * devices, so we'll meet halfway and do some things + * "fancy." + */ + + softc->ohci_isoc_list = _ohci_allocept(softc); + softc->ohci_ctl_list = _ohci_allocept(softc); + softc->ohci_bulk_list = _ohci_allocept(softc); + + /* + * Set up a tree of empty endpoint descriptors. This is + * tree is scanned by the hardware from the leaves up to + * the root. Once a millisecond, the hardware picks the + * next leaf and starts scanning descriptors looking + * for something to do. It traverses all of the endpoints + * along the way until it gets to the root. + * + * The idea here is if you put a transfer descriptor on the + * root node, the hardware will see it every millisecond, + * since the root will be examined each time. If you + * put the TD on the leaf, it will be 1/32 millisecond. + * The tree therefore is six levels deep. + */ + + for (idx = 0; idx < OHCI_INTTREE_SIZE; idx++) { + e = _ohci_allocept(softc); /* allocated with sKip bit set */ + softc->ohci_edtable[idx] = e; + child = (idx == 0) ? softc->ohci_isoc_list : softc->ohci_edtable[(idx-1)/2]; + ed = ohci_ed_from_endpoint(softc,e); + ed->ed_next_ed = BSWAP32(child->ep_phys); + e->ep_next = child; + } + + /* + * We maintain both physical and virtual copies of the interrupt + * table (leaves of the tree). + */ + + for (idx = 0; idx < OHCI_INTTABLE_SIZE; idx++) { + child = softc->ohci_edtable[OHCI_INTTREE_SIZE-OHCI_INTTABLE_SIZE+idx]; + softc->ohci_inttable[ohci_revbits[idx]] = child; + softc->ohci_hcca->hcca_inttable[ohci_revbits[idx]] = BSWAP32(child->ep_phys); + } + + /* + * Okay, at this point the tree is built. + */ + return 0; +} + +/* ********************************************************************* + * ohci_stop(bus) + * + * Stop the OHCI hardware. + * + * Input parameters: + * bus - our bus structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_stop(usbbus_t *bus) +{ + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + + OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET)); +} + + +/* ********************************************************************* + * _ohci_queueept(softc,queue,e) + * + * Add an endpoint to a list of endpoints. This routine + * does things in a particular way according to the OHCI + * spec so we can add endpoints while the hardware is running. + * + * Input parameters: + * queue - endpoint descriptor for head of queue + * e - endpoint to add to queue + * + * Return value: + * nothing + ********************************************************************* */ + +static void _ohci_queueept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *newept) +{ + ohci_ed_t *qed; + ohci_ed_t *newed; + + qed = ohci_ed_from_endpoint(softc,queue); + newed = ohci_ed_from_endpoint(softc,newept); + + newept->ep_next = queue->ep_next; + newed->ed_next_ed = qed->ed_next_ed; + + queue->ep_next = newept; + qed->ed_next_ed = BSWAP32(newept->ep_phys); + + if (ohcidebug > 1) ohci_dumped(newed); + +} + +/* ********************************************************************* + * _ohci_deqept(queue,e) + * + * Remove and endpoint from the list of endpoints. This + * routine does things in a particular way according to + * the OHCI specification, since we are operating on + * a running list. + * + * Input parameters: + * queue - base of queue to look for endpoint on + * e - endpoint to remove + * + * Return value: + * nothing + ********************************************************************* */ + +static void _ohci_deqept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *e) +{ + ohci_endpoint_t *cur; + ohci_ed_t *cured; + ohci_ed_t *ed; + + cur = queue; + + while (cur && (cur->ep_next != e)) cur = cur->ep_next; + + if (cur == NULL) { + printf("Could not remove EP %08X: not on the list!\n",(uint32_t) (intptr_t)e); + return; + } + + /* + * Remove from our regular list + */ + + cur->ep_next = e->ep_next; + + /* + * now remove from the hardware's list + */ + + cured = ohci_ed_from_endpoint(softc,cur); + ed = ohci_ed_from_endpoint(softc,e); + + cured->ed_next_ed = ed->ed_next_ed; +} + + +/* ********************************************************************* + * ohci_intr_procdoneq(softc) + * + * Process the "done" queue for this ohci controller. As + * descriptors are retired, the hardware links them to the + * "done" queue so we can examine the results. + * + * Input parameters: + * softc - our OHCI controller + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_intr_procdoneq(ohci_softc_t *softc) +{ + uint32_t doneq; + ohci_transfer_t *transfer; + ohci_td_t *td; + int val; + usbreq_t *ur; + + /* + * Get the head of the queue + */ + + doneq = softc->ohci_hcca->hcca_donehead; + doneq = BSWAP32(doneq); + + td = (ohci_td_t *) OHCI_PTOV(doneq); + transfer = ohci_transfer_from_td(softc,td); + + /* + * Process all elements from the queue + */ + + while (doneq) { + + ohci_ed_t *ed; + ohci_endpoint_t *ept; + usbreq_t *xur = transfer->t_ref; + + if (ohcidebug > 1) { + if (xur) { + ept = (ohci_endpoint_t *) xur->ur_pipe->up_hwendpoint; + ed = ohci_ed_from_endpoint(softc,ept); +// printf("ProcDoneQ:ED [%08X] -> ",ept->ep_phys); +// ohci_dumped(ed); + } + } + + /* + * Get the pointer to next one before freeing this one + */ + + if (ohcidebug > 1) { + ur = transfer->t_ref; + printf("Done(%d): ",ur ? ur->ur_tdcount : -1); + ohci_dumptd(td); + } + + doneq = BSWAP32(td->td_next_td); + + val = G_OHCI_TD_CC(BSWAP32(td->td_control)); + + if (val != 0) printf("[Transfer error: %d]\n",val); + + /* + * See if it's time to call the callback. + */ + ur = transfer->t_ref; + if (ur) { + ur->ur_status = val; + ur->ur_tdcount--; + if (BSWAP32(td->td_cbp) == 0) { + ur->ur_xferred += transfer->t_length; + } + else { + ur->ur_xferred += transfer->t_length - + (BSWAP32(td->td_be) - BSWAP32(td->td_cbp) + 1); + } + if (ur->ur_tdcount == 0) { + /* Noncoherent DMA: need to invalidate, since data is in phys mem */ + OHCI_INVAL_RANGE(ur->ur_buffer,ur->ur_xferred); + usb_complete_request(ur,val); + } + } + + + /* + * Free up the request + */ + _ohci_freexfer(softc,transfer); + + + /* + * Advance to the next request. + */ + + td = (ohci_td_t *) OHCI_PTOV(doneq); + transfer = ohci_transfer_from_td(softc,td); + } + +} + +/* ********************************************************************* + * ohci_intr(bus) + * + * Process pending interrupts for the OHCI controller. + * + * Input parameters: + * bus - our bus structure + * + * Return value: + * 0 if we did nothing + * nonzero if we did something. + ********************************************************************* */ + +static int ohci_intr(usbbus_t *bus) +{ + uint32_t reg; + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + + /* + * Read the interrupt status register. + */ + + reg = OHCI_READCSR(softc,R_OHCI_INTSTATUS); + + /* + * Don't bother doing anything if nothing happened. + */ + if (reg == 0) { + return 0; + } + + /* Scheduling Overruns */ + if (reg & M_OHCI_INT_SO) { + printf("SchedOverrun\n"); + } + + /* Done Queue */ + if (reg & M_OHCI_INT_WDH) { + /* printf("DoneQueue\n"); */ + ohci_intr_procdoneq(softc); + } + + /* Start of Frame */ + if (reg & M_OHCI_INT_SF) { + /* don't be noisy about this */ + } + + /* Resume Detect */ + if (reg & M_OHCI_INT_RD) { + printf("ResumeDetect\n"); + } + + /* Unrecoverable errors */ + if (reg & M_OHCI_INT_UE) { + printf("UnrecoverableError\n"); + } + + /* Frame number overflow */ + if (reg & M_OHCI_INT_FNO) { + /*printf("FrameNumberOverflow\n"); */ + } + + /* Root Hub Status Change */ + if ((reg & ~softc->ohci_intdisable) & M_OHCI_INT_RHSC) { + uint32_t reg; + if (ohcidebug > 0) { + printf("RootHubStatusChange: "); + reg = OHCI_READCSR(softc,R_OHCI_RHSTATUS); + ohci_dumprhstat(reg); + reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(1)); + ohci_dumpportstat(1,reg); + reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(2)); + ohci_dumpportstat(2,reg); + } + ohci_roothub_statchg(softc); + } + + /* Ownership Change */ + if (reg & M_OHCI_INT_OC) { + printf("OwnershipChange\n"); + } + + /* + * Write the value back to the interrupt + * register to clear the bits that were set. + */ + + OHCI_WRITECSR(softc,R_OHCI_INTSTATUS,reg); + + return 1; +} + + +/* ********************************************************************* + * ohci_delete(bus) + * + * Remove an OHCI bus structure and all resources allocated to + * it (used when shutting down USB) + * + * Input parameters: + * bus - our USB bus structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_delete(usbbus_t *bus) +{ + // xxx fill in later. +} + + +/* ********************************************************************* + * ohci_create(addr) + * + * Create a USB bus structure and associate it with our OHCI + * controller device. + * + * Input parameters: + * addr - physical address of controller + * + * Return value: + * usbbus structure pointer + ********************************************************************* */ + +static usbbus_t *ohci_create(physaddr_t addr) +{ + int res; + ohci_softc_t *softc; + usbbus_t *bus; + + softc = KMALLOC(sizeof(ohci_softc_t),0); + if (!softc) return NULL; + + bus = KMALLOC(sizeof(usbbus_t),0); + if (!bus) return NULL; + + memset(softc,0,sizeof(ohci_softc_t)); + memset(bus,0,sizeof(usbbus_t)); + + bus->ub_hwsoftc = (usb_hc_t *) softc; + bus->ub_hwdisp = &ohci_driver; + + q_init(&(softc->ohci_rh_intrq)); + +#ifdef _CFE_ + softc->ohci_regs = addr; +#else + softc->ohci_regs = (volatile uint32_t *) addr; +#endif + + softc->ohci_rh_newaddr = -1; + softc->ohci_bus = bus; + + if ((res = _ohci_initpools(softc)) != 0) goto error; + if ((res = _ohci_setupepts(softc)) != 0) goto error; + + OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET)); + + return bus; + +error: + KFREE(softc); + return NULL; +} + + +/* ********************************************************************* + * ohci_ept_create(bus,usbaddr,eptnum,mps,flags) + * + * Create a hardware endpoint structure and attach it to + * the hardware's endpoint list. The hardware manages lists + * of queues, and this routine adds a new queue to the appropriate + * list of queues for the endpoint in question. It roughly + * corresponds to the information in the OHCI specification. + * + * Input parameters: + * bus - the USB bus we're dealing with + * usbaddr - USB address (0 means default address) + * eptnum - the endpoint number + * mps - the packet size for this endpoint + * flags - various flags to control endpoint creation + * + * Return value: + * endpoint structure poihter, or NULL + ********************************************************************* */ + +static usb_ept_t *ohci_ept_create(usbbus_t *bus, + int usbaddr, + int eptnum, + int mps, + int flags) +{ + uint32_t eptflags; + ohci_endpoint_t *ept; + ohci_ed_t *ed; + ohci_transfer_t *tailtransfer; + ohci_td_t *tailtd; + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + + ept = _ohci_allocept(softc); + ed = ohci_ed_from_endpoint(softc,ept); + + tailtransfer = _ohci_allocxfer(softc); + tailtd = ohci_td_from_transfer(softc,tailtransfer); + + /* + * Set up functional address, endpoint number, and packet size + */ + + eptflags = V_OHCI_ED_FA(usbaddr) | + V_OHCI_ED_EN(eptnum) | + V_OHCI_ED_MPS(mps) | + 0; + + /* + * Set up the endpoint type based on the flags + * passed to us + */ + + if (flags & UP_TYPE_IN) { + eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_IN); + } + else if (flags & UP_TYPE_OUT) { + eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_OUT); + } + else { + eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_FROMTD); + } + + /* + * Don't forget about lowspeed devices. + */ + + if (flags & UP_TYPE_LOWSPEED) { + eptflags |= M_OHCI_ED_LOWSPEED; + } + + if (ohcidebug > 0) { + printf("Create endpoint %d addr %d flags %08X mps %d\n", + eptnum,usbaddr,eptflags,mps); + } + + /* + * Transfer this info into the endpoint descriptor. + * No need to flush the cache here, it'll get done when + * we add to the hardware list. + */ + + ed->ed_control = BSWAP32(eptflags); + ed->ed_tailp = BSWAP32(OHCI_VTOP(tailtd)); + ed->ed_headp = BSWAP32(OHCI_VTOP(tailtd)); + ept->ep_flags = flags; + ept->ep_mps = mps; + ept->ep_num = eptnum; + + /* + * Put it on the right queue + */ + + if (flags & UP_TYPE_CONTROL) { + _ohci_queueept(softc,softc->ohci_ctl_list,ept); + } + else if (flags & UP_TYPE_BULK) { + _ohci_queueept(softc,softc->ohci_bulk_list,ept); + } + else if (flags & UP_TYPE_INTR) { + /* XXX Choose place in inttable properly. */ + _ohci_queueept(softc,softc->ohci_inttable[0],ept); + } + + return (usb_ept_t *) ept; +} + +/* ********************************************************************* + * ohci_ept_setaddr(bus,ept,usbaddr) + * + * Change the functional address for a USB endpoint. We do this + * when we switch the device's state from DEFAULT to ADDRESSED + * and we've already got the default pipe open. This + * routine mucks with the descriptor and changes its address + * bits. + * + * Input parameters: + * bus - usb bus structure + * ept - an open endpoint descriptor + * usbaddr - new address for this endpoint + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_ept_setaddr(usbbus_t *bus,usb_ept_t *uept,int usbaddr) +{ + uint32_t eptflags; + ohci_endpoint_t *ept = (ohci_endpoint_t *) uept; + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept); + + eptflags = BSWAP32(ed->ed_control); + eptflags &= ~M_OHCI_ED_FA; + eptflags |= V_OHCI_ED_FA(usbaddr); + ed->ed_control = BSWAP32(eptflags); +} + + +/* ********************************************************************* + * ohci_ept_setmps(bus,ept,mps) + * + * Set the maximum packet size of this endpoint. This is + * normally used during the processing of endpoint 0 (default + * pipe) after we find out how big ep0's packets can be. + * + * Input parameters: + * bus - our USB bus structure + * ept - endpoint structure + * mps - new packet size + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_ept_setmps(usbbus_t *bus,usb_ept_t *uept,int mps) +{ + uint32_t eptflags; + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + ohci_endpoint_t *ept = (ohci_endpoint_t *) uept; + ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept); + + eptflags = BSWAP32(ed->ed_control); + eptflags &= ~M_OHCI_ED_MPS; + eptflags |= V_OHCI_ED_MPS(mps); + ed->ed_control = BSWAP32(eptflags); + ept->ep_mps = mps; + +} + +/* ********************************************************************* + * ohci_ept_cleartoggle(bus,ept,mps) + * + * Clear the data toggle for the specified endpoint. + * + * Input parameters: + * bus - our USB bus structure + * ept - endpoint structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_ept_cleartoggle(usbbus_t *bus,usb_ept_t *uept) +{ + uint32_t eptflags; + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + ohci_endpoint_t *ept = (ohci_endpoint_t *) uept; + ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept); + + eptflags = BSWAP32(ed->ed_headp); + eptflags &= ~(M_OHCI_ED_HALT | M_OHCI_ED_TOGGLECARRY); + ed->ed_headp = BSWAP32(eptflags); + + OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF); +} + +/* ********************************************************************* + * ohci_ept_delete(bus,ept) + * + * Deletes an endpoint from the OHCI controller. This + * routine also completes pending transfers for the + * endpoint and gets rid of the hardware ept (queue base). + * + * Input parameters: + * bus - ohci bus structure + * ept - endpoint to remove + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_ept_delete(usbbus_t *bus,usb_ept_t *uept) +{ + ohci_endpoint_t *queue; + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + ohci_endpoint_t *ept = (ohci_endpoint_t *) uept; + ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept); + uint32_t framenum; + uint32_t tdphys; + usbreq_t *ur; + ohci_td_t *td; + ohci_transfer_t *transfer; + + if (ept->ep_flags & UP_TYPE_CONTROL) { + queue = softc->ohci_ctl_list; + } + else if (ept->ep_flags & UP_TYPE_BULK) { + queue = softc->ohci_bulk_list; + } + else if (ept->ep_flags & UP_TYPE_INTR) { + queue = softc->ohci_inttable[0]; + } + else { + printf("Invalid endpoint\n"); + return; + } + + + /* + * Set the SKIP bit on the endpoint and + * wait for two SOFs to guarantee that we're + * not processing this ED anymore. + */ + + ((volatile uint32_t) ed->ed_control) |= BSWAP32(M_OHCI_ED_SKIP); + + framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF; + while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */ + + framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF; + while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */ + + /* + * Remove endpoint from queue + */ + + _ohci_deqept(softc,queue,ept); + + /* + * Free/complete the TDs on the queue + */ + + tdphys = BSWAP32(ed->ed_headp) & M_OHCI_ED_PTRMASK; + + while (tdphys != BSWAP32(ed->ed_tailp)) { + td = (ohci_td_t *) OHCI_PTOV(tdphys); + tdphys = BSWAP32(td->td_next_td); + transfer = ohci_transfer_from_td(softc,td); + + ur = transfer->t_ref; + if (ur) { + ur->ur_status = K_OHCI_CC_CANCELLED; + ur->ur_tdcount--; + if (ur->ur_tdcount == 0) { + if (ohcidebug > 0) printf("Completing request due to closed pipe: %p\n",ur); + usb_complete_request(ur,K_OHCI_CC_CANCELLED); + /* XXX it is expected that the callee will free the usbreq. */ + } + } + + _ohci_freexfer(softc,transfer); + } + + /* + * tdphys now points at the tail TD. Just free it. + */ + + td = (ohci_td_t *) OHCI_PTOV(tdphys); + _ohci_freexfer(softc,ohci_transfer_from_td(softc,td)); + + /* + * Return endpoint to free pool + */ + + _ohci_freeept(softc,ept); +} + + + +/* ********************************************************************* + * ohci_xfer(bus,ept,ur) + * + * Queue a transfer for the specified endpoint. Depending on + * the transfer type, the transfer may go on one of many queues. + * When the transfer completes, a callback will be called. + * + * Input parameters: + * bus - bus structure + * ept - endpoint descriptor + * ur - request (includes pointer to user buffer) + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +static int ohci_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur) +{ + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + ohci_endpoint_t *ept = (ohci_endpoint_t *) uept; + ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept); + ohci_transfer_t *newtailtransfer = 0; + ohci_td_t *newtailtd = NULL; + ohci_transfer_t *curtransfer; + ohci_td_t *curtd; + uint8_t *ptr; + int len; + int amtcopy; + int pktlen; + uint32_t tdcontrol = 0; + + /* + * If the destination USB address matches + * the address of the root hub, shunt the request + * over to our root hub emulation. + */ + + if (ur->ur_dev->ud_address == softc->ohci_rh_addr) { + return ohci_roothub_xfer(bus,uept,ur); + } + + /* + * Set up the TD flags based on the + * request type. + */ + +// pktlen = ept->ep_mps; + pktlen = OHCI_TD_MAX_DATA - 16; + + if (ur->ur_flags & UR_FLAG_SETUP) { + tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_SETUP) | + V_OHCI_TD_DT(K_OHCI_TD_DT_DATA0) | + V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) | + V_OHCI_TD_DI(1); + } + else if (ur->ur_flags & UR_FLAG_IN) { + tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) | + V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) | + V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) | + V_OHCI_TD_DI(1); + } + else if (ur->ur_flags & UR_FLAG_OUT) { + tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) | + V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) | + V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) | + V_OHCI_TD_DI(1); + } + else if (ur->ur_flags & UR_FLAG_STATUS_OUT) { + tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) | + V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) | + V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) | + V_OHCI_TD_DI(1); + } + else if (ur->ur_flags & UR_FLAG_STATUS_IN) { + tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) | + V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) | + V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) | + V_OHCI_TD_DI(1); + } + else { + printf("Shouldn't happen!\n"); + } + + if (ur->ur_flags & UR_FLAG_SHORTOK) { + tdcontrol |= M_OHCI_TD_SHORTOK; + } + + + ptr = ur->ur_buffer; + len = ur->ur_length; + ur->ur_tdcount = 0; + + if (ohcidebug > 1) { + printf(">> Queueing xfer addr %d pipe %d ED %08X ptr %016llX length %d\n", + ur->ur_dev->ud_address, + ur->ur_pipe->up_num, + ept->ep_phys, + (uint64_t) (uintptr_t) ptr, + len); +// ohci_dumped(ed); + } + + curtd = OHCI_PTOV(BSWAP32(ed->ed_tailp)); + curtransfer = ohci_transfer_from_td(softc,curtd); + + if (len == 0) { + newtailtransfer = _ohci_allocxfer(softc); + newtailtd = ohci_td_from_transfer(softc,newtailtransfer); + curtd->td_cbp = 0; + curtd->td_be = 0; + curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd)); + curtd->td_control = BSWAP32(tdcontrol); + curtransfer->t_next = newtailtransfer; + curtransfer->t_ref = ur; + curtransfer->t_length = 0; + if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); } + ur->ur_tdcount++; + } + else { + /* Noncoherent DMA: need to flush user buffer to real memory first */ + OHCI_FLUSH_RANGE(ptr,len); + while (len > 0) { + amtcopy = len; + if (amtcopy > pktlen) amtcopy = pktlen; + newtailtransfer = _ohci_allocxfer(softc); + newtailtd = ohci_td_from_transfer(softc,newtailtransfer); + curtd->td_cbp = BSWAP32(OHCI_VTOP(ptr)); + curtd->td_be = BSWAP32(OHCI_VTOP(ptr+amtcopy)-1); + curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd)); + curtd->td_control = BSWAP32(tdcontrol); + curtransfer->t_next = newtailtransfer; + curtransfer->t_ref = ur; + curtransfer->t_length = amtcopy; + if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); } + curtd = newtailtd; + curtransfer = ohci_transfer_from_td(softc,curtd); + ptr += amtcopy; + len -= amtcopy; + ur->ur_tdcount++; + } + } + + curtd = OHCI_PTOV(BSWAP32(ed->ed_headp & M_OHCI_ED_PTRMASK)); + ed->ed_tailp = BSWAP32(OHCI_VTOP(newtailtd)); + + /* + * Prod the controller depending on what type of list we put + * a TD on. + */ + + if (ept->ep_flags & UP_TYPE_BULK) { + OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_BLF); + } + else { + /* XXX should probably make sure we're UP_TYPE_CONTROL here */ + OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF); + } + + return 0; +} + +/* ********************************************************************* + * Driver structure + ********************************************************************* */ + +usb_hcdrv_t ohci_driver = { + ohci_create, + ohci_delete, + ohci_start, + ohci_stop, + ohci_intr, + ohci_ept_create, + ohci_ept_delete, + ohci_ept_setmps, + ohci_ept_setaddr, + ohci_ept_cleartoggle, + ohci_xfer +}; + +/* ********************************************************************* + * Root Hub + * + * Data structures and functions + ********************************************************************* */ + +/* + * Data structures and routines to emulate the root hub. + */ +static usb_device_descr_t ohci_root_devdsc = { + sizeof(usb_device_descr_t), /* bLength */ + USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ + USBWORD(0x0100), /* bcdUSB */ + USB_DEVICE_CLASS_HUB, /* bDeviceClass */ + 0, /* bDeviceSubClass */ + 0, /* bDeviceProtocol */ + 64, /* bMaxPacketSize0 */ + USBWORD(0), /* idVendor */ + USBWORD(0), /* idProduct */ + USBWORD(0x0100), /* bcdDevice */ + 1, /* iManufacturer */ + 2, /* iProduct */ + 0, /* iSerialNumber */ + 1 /* bNumConfigurations */ +}; + +static usb_config_descr_t ohci_root_cfgdsc = { + sizeof(usb_config_descr_t), /* bLength */ + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ + USBWORD( + sizeof(usb_config_descr_t) + + sizeof(usb_interface_descr_t) + + sizeof(usb_endpoint_descr_t)), /* wTotalLength */ + 1, /* bNumInterfaces */ + 1, /* bConfigurationValue */ + 0, /* iConfiguration */ + USB_CONFIG_SELF_POWERED, /* bmAttributes */ + 0 /* MaxPower */ +}; + +static usb_interface_descr_t ohci_root_ifdsc = { + sizeof(usb_interface_descr_t), /* bLength */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0, /* bInterfaceNumber */ + 0, /* bAlternateSetting */ + 1, /* bNumEndpoints */ + USB_INTERFACE_CLASS_HUB, /* bInterfaceClass */ + 0, /* bInterfaceSubClass */ + 0, /* bInterfaceProtocol */ + 0 /* iInterface */ +}; + +static usb_endpoint_descr_t ohci_root_epdsc = { + sizeof(usb_endpoint_descr_t), /* bLength */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ + (USB_ENDPOINT_DIRECTION_IN | 1), /* bEndpointAddress */ + USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ + USBWORD(8), /* wMaxPacketSize */ + 255 /* bInterval */ +}; + +static usb_hub_descr_t ohci_root_hubdsc = { + USB_HUB_DESCR_SIZE, /* bLength */ + USB_HUB_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0, /* bNumberOfPorts */ + USBWORD(0), /* wHubCharacteristics */ + 0, /* bPowreOnToPowerGood */ + 0, /* bHubControl Current */ + {0} /* bRemoveAndPowerMask */ +}; + +/* ********************************************************************* + * ohci_roothb_strdscr(ptr,str) + * + * Construct a string descriptor for root hub requests + * + * Input parameters: + * ptr - pointer to where to put descriptor + * str - regular string to put into descriptor + * + * Return value: + * number of bytes written to descriptor + ********************************************************************* */ + +static int ohci_roothub_strdscr(uint8_t *ptr,char *str) +{ + uint8_t *p = ptr; + + *p++ = strlen(str)*2 + 2; /* Unicode strings */ + *p++ = USB_STRING_DESCRIPTOR_TYPE; + while (*str) { + *p++ = *str++; + *p++ = 0; + } + return (p - ptr); +} + +/* ********************************************************************* + * ohci_roothub_req(softc,req) + * + * Handle a descriptor request on the control pipe for the + * root hub. We pretend to be a real root hub here and + * return all the standard descriptors. + * + * Input parameters: + * softc - our OHCI controller + * req - a usb request (completed immediately) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int ohci_roothub_req(ohci_softc_t *softc,usb_device_request_t *req) +{ + uint8_t *ptr; + uint16_t wLength; + uint16_t wValue; + uint16_t wIndex; + usb_port_status_t ups; + usb_hub_descr_t hdsc; + uint32_t status; + uint32_t statport; + uint32_t tmpval; + int res = 0; + + ptr = softc->ohci_rh_buf; + + wLength = GETUSBFIELD(req,wLength); + wValue = GETUSBFIELD(req,wValue); + wIndex = GETUSBFIELD(req,wIndex); + + switch (REQSW(req->bRequest,req->bmRequestType)) { + + case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE): + *ptr++ = (USB_GETSTATUS_SELF_POWERED & 0xFF); + *ptr++ = (USB_GETSTATUS_SELF_POWERED >> 8); + break; + + case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT): + case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE): + *ptr++ = 0; + *ptr++ = 0; + break; + + case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER): + status = OHCI_READCSR(softc,(R_OHCI_RHPORTSTATUS(wIndex))); + if (ohcidebug > 0) { printf("RHGetStatus: "); ohci_dumpportstat(wIndex,status);} + PUTUSBFIELD((&ups),wPortStatus,(status & 0xFFFF)); + PUTUSBFIELD((&ups),wPortChange,(status >> 16)); + memcpy(ptr,&ups,sizeof(ups)); + ptr += sizeof(ups); + break; + + case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE): + *ptr++ = 0; + *ptr++ = 0; + *ptr++ = 0; + *ptr++ = 0; + break; + + case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE): + case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE): + case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT): + /* do nothing, not supported */ + break; + + case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER): + statport = R_OHCI_RHPORTSTATUS(wIndex); + if (ohcidebug> 0) { + printf("RHClearFeature(%d): ",wValue); ohci_dumpportstat(wIndex,OHCI_READCSR(softc,statport)); + } + switch (wValue) { + case USB_PORT_FEATURE_CONNECTION: + break; + case USB_PORT_FEATURE_ENABLE: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CCS); + break; + case USB_PORT_FEATURE_SUSPEND: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_POCI); + break; + case USB_PORT_FEATURE_OVER_CURRENT: + break; + case USB_PORT_FEATURE_RESET: + break; + case USB_PORT_FEATURE_POWER: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_LSDA); + break; + case USB_PORT_FEATURE_LOW_SPEED: + break; + case USB_PORT_FEATURE_C_PORT_CONNECTION: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CSC); + break; + case USB_PORT_FEATURE_C_PORT_ENABLE: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PESC); + break; + case USB_PORT_FEATURE_C_PORT_SUSPEND: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSSC); + break; + case USB_PORT_FEATURE_C_PORT_OVER_CURRENT: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_OCIC); + break; + case USB_PORT_FEATURE_C_PORT_RESET: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRSC); + break; + + } + + /* + * If we've cleared all of the conditions that + * want our attention on the port status, + * then we can accept port status interrupts again. + */ + + if ((wValue >= USB_PORT_FEATURE_C_PORT_CONNECTION) && + (wValue <= USB_PORT_FEATURE_C_PORT_RESET)) { + status = OHCI_READCSR(softc,statport); + if ((status & M_OHCI_RHPORTSTAT_ALLC) == 0) { + softc->ohci_intdisable &= ~M_OHCI_INT_RHSC; + } + } + break; + + case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE): + case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE): + case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT): + res = -1; + break; + + case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE): + /* nothing */ + break; + + case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER): + statport = R_OHCI_RHPORTSTATUS(wIndex); + switch (wValue) { + case USB_PORT_FEATURE_CONNECTION: + break; + case USB_PORT_FEATURE_ENABLE: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PES); + break; + case USB_PORT_FEATURE_SUSPEND: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSS); + break; + case USB_PORT_FEATURE_OVER_CURRENT: + break; + case USB_PORT_FEATURE_RESET: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRS); + for (;;) { /* XXX timer */ + usb_delay_ms(softc->ohci_bus,100); + if (!(OHCI_READCSR(softc,statport) & M_OHCI_RHPORTSTAT_PRS)) break; + } + break; + case USB_PORT_FEATURE_POWER: + OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PPS); + break; + case USB_PORT_FEATURE_LOW_SPEED: + break; + case USB_PORT_FEATURE_C_PORT_CONNECTION: + break; + case USB_PORT_FEATURE_C_PORT_ENABLE: + break; + case USB_PORT_FEATURE_C_PORT_SUSPEND: + break; + case USB_PORT_FEATURE_C_PORT_OVER_CURRENT: + break; + case USB_PORT_FEATURE_C_PORT_RESET: + break; + + } + + break; + + case REQCODE(USB_REQUEST_SET_ADDRESS,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE): + softc->ohci_rh_newaddr = wValue; + break; + + case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE): + switch (wValue >> 8) { + case USB_DEVICE_DESCRIPTOR_TYPE: + memcpy(ptr,&ohci_root_devdsc,sizeof(ohci_root_devdsc)); + ptr += sizeof(ohci_root_devdsc); + break; + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + memcpy(ptr,&ohci_root_cfgdsc,sizeof(ohci_root_cfgdsc)); + ptr += sizeof(ohci_root_cfgdsc); + memcpy(ptr,&ohci_root_ifdsc,sizeof(ohci_root_ifdsc)); + ptr += sizeof(ohci_root_ifdsc); + memcpy(ptr,&ohci_root_epdsc,sizeof(ohci_root_epdsc)); + ptr += sizeof(ohci_root_epdsc); + break; + case USB_STRING_DESCRIPTOR_TYPE: + switch (wValue & 0xFF) { + case 1: + ptr += ohci_roothub_strdscr(ptr,"Generic"); + break; + case 2: + ptr += ohci_roothub_strdscr(ptr,"Root Hub"); + break; + default: + *ptr++ = 0; + break; + } + break; + default: + res = -1; + break; + } + break; + + case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE): + memcpy(&hdsc,&ohci_root_hubdsc,sizeof(hdsc)); + hdsc.bNumberOfPorts = softc->ohci_ndp; + status = OHCI_READCSR(softc,R_OHCI_RHDSCRA); + tmpval = 0; + if (status & M_OHCI_RHDSCRA_NPS) tmpval |= USB_HUBCHAR_PWR_NONE; + if (status & M_OHCI_RHDSCRA_PSM) tmpval |= USB_HUBCHAR_PWR_GANGED; + else tmpval |= USB_HUBCHAR_PWR_IND; + PUTUSBFIELD((&hdsc),wHubCharacteristics,tmpval); + tmpval = G_OHCI_RHDSCRA_POTPGT(status); + hdsc.bPowerOnToPowerGood = tmpval; + hdsc.bDescriptorLength = USB_HUB_DESCR_SIZE + 1; + status = OHCI_READCSR(softc,R_OHCI_RHDSCRB); + hdsc.bRemoveAndPowerMask[0] = (uint8_t) status; + memcpy(ptr,&hdsc,sizeof(hdsc)); + ptr += sizeof(hdsc); + break; + + case REQCODE(USB_REQUEST_SET_DESCRIPTOR,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE): + /* nothing */ + break; + + case REQCODE(USB_REQUEST_GET_CONFIGURATION,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE): + *ptr++ = softc->ohci_rh_conf; + break; + + case REQCODE(USB_REQUEST_SET_CONFIGURATION,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE): + softc->ohci_rh_conf = wValue; + break; + + case REQCODE(USB_REQUEST_GET_INTERFACE,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE): + *ptr++ = 0; + break; + + case REQCODE(USB_REQUEST_SET_INTERFACE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE): + /* nothing */ + break; + + case REQCODE(USB_REQUEST_SYNC_FRAME,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT): + /* nothing */ + break; + } + + softc->ohci_rh_ptr = softc->ohci_rh_buf; + softc->ohci_rh_len = ptr - softc->ohci_rh_buf; + + return res; +} + +/* ********************************************************************* + * ohci_roothub_statchg(softc) + * + * This routine is called from the interrupt service routine + * (well, polling routine) for the ohci controller. If the + * controller notices a root hub status change, it dequeues an + * interrupt transfer from the root hub's queue and completes + * it here. + * + * Input parameters: + * softc - our OHCI controller + * + * Return value: + * nothing + ********************************************************************* */ + +static void ohci_roothub_statchg(ohci_softc_t *softc) +{ + usbreq_t *ur; + uint32_t status; + uint8_t portstat = 0; + int idx; + + /* Note: this only works up to 8 ports */ + for (idx = 1; idx <= softc->ohci_ndp; idx++) { + status = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(idx)); + if (status & M_OHCI_RHPORTSTAT_ALLC) { + portstat = (1<ohci_intdisable |= M_OHCI_INT_RHSC; + } + + ur = (usbreq_t *) q_deqnext(&(softc->ohci_rh_intrq)); + if (!ur) return; /* no requests pending, ignore it */ + + memset(ur->ur_buffer,0,ur->ur_length); + ur->ur_buffer[0] = portstat; + ur->ur_xferred = ur->ur_length; + + usb_complete_request(ur,0); +} + +/* ********************************************************************* + * ohci_roothub_xfer(softc,req) + * + * Handle a root hub xfer - ohci_xfer transfers control here + * if we detect the address of the root hub - no actual transfers + * go out on the wire, we just handle the requests directly to + * make it look like a hub is attached. + * + * This seems to be common practice in the USB world, so we do + * it here too. + * + * Input parameters: + * softc - our OHCI controller structure + * req - usb request destined for host controller + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur) +{ + ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc; + ohci_endpoint_t *ept = (ohci_endpoint_t *) uept; + int res; + + switch (ept->ep_num) { + + /* + * CONTROL ENDPOINT + */ + case 0: + + /* + * Three types of transfers: OUT (SETUP), IN (data), or STATUS. + * figure out which is which. + */ + + if (ur->ur_flags & UR_FLAG_SETUP) { + /* + * SETUP packet - this is an OUT request to the control + * pipe. We emulate the hub request here. + */ + usb_device_request_t *req; + + req = (usb_device_request_t *) ur->ur_buffer; + + res = ohci_roothub_req(softc,req); + if (res != 0) printf("Root hub request returned an error\n"); + + ur->ur_xferred = ur->ur_length; + ur->ur_status = 0; + usb_complete_request(ur,0); + } + + else if (ur->ur_flags & UR_FLAG_STATUS_IN) { + /* + * STATUS IN : it's sort of like a dummy IN request + * to acknowledge a SETUP packet that otherwise has no + * status. Just complete the usbreq. + */ + + if (softc->ohci_rh_newaddr != -1) { + softc->ohci_rh_addr = softc->ohci_rh_newaddr; + softc->ohci_rh_newaddr = -1; + } + + ur->ur_status = 0; + ur->ur_xferred = 0; + usb_complete_request(ur,0); + } + + else if (ur->ur_flags & UR_FLAG_STATUS_OUT) { + /* + * STATUS OUT : it's sort of like a dummy OUT request + */ + ur->ur_status = 0; + ur->ur_xferred = 0; + usb_complete_request(ur,0); + } + + else if (ur->ur_flags & UR_FLAG_IN) { + /* + * IN : return data from the root hub + */ + int amtcopy; + + amtcopy = softc->ohci_rh_len; + if (amtcopy > ur->ur_length) amtcopy = ur->ur_length; + + memcpy(ur->ur_buffer,softc->ohci_rh_ptr,amtcopy); + + softc->ohci_rh_ptr += amtcopy; + softc->ohci_rh_len -= amtcopy; + + ur->ur_status = 0; + ur->ur_xferred = amtcopy; + usb_complete_request(ur,0); + } + + else { + printf("Unknown root hub transfer type\n"); + return -1; + } + break; + + /* + * INTERRUPT ENDPOINT + */ + + case 1: /* interrupt pipe */ + if (ur->ur_flags & UR_FLAG_IN) { + q_enqueue(&(softc->ohci_rh_intrq),(queue_t *) ur); + } + break; + + } + + + return 0; +} diff --git a/cfe/cfe/usb/ohci.h b/cfe/cfe/usb/ohci.h new file mode 100644 index 0000000..06368e5 --- /dev/null +++ b/cfe/cfe/usb/ohci.h @@ -0,0 +1,490 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * OHCI defs File: ohci.h + * + * Open Host controller interface definitions + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +/* ********************************************************************* + * Macros to muck with bitfields + ********************************************************************* */ + +#define _OHCI_MAKE32(x) ((uint32_t)(x)) + +/* + * Make a mask for 1 bit at position 'n' + */ + +#define _OHCI_MAKEMASK1(n) (_OHCI_MAKE32(1) << _OHCI_MAKE32(n)) + +/* + * Make a mask for 'v' bits at position 'n' + */ + +#define _OHCI_MAKEMASK(v,n) (_OHCI_MAKE32((_OHCI_MAKE32(1)<<(v))-1) << _OHCI_MAKE32(n)) + +/* + * Make a value at 'v' at bit position 'n' + */ + +#define _OHCI_MAKEVALUE(v,n) (_OHCI_MAKE32(v) << _OHCI_MAKE32(n)) +#define _OHCI_GETVALUE(v,n,m) ((_OHCI_MAKE32(v) & _OHCI_MAKE32(m)) >> _OHCI_MAKE32(n)) + + + +/* ********************************************************************* + * Endpoint Descriptor (interrupt, bulk) + ********************************************************************* */ + +#define OHCI_ED_ALIGN 32 + +typedef struct ohci_ed_s { + uint32_t ed_control; + uint32_t ed_tailp; + uint32_t ed_headp; + uint32_t ed_next_ed; +} ohci_ed_t; + +#define S_OHCI_ED_FA 0 +#define M_OHCI_ED_FA _OHCI_MAKEMASK(7,S_OHCI_ED_FA) +#define V_OHCI_ED_FA(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_FA) +#define G_OHCI_ED_FA(x) _OHCI_GETVALUE(x,S_OHCI_ED_FA,M_OHCI_ED_FA) + +#define S_OHCI_ED_EN 7 +#define M_OHCI_ED_EN _OHCI_MAKEMASK(4,S_OHCI_ED_EN) +#define V_OHCI_ED_EN(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_EN) +#define G_OHCI_ED_EN(x) _OHCI_GETVALUE(x,S_OHCI_ED_EN,M_OHCI_ED_EN) + +#define S_OHCI_ED_DIR 11 +#define M_OHCI_ED_DIR _OHCI_MAKEMASK(2,S_OHCI_ED_DIR) +#define V_OHCI_ED_DIR(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_DIR) +#define G_OHCI_ED_DIR(x) _OHCI_GETVALUE(x,S_OHCI_ED_DIR,M_OHCI_ED_DIR) + +#define K_OHCI_ED_DIR_FROMTD 0 +#define K_OHCI_ED_DIR_OUT 1 +#define K_OHCI_ED_DIR_IN 2 + +#define M_OHCI_ED_LOWSPEED _OHCI_MAKEMASK1(13) +#define M_OHCI_ED_SKIP _OHCI_MAKEMASK1(14) +#define M_OHCI_ED_ISOCFMT _OHCI_MAKEMASK1(15) + +#define S_OHCI_ED_MPS 16 +#define M_OHCI_ED_MPS _OHCI_MAKEMASK(11,S_OHCI_ED_MPS) +#define V_OHCI_ED_MPS(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_MPS) +#define G_OHCI_ED_MPS(x) _OHCI_GETVALUE(x,S_OHCI_ED_MPS,M_OHCI_ED_MPS) + +#define M_OHCI_ED_PTRMASK 0xFFFFFFF0 +#define M_OHCI_ED_HALT _OHCI_MAKEMASK1(0) +#define M_OHCI_ED_TOGGLECARRY _OHCI_MAKEMASK1(1) + +/* ********************************************************************* + * Transfer Descriptor + ********************************************************************* */ + +#define OHCI_TD_ALIGN 32 + +typedef struct ohci_td_s { + uint32_t td_control; + uint32_t td_cbp; + uint32_t td_next_td; + uint32_t td_be; +} ohci_td_t; + +#define M_OHCI_TD_SHORTOK _OHCI_MAKEMASK1(18) + +#define S_OHCI_TD_PID 19 +#define M_OHCI_TD_PID _OHCI_MAKEMASK(2,S_OHCI_TD_PID) +#define V_OHCI_TD_PID(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_PID) +#define G_OHCI_TD_PID(x) _OHCI_GETVALUE(x,S_OHCI_TD_PID,M_OHCI_TD_PID) + +#define K_OHCI_TD_SETUP 0 +#define K_OHCI_TD_OUT 1 +#define K_OHCI_TD_IN 2 +#define K_OHCI_TD_RESERVED 3 + +#define V_OHCI_TD_SETUP V_OHCI_TD_PID(K_OHCI_TD_SETUP) +#define V_OHCI_TD_OUT V_OHCI_TD_PID(K_OHCI_TD_OUT) +#define V_OHCI_TD_IN V_OHCI_TD_PID(K_OHCI_TD_IN) +#define V_OHCI_TD_RESERVED V_OHCI_TD_PID(K_OHCI_TD_RESERVED) + +#define S_OHCI_TD_DI 21 +#define M_OHCI_TD_DI _OHCI_MAKEMASK(3,S_OHCI_TD_DI) +#define V_OHCI_TD_DI(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_DI) +#define G_OHCI_TD_DI(x) _OHCI_GETVALUE(x,S_OHCI_TD_DI,M_OHCI_TD_DI) + +#define K_OHCI_TD_NOINTR 7 +#define V_OHCI_TD_NOINTR V_OHCI_TD_DI(K_OHCI_TD_NOINTR) + +#define S_OHCI_TD_DT 24 +#define M_OHCI_TD_DT _OHCI_MAKEMASK(2,S_OHCI_TD_DT) +#define V_OHCI_TD_DT(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_DT) +#define G_OHCI_TD_DT(x) _OHCI_GETVALUE(x,S_OHCI_TD_DT,M_OHCI_TD_DT) + +#define K_OHCI_TD_DT_DATA0 2 +#define K_OHCI_TD_DT_DATA1 3 +#define K_OHCI_TD_DT_TCARRY 0 + +#define S_OHCI_TD_EC 26 +#define M_OHCI_TD_EC _OHCI_MAKEMASK(2,S_OHCI_TD_EC) +#define V_OHCI_TD_EC(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_EC) +#define G_OHCI_TD_EC(x) _OHCI_GETVALUE(x,S_OHCI_TD_EC,M_OHCI_TD_EC) + +#define S_OHCI_TD_CC 28 +#define M_OHCI_TD_CC _OHCI_MAKEMASK(4,S_OHCI_TD_CC) +#define V_OHCI_TD_CC(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_CC) +#define G_OHCI_TD_CC(x) _OHCI_GETVALUE(x,S_OHCI_TD_CC,M_OHCI_TD_CC) + +#define K_OHCI_CC_NOERROR 0 +#define K_OHCI_CC_CRC 1 +#define K_OHCI_CC_BITSTUFFING 2 +#define K_OHCI_CC_DATATOGGLEMISMATCH 3 +#define K_OHCI_CC_STALL 4 +#define K_OHCI_CC_DEVICENOTRESPONDING 5 +#define K_OHCI_CC_PIDCHECKFAILURE 6 +#define K_OHCI_CC_UNEXPECTEDPID 7 +#define K_OHCI_CC_DATAOVERRUN 8 +#define K_OHCI_CC_DATAUNDERRUN 9 +#define K_OHCI_CC_BUFFEROVERRUN 12 +#define K_OHCI_CC_BUFFERUNDERRUN 13 +#define K_OHCI_CC_NOTACCESSED 15 + +#define K_OHCI_CC_CANCELLED 0xFF + +#define OHCI_TD_MAX_DATA 8192 + + +/* ********************************************************************* + * Endpoint descriptor (isochronous) + ********************************************************************* */ + +/* + * TBA + */ + +/* ********************************************************************* + * Host Controller Communications Area (HCCA) + ********************************************************************* */ + +#define OHCI_INTTABLE_SIZE 32 + +#define OHCI_HCCA_ALIGN 256 /* Align on 256-byte boundary */ + +typedef struct ohci_hcca_s { + uint32_t hcca_inttable[OHCI_INTTABLE_SIZE]; + uint32_t hcca_framenum; /* note: actually two 16-bit fields */ + uint32_t hcca_donehead; + uint32_t hcca_reserved[29]; /* round to 256 bytes */ + uint32_t hcca_pad; +} ohci_hcca_t; + +/* ********************************************************************* + * Registers + ********************************************************************* */ + +#define _OHCI_REGIDX(x) ((x)*4) + +#define R_OHCI_REVISION _OHCI_REGIDX(0) +#define R_OHCI_CONTROL _OHCI_REGIDX(1) +#define R_OHCI_CMDSTATUS _OHCI_REGIDX(2) +#define R_OHCI_INTSTATUS _OHCI_REGIDX(3) +#define R_OHCI_INTENABLE _OHCI_REGIDX(4) +#define R_OHCI_INTDISABLE _OHCI_REGIDX(5) +#define R_OHCI_HCCA _OHCI_REGIDX(6) +#define R_OHCI_PERIODCURRENTED _OHCI_REGIDX(7) +#define R_OHCI_CONTROLHEADED _OHCI_REGIDX(8) +#define R_OHCI_CONTROLCURRENTED _OHCI_REGIDX(9) +#define R_OHCI_BULKHEADED _OHCI_REGIDX(10) +#define R_OHCI_BULKCURRENTED _OHCI_REGIDX(11) +#define R_OHCI_DONEHEAD _OHCI_REGIDX(12) +#define R_OHCI_FMINTERVAL _OHCI_REGIDX(13) +#define R_OHCI_FMREMAINING _OHCI_REGIDX(14) +#define R_OHCI_FMNUMBER _OHCI_REGIDX(15) +#define R_OHCI_PERIODICSTART _OHCI_REGIDX(16) +#define R_OHCI_LSTHRESHOLD _OHCI_REGIDX(17) +#define R_OHCI_RHDSCRA _OHCI_REGIDX(18) +#define R_OHCI_RHDSCRB _OHCI_REGIDX(19) +#define R_OHCI_RHSTATUS _OHCI_REGIDX(20) +#define R_OHCI_RHPORTSTATUS(x) _OHCI_REGIDX(20+(x)) /* note: 1-based! */ + + +/* + * R_OHCI_REVISION + */ + +#define S_OHCI_REV_REV 0 +#define M_OHCI_REV_REV _OHCI_MAKEMASK(8,S_OHCI_REV_REV) +#define V_OHCI_REV_REV(x) _OHCI_MAKEVALUE(x,S_OHCI_REV_REV) +#define G_OHCI_REV_REV(x) _OHCI_GETVALUE(x,S_OHCI_REV_REV,M_OHCI_REV_REV) +#define K_OHCI_REV_11 0x10 + +/* + * R_OHCI_CONTROL + */ + +#define S_OHCI_CONTROL_CBSR 0 +#define M_OHCI_CONTROL_CBSR _OHCI_MAKEMASK(2,S_OHCI_CONTROL_CBSR) +#define V_OHCI_CONTROL_CBSR(x) _OHCI_MAKEVALUE(x,S_OHCI_CONTROL_CBSR) +#define G_OHCI_CONTROL_CBSR(x) _OHCI_GETVALUE(x,S_OHCI_CONTROL_CBSR,M_OHCI_CONTROL_CBSR) + +#define K_OHCI_CBSR_11 0 +#define K_OHCI_CBSR_21 1 +#define K_OHCI_CBSR_31 2 +#define K_OHCI_CBSR_41 3 + +#define M_OHCI_CONTROL_PLE _OHCI_MAKEMASK1(2) +#define M_OHCI_CONTROL_IE _OHCI_MAKEMASK1(3) +#define M_OHCI_CONTROL_CLE _OHCI_MAKEMASK1(4) +#define M_OHCI_CONTROL_BLE _OHCI_MAKEMASK1(5) + +#define S_OHCI_CONTROL_HCFS 6 +#define M_OHCI_CONTROL_HCFS _OHCI_MAKEMASK(2,S_OHCI_CONTROL_HCFS) +#define V_OHCI_CONTROL_HCFS(x) _OHCI_MAKEVALUE(x,S_OHCI_CONTROL_HCFS) +#define G_OHCI_CONTROL_HCFS(x) _OHCI_GETVALUE(x,S_OHCI_CONTROL_HCFS,M_OHCI_CONTROL_HCFS) + +#define K_OHCI_HCFS_RESET 0 +#define K_OHCI_HCFS_RESUME 1 +#define K_OHCI_HCFS_OPERATIONAL 2 +#define K_OHCI_HCFS_SUSPEND 3 + +#define M_OHCI_CONTROL_IR _OHCI_MAKEMASK1(8) +#define M_OHCI_CONTROL_RWC _OHCI_MAKEMASK1(9) +#define M_OHCI_CONTROL_RWE _OHCI_MAKEMASK1(10) + +/* + * R_OHCI_CMDSTATUS + */ + +#define M_OHCI_CMDSTATUS_HCR _OHCI_MAKEMASK1(0) +#define M_OHCI_CMDSTATUS_CLF _OHCI_MAKEMASK1(1) +#define M_OHCI_CMDSTATUS_BLF _OHCI_MAKEMASK1(2) +#define M_OHCI_CMDSTATUS_OCR _OHCI_MAKEMASK1(3) + +#define S_OHCI_CMDSTATUS_SOC 16 +#define M_OHCI_CMDSTATUS_SOC _OHCI_MAKEMASK(2,S_OHCI_CMDSTATUS_SOC) +#define V_OHCI_CMDSTATUS_SOC(x) _OHCI_MAKEVALUE(x,S_OHCI_CMDSTATUS_SOC) +#define G_OHCI_CMDSTATUS_SOC(x) _OHCI_GETVALUE(x,S_OHCI_CMDSTATUS_SOC,M_OHCI_CMDSTATUS_SOC) + +/* + * R_OHCI_INTSTATUS, R_OHCI_INTENABLE, R_OHCI_INTDISABLE + */ + + +#define M_OHCI_INT_SO _OHCI_MAKEMASK1(0) +#define M_OHCI_INT_WDH _OHCI_MAKEMASK1(1) +#define M_OHCI_INT_SF _OHCI_MAKEMASK1(2) +#define M_OHCI_INT_RD _OHCI_MAKEMASK1(3) +#define M_OHCI_INT_UE _OHCI_MAKEMASK1(4) +#define M_OHCI_INT_FNO _OHCI_MAKEMASK1(5) +#define M_OHCI_INT_RHSC _OHCI_MAKEMASK1(6) +#define M_OHCI_INT_OC _OHCI_MAKEMASK1(30) +#define M_OHCI_INT_MIE _OHCI_MAKEMASK1(31) + +#define M_OHCI_INT_ALL M_OHCI_INT_SO | M_OHCI_INT_WDH | M_OHCI_INT_SF | \ + M_OHCI_INT_RD | M_OHCI_INT_UE | M_OHCI_INT_FNO | \ + M_OHCI_INT_RHSC | M_OHCI_INT_OC | M_OHCI_INT_MIE + +/* + * R_OHCI_FMINTERVAL + */ + + +#define S_OHCI_FMINTERVAL_FI 0 +#define M_OHCI_FMINTERVAL_FI _OHCI_MAKEMASK(14,S_OHCI_FMINTERVAL_FI) +#define V_OHCI_FMINTERVAL_FI(x) _OHCI_MAKEVALUE(x,S_OHCI_FMINTERVAL_FI) +#define G_OHCI_FMINTERVAL_FI(x) _OHCI_GETVALUE(x,S_OHCI_FMINTERVAL_FI,M_OHCI_FMINTERVAL_FI) + +#define S_OHCI_FMINTERVAL_FSMPS 16 +#define M_OHCI_FMINTERVAL_FSMPS _OHCI_MAKEMASK(15,S_OHCI_FMINTERVAL_FSMPS) +#define V_OHCI_FMINTERVAL_FSMPS(x) _OHCI_MAKEVALUE(x,S_OHCI_FMINTERVAL_FSMPS) +#define G_OHCI_FMINTERVAL_FSMPS(x) _OHCI_GETVALUE(x,S_OHCI_FMINTERVAL_FSMPS,M_OHCI_FMINTERVAL_FSMPS) + +#define OHCI_CALC_FSMPS(x) ((((x)-210)*6/7)) + + +#define M_OHCI_FMINTERVAL_FIT _OHCI_MAKEMASK1(31) + +/* + * R_OHCI_FMREMAINING + */ + + +#define S_OHCI_FMREMAINING_FR 0 +#define M_OHCI_FMREMAINING_FR _OHCI_MAKEMASK(14,S_OHCI_FMREMAINING_FR) +#define V_OHCI_FMREMAINING_FR(x) _OHCI_MAKEVALUE(x,S_OHCI_FMREMAINING_FR) +#define G_OHCI_FMREMAINING_FR(x) _OHCI_GETVALUE(x,S_OHCI_FMREMAINING_FR,M_OHCI_FMREMAINING_FR) + +#define M_OHCI_FMREMAINING_FRT _OHCI_MAKEMASK1(31) + +/* + * R_OHCI_RHDSCRA + */ + + +#define S_OHCI_RHDSCRA_NDP 0 +#define M_OHCI_RHDSCRA_NDP _OHCI_MAKEMASK(8,S_OHCI_RHDSCRA_NDP) +#define V_OHCI_RHDSCRA_NDP(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRA_NDP) +#define G_OHCI_RHDSCRA_NDP(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRA_NDP,M_OHCI_RHDSCRA_NDP) + +#define M_OHCI_RHDSCRA_PSM _OHCI_MAKEMASK1(8) +#define M_OHCI_RHDSCRA_NPS _OHCI_MAKEMASK1(9) +#define M_OHCI_RHDSCRA_DT _OHCI_MAKEMASK1(10) +#define M_OHCI_RHDSCRA_OCPM _OHCI_MAKEMASK1(11) +#define M_OHCI_RHDSCRA_NOCP _OHCI_MAKEMASK1(12) + +#define S_OHCI_RHDSCRA_POTPGT 24 +#define M_OHCI_RHDSCRA_POTPGT _OHCI_MAKEMASK(8,S_OHCI_RHDSCRA_POTPGT) +#define V_OHCI_RHDSCRA_POTPGT(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRA_POTPGT) +#define G_OHCI_RHDSCRA_POTPGT(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRA_POTPGT,M_OHCI_RHDSCRA_POTPGT) + +/* + * R_OHCI_RHDSCRB + */ + +#define S_OHCI_RHDSCRB_DR 0 +#define M_OHCI_RHDSCRB_DR _OHCI_MAKEMASK(16,S_OHCI_RHDSCRB_DR) +#define V_OHCI_RHDSCRB_DR(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRB_DR) +#define G_OHCI_RHDSCRB_DR(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRB_DR,M_OHCI_RHDSCRB_DR) + +#define S_OHCI_RHDSCRB_PPCM 16 +#define M_OHCI_RHDSCRB_PPCM _OHCI_MAKEMASK(16,S_OHCI_RHDSCRB_PPCM) +#define V_OHCI_RHDSCRB_PPCM(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRB_PPCM) +#define G_OHCI_RHDSCRB_PPCM(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRB_PPCM,M_OHCI_RHDSCRB_PPCM) + +/* + * R_OHCI_RHSTATUS + */ + +#define M_OHCI_RHSTATUS_LPS _OHCI_MAKEMASK1(0) +#define M_OHCI_RHSTATUS_OCI _OHCI_MAKEMASK1(1) +#define M_OHCI_RHSTATUS_DRWE _OHCI_MAKEMASK1(15) +#define M_OHCI_RHSTATUS_LPSC _OHCI_MAKEMASK1(16) +#define M_OHCI_RHSTATUS_OCIC _OHCI_MAKEMASK1(17) +#define M_OHCI_RHSTATUS_CRWE _OHCI_MAKEMASK1(31) + +/* + * R_OHCI_RHPORTSTATUS + */ + +#define M_OHCI_RHPORTSTAT_CCS _OHCI_MAKEMASK1(0) +#define M_OHCI_RHPORTSTAT_PES _OHCI_MAKEMASK1(1) +#define M_OHCI_RHPORTSTAT_PSS _OHCI_MAKEMASK1(2) +#define M_OHCI_RHPORTSTAT_POCI _OHCI_MAKEMASK1(3) +#define M_OHCI_RHPORTSTAT_PRS _OHCI_MAKEMASK1(4) +#define M_OHCI_RHPORTSTAT_PPS _OHCI_MAKEMASK1(8) +#define M_OHCI_RHPORTSTAT_LSDA _OHCI_MAKEMASK1(9) +#define M_OHCI_RHPORTSTAT_CSC _OHCI_MAKEMASK1(16) +#define M_OHCI_RHPORTSTAT_PESC _OHCI_MAKEMASK1(17) +#define M_OHCI_RHPORTSTAT_PSSC _OHCI_MAKEMASK1(18) +#define M_OHCI_RHPORTSTAT_OCIC _OHCI_MAKEMASK1(19) +#define M_OHCI_RHPORTSTAT_PRSC _OHCI_MAKEMASK1(20) + +#define M_OHCI_RHPORTSTAT_ALLC (M_OHCI_RHPORTSTAT_CSC | \ + M_OHCI_RHPORTSTAT_PSSC | \ + M_OHCI_RHPORTSTAT_OCIC | \ + M_OHCI_RHPORTSTAT_PRSC) + +/* ********************************************************************* + * OHCI Structures + ********************************************************************* */ + +#define beginningof(ptr,type,field) ((type *) (((int) (ptr)) - ((int) ((type *) 0)->field))) + +#define OHCI_INTTREE_SIZE 63 + +#define OHCI_EDPOOL_SIZE 128 +#define OHCI_TDPOOL_SIZE 32 + +typedef struct ohci_endpoint_s { + struct ohci_endpoint_s *ep_next; + uint32_t ep_phys; + int ep_flags; + int ep_mps; + int ep_num; +} ohci_endpoint_t; + +typedef struct ohci_transfer_s { + void *t_ref; + int t_length; + struct ohci_transfer_s *t_next; +} ohci_transfer_t; + +typedef struct ohci_softc_s { + ohci_endpoint_t *ohci_edtable[OHCI_INTTREE_SIZE]; + ohci_endpoint_t *ohci_inttable[OHCI_INTTABLE_SIZE]; + ohci_endpoint_t *ohci_isoc_list; + ohci_endpoint_t *ohci_ctl_list; + ohci_endpoint_t *ohci_bulk_list; + ohci_hcca_t *ohci_hcca; + ohci_endpoint_t *ohci_endpoint_pool; + ohci_transfer_t *ohci_transfer_pool; + ohci_ed_t *ohci_hwedpool; + ohci_td_t *ohci_hwtdpool; + ohci_endpoint_t *ohci_endpoint_freelist; + ohci_transfer_t *ohci_transfer_freelist; +#ifdef _CFE_ + physaddr_t ohci_regs; +#else + volatile uint32_t *ohci_regs; +#endif + int ohci_ndp; + long ohci_addr; + uint32_t ohci_intdisable; + + int ohci_rh_newaddr; /* Address to be set on next status update */ + int ohci_rh_addr; /* address of root hub */ + int ohci_rh_conf; /* current configuration # */ + uint8_t ohci_rh_buf[128]; /* buffer to hold hub responses */ + uint8_t *ohci_rh_ptr; /* pointer into buffer */ + int ohci_rh_len; /* remaining bytes to transfer */ + queue_t ohci_rh_intrq; /* Interrupt request queue */ + usbbus_t *ohci_bus; /* owning usbbus structure */ + +} ohci_softc_t; + + +/* + * Misc stuff + */ +#define OHCI_RESET_DELAY 10 + + diff --git a/cfe/cfe/usb/usbchap9.h b/cfe/cfe/usb/usbchap9.h new file mode 100644 index 0000000..1afd0db --- /dev/null +++ b/cfe/cfe/usb/usbchap9.h @@ -0,0 +1,389 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Chapter 9 definitions File: usbchap9.h + * + * This module contains definitions from the USB specification, + * chapter 9. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#ifndef _USBCHAP9_H_ +#define _USBCHAP9_H_ + +#define MAXIMUM_USB_STRING_LENGTH 255 + +/* + * values for the bits returned by the USB GET_STATUS command + */ +#define USB_GETSTATUS_SELF_POWERED 0x01 +#define USB_GETSTATUS_REMOTE_WAKEUP_ENABLED 0x02 + + +#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 +#define USB_STRING_DESCRIPTOR_TYPE 0x03 +#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 +#define USB_POWER_DESCRIPTOR_TYPE 0x06 +#define USB_HID_DESCRIPTOR_TYPE 0x21 +#define USB_HUB_DESCRIPTOR_TYPE 0x29 + +#define USB_DESCRIPTOR_TYPEINDEX(d, i) ((uint16_t)((uint16_t)(d)<<8 | (i))) + +/* + * Values for bmAttributes field of an + * endpoint descriptor + */ + +#define USB_ENDPOINT_TYPE_MASK 0x03 + +#define USB_ENDPOINT_TYPE_CONTROL 0x00 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_TYPE_BULK 0x02 +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + + +/* + * definitions for bits in the bmAttributes field of a + * configuration descriptor. + */ +#define USB_CONFIG_POWERED_MASK 0xc0 + +#define USB_CONFIG_BUS_POWERED 0x80 +#define USB_CONFIG_SELF_POWERED 0x40 +#define USB_CONFIG_REMOTE_WAKEUP 0x20 + +/* + * Endpoint direction bit, stored in address + */ + +#define USB_ENDPOINT_DIRECTION_MASK 0x80 +#define USB_ENDPOINT_DIRECTION_IN 0x80 /* bit set means IN */ + +/* + * test direction bit in the bEndpointAddress field of + * an endpoint descriptor. + */ +#define USB_ENDPOINT_DIR_OUT(addr) (!((addr) & USB_ENDPOINT_DIRECTION_MASK)) +#define USB_ENDPOINT_DIR_IN(addr) ((addr) & USB_ENDPOINT_DIRECTION_MASK) + +#define USB_ENDPOINT_ADDRESS(addr) ((addr) & 0x0F) + +/* + * USB defined request codes + * see chapter 9 of the USB 1.0 specifcation for + * more information. + */ + +/* + * These are the correct values based on the USB 1.0 + * specification + */ + +#define USB_REQUEST_GET_STATUS 0x00 +#define USB_REQUEST_CLEAR_FEATURE 0x01 + +#define USB_REQUEST_SET_FEATURE 0x03 + +#define USB_REQUEST_SET_ADDRESS 0x05 +#define USB_REQUEST_GET_DESCRIPTOR 0x06 +#define USB_REQUEST_SET_DESCRIPTOR 0x07 +#define USB_REQUEST_GET_CONFIGURATION 0x08 +#define USB_REQUEST_SET_CONFIGURATION 0x09 +#define USB_REQUEST_GET_INTERFACE 0x0A +#define USB_REQUEST_SET_INTERFACE 0x0B +#define USB_REQUEST_SYNC_FRAME 0x0C + + +/* + * defined USB device classes + */ + + +#define USB_DEVICE_CLASS_RESERVED 0x00 +#define USB_DEVICE_CLASS_AUDIO 0x01 +#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 +#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 +#define USB_DEVICE_CLASS_MONITOR 0x04 +#define USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05 +#define USB_DEVICE_CLASS_POWER 0x06 +#define USB_DEVICE_CLASS_PRINTER 0x07 +#define USB_DEVICE_CLASS_STORAGE 0x08 +#define USB_DEVICE_CLASS_HUB 0x09 +#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF + +/* + * USB defined Feature selectors + */ + +#define USB_FEATURE_ENDPOINT_STALL 0x0000 +#define USB_FEATURE_REMOTE_WAKEUP 0x0001 +#define USB_FEATURE_POWER_D0 0x0002 +#define USB_FEATURE_POWER_D1 0x0003 +#define USB_FEATURE_POWER_D2 0x0004 +#define USB_FEATURE_POWER_D3 0x0005 + +/* + * USB Device descriptor. + * To reduce problems with compilers trying to optimize + * this structure, all the fields are bytes. + */ + +#define USBWORD(x) ((x) & 0xFF),(((x) >> 8) & 0xFF) + +#define USB_CONTROL_ENDPOINT_MIN_SIZE 8 + +typedef struct usb_device_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bcdUSBLow,bcdUSBHigh; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t idVendorLow,idVendorHigh; + uint8_t idProductLow,idProductHigh; + uint8_t bcdDeviceLow,bcdDeviceHigh; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} usb_device_descr_t; + +typedef struct usb_endpoint_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint8_t wMaxPacketSizeLow,wMaxPacketSizeHigh; + uint8_t bInterval; +} usb_endpoint_descr_t; + +/* + * values for bmAttributes Field in + * USB_CONFIGURATION_DESCRIPTOR + */ + +#define CONFIG_BUS_POWERED 0x80 +#define CONFIG_SELF_POWERED 0x40 +#define CONFIG_REMOTE_WAKEUP 0x20 + +typedef struct usb_config_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t wTotalLengthLow,wTotalLengthHigh; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t MaxPower; +} usb_config_descr_t; + +#define USB_INTERFACE_CLASS_HUB 0x09 + +typedef struct usb_interface_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_interface_descr_t; + +typedef struct usb_string_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bString[1]; +} usb_string_descr_t; + +/* + * USB power descriptor added to core specification + */ + +#define USB_SUPPORT_D0_COMMAND 0x01 +#define USB_SUPPORT_D1_COMMAND 0x02 +#define USB_SUPPORT_D2_COMMAND 0x04 +#define USB_SUPPORT_D3_COMMAND 0x08 + +#define USB_SUPPORT_D1_WAKEUP 0x10 +#define USB_SUPPORT_D2_WAKEUP 0x20 + + +typedef struct usb_power_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bCapabilitiesFlags; + uint16_t EventNotification; + uint16_t D1LatencyTime; + uint16_t D2LatencyTime; + uint16_t D3LatencyTime; + uint8_t PowerUnit; + uint16_t D0PowerConsumption; + uint16_t D1PowerConsumption; + uint16_t D2PowerConsumption; +} usb_power_descr_t; + + +typedef struct usb_common_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; +} usb_common_descr_t; + +typedef struct usb_device_status_s { + uint8_t wDeviceStatusLow,wDeviceStatusHigh; +} usb_device_status_t; + + +/* + * Standard USB HUB definitions + * + * See Chapter 11 + */ + +#define USB_HUB_DESCR_SIZE 8 +typedef struct usb_hub_descr_s { + uint8_t bDescriptorLength; /* Length of this descriptor */ + uint8_t bDescriptorType; /* Hub configuration type */ + uint8_t bNumberOfPorts; /* number of ports on this hub */ + uint8_t wHubCharacteristicsLow; /* Hub Charateristics */ + uint8_t wHubCharacteristicsHigh; + uint8_t bPowerOnToPowerGood; /* port power on till power good in 2ms */ + uint8_t bHubControlCurrent; /* max current in mA */ + /* room for 255 ports power control and removable bitmask */ + uint8_t bRemoveAndPowerMask[64]; +} usb_hub_descr_t; + +#define USB_HUBCHAR_PWR_GANGED 0 +#define USB_HUBCHAR_PWR_IND 1 +#define USB_HUBCHAR_PWR_NONE 2 + +typedef struct usb_hub_status_s { + uint8_t wHubStatusLow,wHubStatusHigh; + uint8_t wHubChangeLow,wHubChangeHigh; +} usb_hub_status_t; + +#define USB_PORT_STATUS_CONNECT 0x0001 +#define USB_PORT_STATUS_ENABLED 0x0002 +#define USB_PORT_STATUS_SUSPEND 0x0004 +#define USB_PORT_STATUS_OVERCUR 0x0008 +#define USB_PORT_STATUS_RESET 0x0010 +#define USB_PORT_STATUS_POWER 0x0100 +#define USB_PORT_STATUS_LOWSPD 0x0200 + +typedef struct usb_port_status_s { + uint8_t wPortStatusLow,wPortStatusHigh; + uint8_t wPortChangeLow,wPortChangeHigh; +} usb_port_status_t; + + +#define USB_HUBREQ_GET_STATUS 0 +#define USB_HUBREQ_CLEAR_FEATURE 1 +#define USB_HUBREQ_GET_STATE 2 +#define USB_HUBREQ_SET_FEATURE 3 +#define USB_HUBREQ_GET_DESCRIPTOR 6 +#define USB_HUBREQ_SET_DESCRIPTOR 7 + +#define USB_HUB_FEATURE_C_LOCAL_POWER 0 +#define USB_HUB_FEATURE_C_OVER_CURRENT 1 + +#define USB_PORT_FEATURE_CONNECTION 0 +#define USB_PORT_FEATURE_ENABLE 1 +#define USB_PORT_FEATURE_SUSPEND 2 +#define USB_PORT_FEATURE_OVER_CURRENT 3 +#define USB_PORT_FEATURE_RESET 4 +#define USB_PORT_FEATURE_POWER 8 +#define USB_PORT_FEATURE_LOW_SPEED 9 +#define USB_PORT_FEATURE_C_PORT_CONNECTION 16 +#define USB_PORT_FEATURE_C_PORT_ENABLE 17 +#define USB_PORT_FEATURE_C_PORT_SUSPEND 18 +#define USB_PORT_FEATURE_C_PORT_OVER_CURRENT 19 +#define USB_PORT_FEATURE_C_PORT_RESET 20 + + +#define GETUSBFIELD(s,f) (((s)->f##Low) | ((s)->f##High << 8)) +#define PUTUSBFIELD(s,f,v) (s)->f##Low = (v & 0xFF); \ + (s)->f##High = ((v)>>8 & 0xFF) + +typedef struct usb_device_request_s { + uint8_t bmRequestType; + uint8_t bRequest; + uint8_t wValueLow,wValueHigh; + uint8_t wIndexLow,wIndexHigh; + uint8_t wLengthLow,wLengthHigh; +} usb_device_request_t; + +/* + * Values for the bmAttributes field of a request + */ +#define USBREQ_DIR_IN 0x80 +#define USBREQ_DIR_OUT 0x00 +#define USBREQ_TYPE_STD 0x00 +#define USBREQ_TYPE_CLASS 0x20 +#define USBREQ_TYPE_VENDOR 0x40 +#define USBREQ_TYPE_RSVD 0x60 +#define USBREQ_REC_DEVICE 0x00 +#define USBREQ_REC_INTERFACE 0x01 +#define USBREQ_REC_ENDPOINT 0x02 +#define USBREQ_REC_OTHER 0x03 + +#define REQCODE(req,dir,type,rec) (((req) << 8) | (dir) | (type) | (rec)) +#define REQSW(req,attr) (((req) << 8) | (attr)) + +/* ********************************************************************* + * HID stuff + ********************************************************************* */ + +typedef struct usb_hid_descr_s { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bcdHIDLow,bcdHIDHigh; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bClassDescrType; + uint8_t wClassDescrLengthLow,wClassDescrLengthHigh; +} usb_hid_descr_t; + +#endif /* _USBCHAP9_H_ */ diff --git a/cfe/cfe/usb/usbd.c b/cfe/cfe/usb/usbd.c new file mode 100644 index 0000000..3e77049 --- /dev/null +++ b/cfe/cfe/usb/usbd.c @@ -0,0 +1,1215 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB device layer File: usbd.c + * + * This module deals with devices (things connected to USB buses) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_ +#include +#include +#include +#include +#include "usbhack.h" +#else +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "cfe_timer.h" +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +int usb_noisy = 0; + + +/* ********************************************************************* + * usb_create_pipe(dev,epaddr,mps,flags) + * + * Create a pipe, causing the corresponding endpoint to + * be created in the host controller driver. Pipes form the + * basic "handle" for unidirectional communications with a + * USB device. + * + * Input parameters: + * dev - device we're talking about + * epaddr - endpoint address open, usually from the endpoint + * descriptor + * mps - maximum packet size understood by the device + * flags - flags for this pipe (UP_xxx flags) + * + * Return value: + * <0 if error + * 0 if ok + ********************************************************************* */ + +int usb_create_pipe(usbdev_t *dev,int epaddr,int mps,int flags) +{ + usbpipe_t *pipe; + int pipeidx; + + pipeidx = USB_EPADDR_TO_IDX(epaddr); + + if (dev->ud_pipes[pipeidx] != NULL) { + printf("Trying to create a pipe that was already created!\n"); + return 0; + } + + pipe = KMALLOC(sizeof(usbpipe_t),0); + + if (!pipe) return -1; + + pipe->up_flags = flags; + pipe->up_num = pipeidx; + pipe->up_mps = mps; + pipe->up_dev = dev; + if (dev->ud_flags & UD_FLAG_LOWSPEED) flags |= UP_TYPE_LOWSPEED; + pipe->up_hwendpoint = UBEPTCREATE(dev->ud_bus, + dev->ud_address, + USB_ENDPOINT_ADDRESS(epaddr), + mps, + flags); + + dev->ud_pipes[pipeidx] = pipe; + + return 0; +} + +/* ********************************************************************* + * usb_open_pipe(dev,epdesc) + * + * Open a pipe given an endpoint descriptor - this is the + * normal way pipes get open, since you've just selected a + * configuration and have the descriptors handy with all + * the information you need. + * + * Input parameters: + * dev - device we're talking to + * epdesc - endpoint descriptor + * + * Return value: + * <0 if error + * else endpoint/pipe number (from descriptor) + ********************************************************************* */ + +int usb_open_pipe(usbdev_t *dev,usb_endpoint_descr_t *epdesc) +{ + int res; + int flags = 0; + + if (USB_ENDPOINT_DIR_IN(epdesc->bEndpointAddress)) flags |= UP_TYPE_IN; + else flags |= UP_TYPE_OUT; + + switch (epdesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) { + case USB_ENDPOINT_TYPE_CONTROL: + flags |= UP_TYPE_CONTROL; + break; + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + flags |= UP_TYPE_ISOC; + break; + case USB_ENDPOINT_TYPE_BULK: + flags |= UP_TYPE_BULK; + break; + case USB_ENDPOINT_TYPE_INTERRUPT: + flags |= UP_TYPE_INTR; + break; + } + + res = usb_create_pipe(dev, + epdesc->bEndpointAddress, + GETUSBFIELD(epdesc,wMaxPacketSize), + flags); + + if (res < 0) return res; + + return epdesc->bEndpointAddress; +} + + +/* ********************************************************************* + * usb_destroy_pipe(dev,epaddr) + * + * Close(destroy) an open pipe and remove endpoint descriptor + * + * Input parameters: + * dev - device we're talking to + * epaddr - pipe to close + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_destroy_pipe(usbdev_t *dev,int epaddr) +{ + usbpipe_t *pipe; + int pipeidx; + + pipeidx = USB_EPADDR_TO_IDX(epaddr); + + pipe = dev->ud_pipes[pipeidx]; + if (!pipe) return; + + if (dev->ud_pipes[pipeidx]) { + UBEPTDELETE(dev->ud_bus, + dev->ud_pipes[pipeidx]->up_hwendpoint); + } + + KFREE(dev->ud_pipes[pipeidx]); + dev->ud_pipes[pipeidx] = NULL; +} + +/* ********************************************************************* + * usb_destroy_device(dev) + * + * Delete an entire USB device, closing its pipes and freeing + * the device data structure + * + * Input parameters: + * dev - device to destroy + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_destroy_device(usbdev_t *dev) +{ + int idx; + + for (idx = 0; idx < UD_MAX_PIPES; idx++) { + if (dev->ud_pipes[idx]) { + UBEPTDELETE(dev->ud_bus, + dev->ud_pipes[idx]->up_hwendpoint); + KFREE(dev->ud_pipes[idx]); + } + } + + dev->ud_bus->ub_devices[dev->ud_address] = NULL; + + KFREE(dev); +} + + +/* ********************************************************************* + * usb_create_device(bus,lowspeed) + * + * Create a new USB device. This device will be set to + * communicate on address zero (default address) and will be + * ready for basic stuff so we can figure out what it is. + * The control pipe will be open, so you can start requesting + * descriptors right away. + * + * Input parameters: + * bus - bus to create device on + * lowspeed - true if it's a lowspeed device (the hubs tell + * us these things) + * + * Return value: + * usb device structure, or NULL + ********************************************************************* */ + +usbdev_t *usb_create_device(usbbus_t *bus,int lowspeed) +{ + usbdev_t *dev; + int pipeflags; + + /* + * Create the device structure. + */ + + dev = KMALLOC(sizeof(usbdev_t),0); + memset(dev,0,sizeof(usbdev_t)); + + dev->ud_bus = bus; + dev->ud_address = 0; /* default address */ + dev->ud_parent = NULL; + dev->ud_flags = 0; + + /* + * Adjust things based on the target device speed + */ + + pipeflags = UP_TYPE_CONTROL; + if (lowspeed) { + pipeflags |= UP_TYPE_LOWSPEED; + dev->ud_flags |= UD_FLAG_LOWSPEED; + } + + /* + * Create the control pipe. + */ + + usb_create_pipe(dev,0, + USB_CONTROL_ENDPOINT_MIN_SIZE, + pipeflags); + + return dev; +} + +/* ********************************************************************* + * usb_make_request(dev,epaddr,buf,len,flags) + * + * Create a template request structure with basic fields + * ready to go. A shorthand routine. + * + * Input parameters: + * dev- device we're talking to + * epaddr - endpoint address, from usb_open_pipe() + * buf,length - user buffer and buffer length + * flags - transfer direction, etc. (UR_xxx flags) + * + * Return value: + * usbreq_t pointer, or NULL + ********************************************************************* */ + +usbreq_t *usb_make_request(usbdev_t *dev,int epaddr,uint8_t *buf,int length,int flags) +{ + usbreq_t *ur; + usbpipe_t *pipe; + int pipeidx; + + pipeidx = USB_EPADDR_TO_IDX(epaddr); + + pipe = dev->ud_pipes[pipeidx]; + + if (pipe == NULL) return NULL; + + ur = KMALLOC(sizeof(usbreq_t),0); + memset(ur,0,sizeof(usbreq_t)); + + ur->ur_dev = dev; + ur->ur_pipe = pipe; + ur->ur_buffer = buf; + ur->ur_length = length; + ur->ur_flags = flags; + ur->ur_callback = NULL; + + return ur; + +} + +/* ********************************************************************* + * usb_poll(bus) + * + * Handle device-driver polling - simply vectors to host controller + * driver. + * + * Input parameters: + * bus - bus structure + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_poll(usbbus_t *bus) +{ + UBINTR(bus); +} + +/* ********************************************************************* + * usb_daemon(bus) + * + * Polls for topology changes and initiates a bus scan if + * necessary. + * + * Input parameters: + * bus - bus to watch + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_daemon(usbbus_t *bus) +{ + /* + * Just see if someone flagged a need for a scan here + * and start the bus scan if necessary. + * + * The actual scanning is a hub function, starting at the + * root hub, so the code for that is over there. + */ + + if (bus->ub_flags & UB_FLG_NEEDSCAN) { + bus->ub_flags &= ~UB_FLG_NEEDSCAN; + usb_scan(bus); + } +} + +/* ********************************************************************* + * usb_cancel_request(ur) + * + * Cancel a pending usb transfer request. + * + * Input parameters: + * ur - request to cancel + * + * Return value: + * 0 if ok + * else error (could not find request) + ********************************************************************* */ + +int usb_cancel_request(usbreq_t *ur) +{ + printf("usb_cancel_request is not implemented.\n"); + return 0; +} + +/* ********************************************************************* + * usb_free_request(ur) + * + * Return a transfer request to the free pool. + * + * Input parameters: + * ur - request to return + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_free_request(usbreq_t *ur) +{ + if (ur->ur_inprogress) { + printf("Yow! Tried to free a request that was in progress!\n"); + return; + } + KFREE(ur); +} + +/* ********************************************************************* + * usb_delay_ms(bus,ms) + * + * Wait a while, calling the polling routine as we go. + * + * Input parameters: + * bus - bus we're talking to + * ms - how long to wait + * + * Return value: + * nothing + ********************************************************************* */ + + +void usb_delay_ms(usbbus_t *bus,int ms) +{ +#ifdef _CFE_ + cfe_sleep(1+((ms*CFE_HZ)/1000)); +#else + mydelay(ms); +#endif +} + +/* ********************************************************************* + * usb_queue_request(ur) + * + * Call the transfer handler in the host controller driver to + * set up a transfer descriptor + * + * Input parameters: + * ur - request to queue + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +int usb_queue_request(usbreq_t *ur) +{ + int res; + + ur->ur_inprogress = 1; + ur->ur_xferred = 0; + res = UBXFER(ur->ur_dev->ud_bus, + ur->ur_pipe->up_hwendpoint, + ur); + return res; +} + +/* ********************************************************************* + * usb_wait_request(ur) + * + * Wait until a request completes, calling the polling routine + * as we wait. + * + * Input parameters: + * ur - request to wait for + * + * Return value: + * request status + ********************************************************************* */ + +int usb_wait_request(usbreq_t *ur) +{ + while ((volatile int) (ur->ur_inprogress)) { + usb_poll(ur->ur_dev->ud_bus); + } + + return ur->ur_status; +} + +/* ********************************************************************* + * usb_sync_request(ur) + * + * Synchronous request - call usb_queue and then usb_wait + * + * Input parameters: + * ur - request to submit + * + * Return value: + * status of request + ********************************************************************* */ + +int usb_sync_request(usbreq_t *ur) +{ + usb_queue_request(ur); + return usb_wait_request(ur); +} + +/* ********************************************************************* + * usb_simple_request(dev,reqtype,bRequest,wValue,wIndex) + * + * Handle a simple USB control pipe request. These are OUT + * requests with no data phase. + * + * Input parameters: + * dev - device we're talking to + * reqtype - request type (bmRequestType) for descriptor + * wValue - wValue for descriptor + * wIndex - wIndex for descriptor + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +int usb_simple_request(usbdev_t *dev,uint8_t reqtype,int bRequest,int wValue,int wIndex) +{ +#if 0 + uint8_t *requestbuf; + usb_device_request_t *req; + usbreq_t *ur; + int res; + + requestbuf = KMALLOC(32,0); + + req = (usb_device_request_t *) requestbuf; + + req->bmRequestType = reqtype; + req->bRequest = bRequest; + PUTUSBFIELD(req,wValue,wValue); + PUTUSBFIELD(req,wIndex,wIndex); + PUTUSBFIELD(req,wLength,0); + + if (usb_noisy > 1) printf("Request: "); + ur = usb_make_request(dev,0,requestbuf,sizeof(usb_device_request_t),UR_FLAG_SETUP); + res = usb_sync_request(ur); + usb_free_request(ur); + + if (res == 4) { /* STALL on control pipe */ + if (usb_noisy > 1) printf("STALL\n"); + usb_clear_stall(dev,dev->ud_pipes[0]->up_num); + return -1; + } + + res = ur->ur_xferred; + if (usb_noisy > 1) printf("Result %d\n",res); + + if (usb_noisy > 1) printf("Status: "); + ur = usb_make_request(dev,0,requestbuf,0,UR_FLAG_STATUS_IN); + res = usb_sync_request(ur); + usb_free_request(ur); + if (usb_noisy > 1) printf("Result %d\n",res); + + if (res == 4) { /* STALL */ + if (usb_noisy > 1) printf("STALL\n"); + usb_clear_stall(dev,dev->ud_pipes[0]->up_num); + return -1; + } + + KFREE(requestbuf); + + return 0; +#else + return usb_std_request(dev,reqtype,bRequest,wValue,wIndex,NULL,0); +#endif + +} + + +/* ********************************************************************* + * usb_set_configuration(dev,config) + * + * Set the current configuration for a USB device. + * + * Input parameters: + * dev - device we're talking to + * config - bConfigValue for the device + * + * Return value: + * request status + ********************************************************************* */ + +int usb_set_configuration(usbdev_t *dev,int config) +{ + int res; + + res = usb_simple_request(dev,0x00,USB_REQUEST_SET_CONFIGURATION,config,0); + + return res; +} + + +/* ********************************************************************* + * usb_new_address(bus) + * + * Return the next available address for the specified bus + * + * Input parameters: + * bus - bus to assign an address for + * + * Return value: + * new address, <0 if error + ********************************************************************* */ + +int usb_new_address(usbbus_t *bus) +{ + int idx; + + for (idx = 1; idx < USB_MAX_DEVICES; idx++) { + if (bus->ub_devices[idx] == NULL) return idx; + } + + return -1; +} + +/* ********************************************************************* + * usb_set_address(dev,address) + * + * Set the address of a device. This also puts the device + * in the master device table for the bus and reconfigures the + * address of the control pipe. + * + * Input parameters: + * dev - device we're talking to + * address - new address (1..127) + * + * Return value: + * request status + ********************************************************************* */ + +int usb_set_address(usbdev_t *dev,int address) +{ + int res; + int idx; + usbpipe_t *pipe; + + res = usb_simple_request(dev,0x00,USB_REQUEST_SET_ADDRESS,address,0); + + if (res == 0) { + dev->ud_bus->ub_devices[address] = dev; + dev->ud_address = address; + for (idx = 0; idx < UD_MAX_PIPES; idx++) { + pipe = dev->ud_pipes[idx]; + if (pipe && pipe->up_hwendpoint) { + UBEPTSETADDR(dev->ud_bus,pipe->up_hwendpoint,address); + } + } + } + + return res; +} + +/* ********************************************************************* + * usb_set_ep0mps(dev,mps) + * + * Set the maximum packet size of endpoint zero (mucks with the + * endpoint in the host controller) + * + * Input parameters: + * dev - device we're talking to + * mps - max packet size for endpoint zero + * + * Return value: + * request status + ********************************************************************* */ + +int usb_set_ep0mps(usbdev_t *dev,int mps) +{ + usbpipe_t *pipe; + + pipe = dev->ud_pipes[0]; + if (pipe && pipe->up_hwendpoint) { + UBEPTSETMPS(dev->ud_bus,pipe->up_hwendpoint,mps); + } + if (pipe) { + pipe->up_mps = mps; + } + + return 0; +} + +/* ********************************************************************* + * usb_clear_stall(dev,epaddr) + * + * Clear a stall condition on the specified pipe + * + * Input parameters: + * dev - device we're talking to + * epaddr - endpoint address + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ +int usb_clear_stall(usbdev_t *dev,int epaddr) +{ + uint8_t *requestbuf; + usb_device_request_t *req; + usbreq_t *ur; + int res; + int pipeidx; + + /* + * Clear the stall in the hardware. + */ + + pipeidx = USB_EPADDR_TO_IDX(epaddr); + + UBEPTCLEARTOGGLE(dev->ud_bus,dev->ud_pipes[pipeidx]->up_hwendpoint); + + /* + * Do the "clear stall" request. Note that we should do this + * without calling usb_simple_request, since usb_simple_request + * may itself stall. + */ + + requestbuf = KMALLOC(32,0); + + req = (usb_device_request_t *) requestbuf; + + req->bmRequestType = 0x02; + req->bRequest = USB_REQUEST_CLEAR_FEATURE; + PUTUSBFIELD(req,wValue,0); /* ENDPOINT_HALT */ + PUTUSBFIELD(req,wIndex,epaddr); + PUTUSBFIELD(req,wLength,0); + + ur = usb_make_request(dev,0,requestbuf, + sizeof(usb_device_request_t), + UR_FLAG_SETUP); + res = usb_sync_request(ur); + usb_free_request(ur); + ur = usb_make_request(dev,0,requestbuf,0,UR_FLAG_STATUS_IN); + res = usb_sync_request(ur); + usb_free_request(ur); + + KFREE(requestbuf); + + return 0; +} + + + +/* ********************************************************************* + * usb_std_request(dev,bmRequestType,bRequest,wValue, + * wIndex,buffer,length) + * + * Do a standard control request on the control pipe, + * with the appropriate setup, data, and status phases. + * + * Input parameters: + * dev - dev we're talking to + * bmRequestType,bRequest,wValue,wIndex - fields for the + * USB request structure + * buffer - user buffer + * length - length of user buffer + * + * Return value: + * number of bytes transferred + ********************************************************************* */ + +int usb_std_request(usbdev_t *dev,uint8_t bmRequestType, + uint8_t bRequest,uint16_t wValue, + uint16_t wIndex,uint8_t *buffer,int length) +{ + usbpipe_t *pipe = dev->ud_pipes[0]; + usbreq_t *ur; + int res; + usb_device_request_t *req; + uint8_t *databuf = NULL; + + req = KMALLOC(32,0); + + if ((buffer != NULL) && (length !=0)) { + databuf = KMALLOC(length,0); + if (!(bmRequestType & USBREQ_DIR_IN)) { + memcpy(databuf,buffer,length); + } + else { + memset(databuf,0,length); + } + } + + req->bmRequestType = bmRequestType; + req->bRequest = bRequest; + PUTUSBFIELD(req,wValue,wValue); + PUTUSBFIELD(req,wIndex,wIndex); + PUTUSBFIELD(req,wLength,length); + + ur = usb_make_request(dev,0,(uint8_t *)req,sizeof(usb_device_request_t),UR_FLAG_SETUP); + res = usb_sync_request(ur); + usb_free_request(ur); + + if (length != 0) { + if (bmRequestType & USBREQ_DIR_IN) { + ur = usb_make_request(dev,0,databuf,length,UR_FLAG_IN); + } + else { + ur = usb_make_request(dev,0,databuf,length,UR_FLAG_OUT); + } + + res = usb_sync_request(ur); + + if (res == 4) { /* STALL */ + usb_clear_stall(dev,pipe->up_num); + usb_free_request(ur); + if (databuf) KFREE(databuf); + KFREE(req); + return 0; + } + + length = ur->ur_xferred; + usb_free_request(ur); + } + + if ((length != 0) && (databuf != NULL) && (bmRequestType & USBREQ_DIR_IN)) { + memcpy(buffer,databuf,length); + } + + if (bmRequestType & USBREQ_DIR_IN) { + ur = usb_make_request(dev,0,(uint8_t *)req,0,UR_FLAG_STATUS_OUT); + } + else { + ur = usb_make_request(dev,0,(uint8_t *)req,0,UR_FLAG_STATUS_IN); + } + + res = usb_sync_request(ur); + usb_free_request(ur); + + if (res == 4) { /* STALL */ + usb_clear_stall(dev,pipe->up_num); + if (databuf) KFREE(databuf); + KFREE(req); + return 0; + } + + if (databuf) KFREE(databuf); + KFREE(req); + + return length; +} + + + + +/* ********************************************************************* + * usb_get_descriptor(dev,reqtype,dsctype,dscidx,respbuf,buflen) + * + * Request a descriptor from the device. + * + * Input parameters: + * dev - device we're talking to + * reqtype - bmRequestType field for descriptor we want + * dsctype - descriptor type we want + * dscidx - index of descriptor we want (often zero) + * respbuf - response buffer + * buflen - length of response buffer + * + * Return value: + * number of bytes transferred + ********************************************************************* */ + +int usb_get_descriptor(usbdev_t *dev,uint8_t reqtype,int dsctype,int dscidx, + uint8_t *respbuf,int buflen) +{ + return usb_std_request(dev, + reqtype,USB_REQUEST_GET_DESCRIPTOR, + USB_DESCRIPTOR_TYPEINDEX(dsctype,dscidx), + 0, + respbuf,buflen); +} + +/* ********************************************************************* + * usb_get_string(dev,id,buf,maxlen) + * + * Request a string from the device, converting it from + * unicode to ascii (brutally). + * + * Input parameters: + * dev - device we're talking to + * id - string ID + * buf - buffer to receive string (null terminated) + * maxlen - length of buffer + * + * Return value: + * number of characters in returned string + ********************************************************************* */ + +int usb_get_string(usbdev_t *dev,int id,char *buf,int maxlen) +{ + int amtcopy; + uint8_t *respbuf; + int idx; + usb_string_descr_t *sdscr; + + respbuf = KMALLOC(maxlen*2+2,0); + sdscr = (usb_string_descr_t *) respbuf; + + /* + * First time just get the header of the descriptor so we can + * get the string length + */ + + amtcopy = usb_get_descriptor(dev,USBREQ_DIR_IN,USB_STRING_DESCRIPTOR_TYPE,id, + respbuf,2); + + /* + * now do it again to get the whole string. + */ + + if (maxlen > sdscr->bLength) maxlen = sdscr->bLength; + + amtcopy = usb_get_descriptor(dev,USBREQ_DIR_IN,USB_STRING_DESCRIPTOR_TYPE,id, + respbuf,maxlen); + + *buf = '\0'; + amtcopy = sdscr->bLength - 2; + if (amtcopy <= 0) return amtcopy; + + for (idx = 0; idx < amtcopy; idx+=2) { + *buf++ = sdscr->bString[idx]; + } + + *buf = '\0'; + + KFREE(respbuf); + + return amtcopy; +} + + + +/* ********************************************************************* + * usb_get_device_descriptor(dev,dscr,smallflg) + * + * Request the device descriptor for the device. This is often + * the first descriptor requested, so it needs to be done in + * stages so we can find out how big the control pipe is. + * + * Input parameters: + * dev - device we're talking to + * dscr - pointer to buffer to receive descriptor + * smallflg - TRUE to request just 8 bytes. + * + * Return value: + * number of bytes copied + ********************************************************************* */ + +int usb_get_device_descriptor(usbdev_t *dev,usb_device_descr_t *dscr,int smallflg) +{ + int res; + uint8_t *respbuf; + int amtcopy; + + /* + * Smallflg truncates the request 8 bytes. We need to do this for + * the very first transaction to a USB device in order to determine + * the size of its control pipe. Bad things will happen if you + * try to retrieve more data than the control pipe will hold. + * + * So, be conservative at first and get the first 8 bytes of the + * descriptor. Byte 7 is bMaxPacketSize0, the size of the control + * pipe. Then you can go back and submit a bigger request for + * everything else. + */ + + amtcopy = smallflg ? USB_CONTROL_ENDPOINT_MIN_SIZE : sizeof(usb_device_descr_t); + + respbuf = KMALLOC(64,0); + res = usb_get_descriptor(dev,USBREQ_DIR_IN,USB_DEVICE_DESCRIPTOR_TYPE,0,respbuf,amtcopy); + memcpy(dscr,respbuf,amtcopy); + KFREE(respbuf); + return res; + +} + +/* ********************************************************************* + * usb_get_config_descriptor(dev,dscr,idx,maxlen) + * + * Request the configuration descriptor from the device. + * + * Input parameters: + * dev - device we're talking to + * dscr - descriptor buffer (receives data from device) + * idx - index of config we want (usually zero) + * maxlen - total size of buffer to receive descriptor + * + * Return value: + * number of bytes copied + ********************************************************************* */ + +int usb_get_config_descriptor(usbdev_t *dev,usb_config_descr_t *dscr,int idx,int maxlen) +{ + int res; + uint8_t *respbuf; + + respbuf = KMALLOC(maxlen,0); + res = usb_get_descriptor(dev,USBREQ_DIR_IN, + USB_CONFIGURATION_DESCRIPTOR_TYPE,idx, + respbuf,maxlen); + memcpy(dscr,respbuf,maxlen); + KFREE(respbuf); + return res; + +} + + + +/* ********************************************************************* + * usb_get_device_status(dev,status) + * + * Request status from the device (status descriptor) + * + * Input parameters: + * dev - device we're talking to + * status - receives device_status structure + * + * Return value: + * number of bytes returned + ********************************************************************* */ + +int usb_get_device_status(usbdev_t *dev,usb_device_status_t *status) +{ + return usb_std_request(dev, + USBREQ_DIR_IN, + 0, + 0, + 0, + (uint8_t *) status, + sizeof(usb_device_status_t)); +} + + +/* ********************************************************************* + * usb_complete_request(ur,status) + * + * Called when a usb request completes - pass status to + * caller and call the callback if there is one. + * + * Input parameters: + * ur - usbreq_t to complete + * status - completion status + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_complete_request(usbreq_t *ur,int status) +{ + ur->ur_status = status; + ur->ur_inprogress = 0; + if (ur->ur_callback) (*(ur->ur_callback))(ur); +} + + +/* ********************************************************************* + * usb_initroot(bus) + * + * Initialize the root hub for the bus - we need to do this + * each time a bus is configured. + * + * Input parameters: + * bus - bus to initialize + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_initroot(usbbus_t *bus) +{ + usbdev_t *dev; + usb_driver_t *drv; + int addr; + int res; + uint8_t *buf; + int len; + usb_config_descr_t cfgdescr; + + /* + * Create a device for the root hub. + */ + + dev = usb_create_device(bus,0); + bus->ub_roothub = dev; + + /* + * Get the device descriptor. Make sure it's a hub. + */ + + res = usb_get_device_descriptor(dev,&(dev->ud_devdescr),TRUE); + + if (dev->ud_devdescr.bDeviceClass != USB_DEVICE_CLASS_HUB) { + printf("Error! Root device is not a hub!\n"); + return; + } + + /* + * Set up the max packet size for the control endpoint, + * then get the rest of the descriptor. + */ + + usb_set_ep0mps(dev,dev->ud_devdescr.bMaxPacketSize0); + res = usb_get_device_descriptor(dev,&(dev->ud_devdescr),FALSE); + + /* + * Obtain a new address and set the address of the + * root hub to this address. + */ + + addr = usb_new_address(dev->ud_bus); + res = usb_set_address(dev,addr); + + /* + * Get the configuration descriptor and all the + * associated interface and endpoint descriptors. + */ + + res = usb_get_config_descriptor(dev,&cfgdescr,0, + sizeof(usb_config_descr_t)); + if (res != sizeof(usb_config_descr_t)) { + printf("[a]usb_get_config_descriptor returns %d\n",res); + } + + len = GETUSBFIELD(&cfgdescr,wTotalLength); + buf = KMALLOC(len,0); + + res = usb_get_config_descriptor(dev,(usb_config_descr_t *)buf,0,len); + if (res != len) { + printf("[b]usb_get_config_descriptor returns %d\n",res); + } + + dev->ud_cfgdescr = (usb_config_descr_t *) buf; + + /* + * Select the configuration. Not really needed for our poor + * imitation root hub, but it's the right thing to do. + */ + + usb_set_configuration(dev,cfgdescr.bConfigurationValue); + + /* + * Find the driver for this. It had better be the hub + * driver. + */ + + drv = usb_find_driver(dev); + + /* + * Call the attach method. + */ + + (*(drv->udrv_attach))(dev,drv); + + /* + * Hub should now be operational. + */ + +} + + +/* ********************************************************************* + * usb_find_cfg_descr(dev,dtype,idx) + * + * Find a configuration descriptor - we retrieved all the config + * descriptors during discovery, this lets us dig out the one + * we want. + * + * Input parameters: + * dev - device we are talking to + * dtype - descriptor type to find + * idx - index of descriptor if there's more than one + * + * Return value: + * pointer to descriptor or NULL if not found + ********************************************************************* */ + +void *usb_find_cfg_descr(usbdev_t *dev,int dtype,int idx) +{ + uint8_t *endptr; + uint8_t *ptr; + usb_config_descr_t *cfgdscr; + + if (dev->ud_cfgdescr == NULL) return NULL; + + ptr = (uint8_t *) dev->ud_cfgdescr; + endptr = ptr + GETUSBFIELD((dev->ud_cfgdescr),wTotalLength); + + while (ptr < endptr) { + + cfgdscr = (usb_config_descr_t *) ptr; + + if (cfgdscr->bDescriptorType == dtype) { + if (idx == 0) return (void *) ptr; + else idx--; + } + + ptr += cfgdscr->bLength; + + } + + return NULL; +} diff --git a/cfe/cfe/usb/usbd.h b/cfe/cfe/usb/usbd.h new file mode 100644 index 0000000..73fde86 --- /dev/null +++ b/cfe/cfe/usb/usbd.h @@ -0,0 +1,308 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Device Layer definitions File: usbd.h + * + * Definitions for the USB device layer. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _PHYSADDR_T_DEFINED_ +#include "lib_physio.h" +#endif + +#include "usbchap9.h" + + +/* ********************************************************************* + * Forward declarations and opaque types + ********************************************************************* */ + +typedef struct usb_hc_s usb_hc_t; +typedef struct usb_ept_s usb_ept_t; +typedef struct usb_hcdrv_s usb_hcdrv_t; +typedef struct usbdev_s usbdev_t; +typedef struct usb_driver_s usb_driver_t; + +/* ********************************************************************* + * USB Bus structure - one of these per host controller + ********************************************************************* */ + +#define USB_MAX_DEVICES 128 + +typedef struct usbbus_s { + struct usbbus_s *ub_next; /* link to other buses */ + usb_hc_t *ub_hwsoftc; /* bus driver softc */ + usb_hcdrv_t *ub_hwdisp; /* bus driver dispatch */ + usbdev_t *ub_roothub; /* root hub device */ + usbdev_t *ub_devices[USB_MAX_DEVICES]; /* pointers to each device, idx by address */ + unsigned int ub_flags; /* flag bits */ + int ub_num; /* bus number */ +} usbbus_t; + +#define UB_FLG_NEEDSCAN 1 /* some device on bus needs scanning */ + +/* ********************************************************************* + * USB Pipe structure - one of these per unidirectional channel + * to an endpoint on a USB device + ********************************************************************* */ + +#define UP_TYPE_CONTROL 1 +#define UP_TYPE_BULK 2 +#define UP_TYPE_INTR 4 +#define UP_TYPE_ISOC 8 + +#define UP_TYPE_IN 128 +#define UP_TYPE_OUT 256 + +#define UP_TYPE_LOWSPEED 16 + +typedef struct usbpipe_s { + usb_ept_t *up_hwendpoint; /* OHCI-specific endpoint pointer */ + usbdev_t *up_dev; /* our device info */ + int up_num; /* pipe number */ + int up_mps; /* max packet size */ + int up_flags; +} usbpipe_t; + +/* ********************************************************************* + * USB device structure - one per device attached to the USB + * This is the basic structure applications will use to + * refer to a device. + ********************************************************************* */ + +#define UD_FLAG_HUB 0x0001 /* this is a hub device */ +#define UD_FLAG_ROOTHUB 0x0002 /* this is a root hub device */ +#define UD_FLAG_LOWSPEED 0x0008 /* this is a lowspeed device */ + +#define UD_MAX_PIPES 32 +#define USB_EPADDR_TO_IDX(addr) ((((addr)&0x80) >> 3) | ((addr) & 0x0F)) +//#define USB_EPADDR_TO_IDX(addr) USB_ENDPOINT_ADDRESS(addr) +//#define UD_MAX_PIPES 16 + +struct usbdev_s { + usb_driver_t *ud_drv; /* Driver's methods */ + usbbus_t *ud_bus; /* owning bus */ + int ud_address; /* USB address */ + usbpipe_t *ud_pipes[UD_MAX_PIPES]; /* pipes, 0 is the control pipe */ + struct usbdev_s *ud_parent; /* used for hubs */ + int ud_flags; + void *ud_private; /* private data for device driver */ + usb_device_descr_t ud_devdescr; /* device descriptor */ + usb_config_descr_t *ud_cfgdescr; /* config, interface, and ep descrs */ +}; + + +/* ********************************************************************* + * USB Request - basic structure to describe an in-progress + * I/O request. It associates buses, pipes, and buffers + * together. + ********************************************************************* */ + + +#define UR_FLAG_SYNC 0x8000 + +#define UR_FLAG_SETUP 0x0001 +#define UR_FLAG_IN 0x0002 +#define UR_FLAG_OUT 0x0004 +#define UR_FLAG_STATUS_IN 0x0008 /* status phase of a control WRITE */ +#define UR_FLAG_STATUS_OUT 0x0010 /* status phase of a control READ */ +#define UR_FLAG_SHORTOK 0x0020 /* short transfers are ok */ + + +typedef struct usbreq_s { + queue_t ur_qblock; + + /* + * pointers to our device and pipe + */ + + usbdev_t *ur_dev; + usbpipe_t *ur_pipe; + + /* + * stuff to keep track of the data we transfer + */ + + uint8_t *ur_buffer; + int ur_length; + int ur_xferred; + int ur_status; + int ur_flags; + + /* + * Stuff needed for the callback + */ + void *ur_ref; + int ur_inprogress; + int (*ur_callback)(struct usbreq_s *req); + + /* + * For use inside the ohci driver + */ + void *ur_tdqueue; + int ur_tdcount; +} usbreq_t; + + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int usb_create_pipe(usbdev_t *dev,int pipenum,int mps,int flags); +void usb_destroy_pipe(usbdev_t *dev,int pipenum); +int usb_set_address(usbdev_t *dev,int addr); +usbdev_t *usb_create_device(usbbus_t *bus,int lowspeed); +void usb_destroy_device(usbdev_t *dev); +usbreq_t *usb_make_request(usbdev_t *dev,int pipenum,uint8_t *buf,int length,int flags); +void usb_poll(usbbus_t *bus); +void usb_daemon(usbbus_t *bus); +int usb_cancel_request(usbreq_t *ur); +void usb_free_request(usbreq_t *ur); +int usb_queue_request(usbreq_t *ur); +int usb_wait_request(usbreq_t *ur); +int usb_sync_request(usbreq_t *ur); +int usb_get_descriptor(usbdev_t *dev,uint8_t reqtype,int dsctype,int dscidx,uint8_t *buffer,int buflen); +int usb_get_config_descriptor(usbdev_t *dev,usb_config_descr_t *dscr,int idx,int maxlen); +int usb_get_device_status(usbdev_t *dev,usb_device_status_t *status); +int usb_set_configuration(usbdev_t *dev,int config); +int usb_open_pipe(usbdev_t *dev,usb_endpoint_descr_t *epdesc); +int usb_simple_request(usbdev_t *dev,uint8_t reqtype,int bRequest,int wValue,int wIndex); +void usb_complete_request(usbreq_t *ur,int status); +int usb_get_device_descriptor(usbdev_t *dev,usb_device_descr_t *dscr,int smallflg); +int usb_set_ep0mps(usbdev_t *dev,int mps); +int usb_new_address(usbbus_t *bus); +int usb_get_string(usbdev_t *dev,int id,char *buf,int maxlen); +int usb_std_request(usbdev_t *dev,uint8_t bmRequestType, + uint8_t bRequest,uint16_t wValue, + uint16_t wIndex,uint8_t *buffer,int length); +void *usb_find_cfg_descr(usbdev_t *dev,int dtype,int idx); +void usb_delay_ms(usbbus_t *bus,int ms); +int usb_clear_stall(usbdev_t *dev,int pipe); + +void usb_scan(usbbus_t *bus); +void usbhub_map_tree(usbbus_t *bus,int (*func)(usbdev_t *dev,void *arg),void *arg); +void usbhub_dumpbus(usbbus_t *bus,uint32_t verbose); + +void usb_initroot(usbbus_t *bus); + + +/* ********************************************************************* + * Host Controller Driver + * Methods for abstracting the USB host controller from the + * rest of the goop. + ********************************************************************* */ + +struct usb_hcdrv_s { + usbbus_t * (*hcdrv_create)(physaddr_t regaddr); + void (*hcdrv_delete)(usbbus_t *); + int (*hcdrv_start)(usbbus_t *); + void (*hcdrv_stop)(usbbus_t *); + int (*hcdrv_intr)(usbbus_t *); + usb_ept_t * (*hcdrv_ept_create)(usbbus_t *,int usbaddr,int eptnum,int mps,int flags); + void (*hcdrv_ept_delete)(usbbus_t *,usb_ept_t *); + void (*hcdrv_ept_setmps)(usbbus_t *,usb_ept_t *,int mps); + void (*hcdrv_ept_setaddr)(usbbus_t *,usb_ept_t *,int addr); + void (*hcdrv_ept_cleartoggle)(usbbus_t *,usb_ept_t *); + int (*hcdrv_xfer)(usbbus_t *,usb_ept_t *uept,usbreq_t *ur); +}; + +#define UBCREATE(driver,addr) (*((driver)->hcdrv_create))(addr) +#define UBDELETE(bus) (*((bus)->ub_hwdisp->hcdrv_delete))(bus) +#define UBSTART(bus) (*((bus)->ub_hwdisp->hcdrv_start))(bus) +#define UBSTOP(bus) (*((bus)->ub_hwdisp->hcdrv_stop))(bus) +#define UBINTR(bus) (*((bus)->ub_hwdisp->hcdrv_intr))(bus) +#define UBEPTCREATE(bus,addr,num,mps,flags) (*((bus)->ub_hwdisp->hcdrv_ept_create))(bus,addr,num,mps,flags) +#define UBEPTDELETE(bus,ept) (*((bus)->ub_hwdisp->hcdrv_ept_delete))(bus,ept) +#define UBEPTSETMPS(bus,ept,mps) (*((bus)->ub_hwdisp->hcdrv_ept_setmps))(bus,ept,mps) +#define UBEPTSETADDR(bus,ept,addr) (*((bus)->ub_hwdisp->hcdrv_ept_setaddr))(bus,ept,addr) +#define UBEPTCLEARTOGGLE(bus,ept) (*((bus)->ub_hwdisp->hcdrv_ept_cleartoggle))(bus,ept) +#define UBXFER(bus,ept,xfer) (*((bus)->ub_hwdisp->hcdrv_xfer))(bus,ept,xfer) + +/* ********************************************************************* + * Devices - methods for abstracting things that _use_ USB + * (devices you can plug into the USB) - the entry points + * here are basically just for device discovery, since the top half + * of the actual driver will be device-specific. + ********************************************************************* */ + +struct usb_driver_s { + char *udrv_name; + int (*udrv_attach)(usbdev_t *,usb_driver_t *); + int (*udrv_detach)(usbdev_t *); +}; + +typedef struct usb_drvlist_s { + int udl_class; + int udl_vendor; + int udl_product; + usb_driver_t *udl_disp; +} usb_drvlist_t; + +extern usb_driver_t *usb_find_driver(usbdev_t *dev); + +#define CLASS_ANY -1 +#define VENDOR_ANY -1 +#define PRODUCT_ANY -1 + +void mydelay(int x); + +#define IS_HUB(dev) ((dev)->ud_devdescr.bDeviceClass == USB_DEVICE_CLASS_HUB) + +/* ********************************************************************* + * Error codes + ********************************************************************* */ + +#define USBD_ERR_OK 0 /* Request ok */ +#define USBD_ERR_STALLED -1 /* Endpoint is stalled */ +#define USBD_ERR_IOERROR -2 /* I/O error */ +#define USBD_ERR_HWERROR -3 /* Hardware failure */ +#define USBD_ERR_CANCELED -4 /* Request canceled */ +#define USBD_ERR_NOMEM -5 /* Out of memory */ +#define USBD_ERR_TIMEOUT -6 /* Request timeout */ + +/* ********************************************************************* + * Debug routines + ********************************************************************* */ + +void usb_dbg_dumpportstatus(int port,usb_port_status_t *portstatus,int level); +void usb_dbg_dumpdescriptors(usbdev_t *dev,uint8_t *ptr,int len); +void usb_dbg_dumpcfgdescr(usbdev_t *dev); +void usb_dbg_dumpeptdescr(usb_endpoint_descr_t * epdscr); diff --git a/cfe/cfe/usb/usbdebug.c b/cfe/cfe/usb/usbdebug.c new file mode 100644 index 0000000..14ed866 --- /dev/null +++ b/cfe/cfe/usb/usbdebug.c @@ -0,0 +1,307 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB debugging code File: usbdebug.c + * + * This module contains debug code for USB. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_ +#include +#include +#include +#include +#include "usbhack.h" +#else +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" + + +void usb_dbg_dumpportstatus(int port,usb_port_status_t *portstatus,int level) +{ + int idx; + uint16_t x; + + for (idx = 0; idx < level; idx++) printf(" "); + printf("PORT %d STATUS\n",port); + + for (idx = 0; idx < level; idx++) printf(" "); + x = GETUSBFIELD((portstatus),wPortStatus); + printf("wPortStatus = %04X ",x); + if (x & 1) printf("DevicePresent "); + if (x & 2) printf("Enabled "); + if (x & 4) printf("Suspend "); + if (x & 8) printf("OverCurrent "); + if (x & 16) printf("InReset "); + if (x & 256) printf("Powered "); + if (x & 512) printf("LowSpeed "); + printf("\n"); + for (idx = 0; idx < level; idx++) printf(" "); + x = GETUSBFIELD((portstatus),wPortChange); + printf("wPortChange = %04X ",x); + if (x & 1) printf("ConnectChange "); + if (x & 2) printf("EnableChange "); + if (x & 4) printf("SuspendChange "); + if (x & 8) printf("OverCurrentChange "); + if (x & 16) printf("ResetChange "); + printf("\n"); +} + +void usb_dbg_dumpeptdescr(usb_endpoint_descr_t * epdscr) +{ + printf("---------------------------------------------------\n"); + printf("ENDPOINT DESCRIPTOR\n"); + + printf("bLength = %d\n",epdscr->bLength); + printf("bDescriptorType = %d\n",epdscr->bDescriptorType); + printf("bEndpointAddr = %02X\n",epdscr->bEndpointAddress); + printf("bmAttrbutes = %02X\n",epdscr->bmAttributes); + printf("wMaxPacketSize = %d\n",GETUSBFIELD(epdscr,wMaxPacketSize)); + printf("bInterval = %d\n",epdscr->bInterval); +} + +static char *getstringmaybe(usbdev_t *dev,int string) +{ + static char buf[256]; + + return ""; + + if (string == 0) { + strcpy(buf,"none"); + return buf; + } + + memset(buf,0,sizeof(buf)); + + usb_get_string(dev,string,buf,sizeof(buf)); + + return buf; +} + +void usb_dbg_dumpdescriptors(usbdev_t *dev,uint8_t *ptr,int len) +{ + uint8_t *endptr; + usb_config_descr_t *cfgdscr; + usb_interface_descr_t *ifdscr; + usb_device_descr_t *devdscr; + usb_endpoint_descr_t *epdscr; + usb_hid_descr_t *hiddscr; + usb_hub_descr_t *hubdscr; + static char *eptattribs[4] = {"Control","Isoc","Bulk","Interrupt"}; + int idx; + + endptr = ptr + len; + + while (ptr < endptr) { + + cfgdscr = (usb_config_descr_t *) ptr; + + switch (cfgdscr->bDescriptorType) { + case USB_DEVICE_DESCRIPTOR_TYPE: + devdscr = (usb_device_descr_t *) ptr; + printf("---------------------------------------------------\n"); + printf("DEVICE DESCRIPTOR\n"); + printf("bLength = %d\n",devdscr->bLength); + printf("bDescriptorType = %d\n",devdscr->bDescriptorType); + printf("bcdUSB = %04X\n",GETUSBFIELD(devdscr,bcdUSB)); + printf("bDeviceClass = %d\n",devdscr->bDeviceClass); + printf("bDeviceSubClass = %d\n",devdscr->bDeviceSubClass); + printf("bDeviceProtocol = %d\n",devdscr->bDeviceProtocol); + printf("bMaxPktSize0 = %d\n",devdscr->bMaxPacketSize0); + if (endptr-ptr <= 8) break; + printf("idVendor = %04X (%d)\n", + GETUSBFIELD(devdscr,idVendor), + GETUSBFIELD(devdscr,idVendor)); + printf("idProduct = %04X (%d)\n", + GETUSBFIELD(devdscr,idProduct), + GETUSBFIELD(devdscr,idProduct)); + printf("bcdDevice = %04X\n",GETUSBFIELD(devdscr,bcdDevice)); + printf("iManufacturer = %d (%s)\n", + devdscr->iManufacturer, + getstringmaybe(dev,devdscr->iManufacturer)); + printf("iProduct = %d (%s)\n", + devdscr->iProduct, + getstringmaybe(dev,devdscr->iProduct)); + printf("iSerialNumber = %d (%s)\n", + devdscr->iSerialNumber, + getstringmaybe(dev,devdscr->iSerialNumber)); + printf("bNumConfigs = %d\n",devdscr->bNumConfigurations); + break; + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + + cfgdscr = (usb_config_descr_t *) ptr; + printf("---------------------------------------------------\n"); + printf("CONFIG DESCRIPTOR\n"); + + printf("bLength = %d\n",cfgdscr->bLength); + printf("bDescriptorType = %d\n",cfgdscr->bDescriptorType); + printf("wTotalLength = %d\n",GETUSBFIELD(cfgdscr,wTotalLength)); + printf("bNumInterfaces = %d\n",cfgdscr->bNumInterfaces); + printf("bConfigValue = %d\n",cfgdscr->bConfigurationValue); + printf("iConfiguration = %d (%s)\n", + cfgdscr->iConfiguration, + getstringmaybe(dev,cfgdscr->iConfiguration)); + printf("bmAttributes = %02X\n",cfgdscr->bmAttributes); + printf("MaxPower = %d (%dma)\n",cfgdscr->MaxPower,cfgdscr->MaxPower*2); + break; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + printf("---------------------------------------------------\n"); + printf("INTERFACE DESCRIPTOR\n"); + + ifdscr = (usb_interface_descr_t *) ptr; + + printf("bLength = %d\n",ifdscr->bLength); + printf("bDescriptorType = %d\n",ifdscr->bDescriptorType); + printf("bInterfaceNum = %d\n",ifdscr->bInterfaceNumber); + printf("bAlternateSet = %d\n",ifdscr->bAlternateSetting); + printf("bNumEndpoints = %d\n",ifdscr->bNumEndpoints); + printf("bInterfaceClass = %d\n",ifdscr->bInterfaceClass); + printf("bInterSubClass = %d\n",ifdscr->bInterfaceSubClass); + printf("bInterfaceProto = %d\n",ifdscr->bInterfaceProtocol); + printf("iInterface = %d (%s)\n", + ifdscr->iInterface, + getstringmaybe(dev,ifdscr->iInterface)); + break; + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + printf("---------------------------------------------------\n"); + printf("ENDPOINT DESCRIPTOR\n"); + + epdscr = (usb_endpoint_descr_t *) ptr; + + printf("bLength = %d\n",epdscr->bLength); + printf("bDescriptorType = %d\n",epdscr->bDescriptorType); + printf("bEndpointAddr = %02X (%d,%s)\n", + epdscr->bEndpointAddress, + epdscr->bEndpointAddress & 0x0F, + (epdscr->bEndpointAddress & USB_ENDPOINT_DIRECTION_IN) ? "IN" : "OUT" + ); + printf("bmAttrbutes = %02X (%s)\n", + epdscr->bmAttributes, + eptattribs[epdscr->bmAttributes&3]); + printf("wMaxPacketSize = %d\n",GETUSBFIELD(epdscr,wMaxPacketSize)); + printf("bInterval = %d\n",epdscr->bInterval); + break; + + case USB_HID_DESCRIPTOR_TYPE: + printf("---------------------------------------------------\n"); + printf("HID DESCRIPTOR\n"); + + hiddscr = (usb_hid_descr_t *) ptr; + + printf("bLength = %d\n",hiddscr->bLength); + printf("bDescriptorType = %d\n",hiddscr->bDescriptorType); + printf("bcdHID = %04X\n",GETUSBFIELD(hiddscr,bcdHID)); + printf("bCountryCode = %d\n",hiddscr->bCountryCode); + printf("bNumDescriptors = %d\n",hiddscr->bNumDescriptors); + printf("bClassDescrType = %d\n",hiddscr->bClassDescrType); + printf("wClassDescrLen = %d\n",GETUSBFIELD(hiddscr,wClassDescrLength)); + break; + + case USB_HUB_DESCRIPTOR_TYPE: + printf("---------------------------------------------------\n"); + printf("HUB DESCRIPTOR\n"); + + hubdscr = (usb_hub_descr_t *) ptr; + + printf("bLength = %d\n",hubdscr->bDescriptorLength); + printf("bDescriptorType = %d\n",hubdscr->bDescriptorType); + printf("bNumberOfPorts = %d\n",hubdscr->bNumberOfPorts); + printf("wHubCharacters = %04X\n",GETUSBFIELD(hubdscr,wHubCharacteristics)); + printf("bPowerOnToPwrGd = %d\n",hubdscr->bPowerOnToPowerGood); + printf("bHubControlCurr = %d (ma)\n",hubdscr->bHubControlCurrent); + printf("bRemPwerMask[0] = %02X\n",hubdscr->bRemoveAndPowerMask[0]); + + break; + + default: + printf("---------------------------------------------------\n"); + printf("UNKNOWN DESCRIPTOR\n"); + printf("bLength = %d\n",cfgdscr->bLength); + printf("bDescriptorType = %d\n",cfgdscr->bDescriptorType); + printf("Data Bytes = "); + for (idx = 0; idx < cfgdscr->bLength; idx++) { + printf("%02X ",ptr[idx]); + } + printf("\n"); + + } + + ptr += cfgdscr->bLength; + + } +} + + +void usb_dbg_dumpcfgdescr(usbdev_t *dev) +{ + uint8_t buffer[512]; + int res; + int len; + usb_config_descr_t *cfgdscr; + + memset(buffer,0,sizeof(buffer)); + + cfgdscr = (usb_config_descr_t *) &buffer[0]; + + res = usb_get_config_descriptor(dev,cfgdscr,0,sizeof(usb_config_descr_t)); + if (res != sizeof(usb_config_descr_t)) { + printf("[a]usb_get_config_descriptor returns %d\n",res); + } + + len = GETUSBFIELD(cfgdscr,wTotalLength); + + res = usb_get_config_descriptor(dev,cfgdscr,0,len); + if (res != len) { + printf("[b]usb_get_config_descriptor returns %d\n",res); + } + + usb_dbg_dumpdescriptors(dev,&buffer[0],res); +} diff --git a/cfe/cfe/usb/usbdevs.c b/cfe/cfe/usb/usbdevs.c new file mode 100644 index 0000000..53a0754 --- /dev/null +++ b/cfe/cfe/usb/usbdevs.c @@ -0,0 +1,168 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Driver List File: usbdevs.c + * + * This module contains a table of supported USB devices and + * the routines to look up appropriate drivers given + * USB product, device, and class codes. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _CFE_ +#include +#include +#include +#include "usbhack.h" +#else +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" + +/* ********************************************************************* + * The list of drivers we support. If you add more drivers, + * list them here. + ********************************************************************* */ + +extern usb_driver_t usbhub_driver; +extern usb_driver_t usbhid_driver; +extern usb_driver_t usbmass_driver; +extern usb_driver_t usbserial_driver; +extern usb_driver_t usbeth_driver; + +usb_drvlist_t usb_drivers[] = { + + /* + * Hub driver + */ + + {USB_DEVICE_CLASS_HUB, VENDOR_ANY, PRODUCT_ANY, &usbhub_driver}, + + /* + * Keyboards and mice + */ + + {USB_DEVICE_CLASS_HUMAN_INTERFACE, VENDOR_ANY,PRODUCT_ANY, &usbhid_driver}, + + /* + * Mass storage devices + */ + + {USB_DEVICE_CLASS_STORAGE, VENDOR_ANY, PRODUCT_ANY, &usbmass_driver}, + + /* + * Serial ports + */ + + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x557,0x2008,&usbserial_driver}, + + /* + * Ethernet Adapters + */ + + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x506,0x4601,&usbeth_driver}, /* 3Com */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2202,&usbeth_driver}, /* Linksys */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2203,&usbeth_driver}, /* Linksys */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2204,&usbeth_driver}, /* Linksys */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2206,&usbeth_driver}, /* Linksys */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x400b,&usbeth_driver}, /* Linksys */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x200c,&usbeth_driver}, /* Linksys */ + {USB_DEVICE_CLASS_RESERVED,0xbda,0x8150,&usbeth_driver}, /* Realtek */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x423,0x000a,&usbeth_driver}, /* CATC */ + {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x423,0x000c,&usbeth_driver}, /* Belkin */ + + {0,0,0,NULL} +}; + + +/* ********************************************************************* + * usb_find_driver(class,vendor,product) + * + * Find a suitable device driver to handle the specified + * class, vendor, or product. + * + * Input parameters: + * devdescr - device descriptor + * + * Return value: + * pointer to device driver or NULL + ********************************************************************* */ + +usb_driver_t *usb_find_driver(usbdev_t *dev) +{ + usb_device_descr_t *devdescr; + usb_interface_descr_t *ifdescr; + usb_drvlist_t *list; + int dclass,vendor,product; + + devdescr = &(dev->ud_devdescr); + + dclass = devdescr->bDeviceClass; + if (dclass == 0) { + ifdescr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); + if (ifdescr) dclass = ifdescr->bInterfaceClass; + } + + vendor = (int) GETUSBFIELD(devdescr,idVendor); + product = (int) GETUSBFIELD(devdescr,idProduct); + + printf("USB: Locating Class %02X Vendor %04X Product %04X: ",dclass,vendor,product); + + list = usb_drivers; + while (list->udl_disp) { + if (((list->udl_class == dclass) || (list->udl_class == CLASS_ANY)) && + ((list->udl_vendor == vendor) || (list->udl_vendor == VENDOR_ANY)) && + ((list->udl_product == product) || (list->udl_product == PRODUCT_ANY))) { + printf("%s\n",list->udl_disp->udrv_name); + return list->udl_disp; + } + list++; + } + + printf("Not found.\n"); + + return NULL; +} diff --git a/cfe/cfe/usb/usbeth.c b/cfe/cfe/usb/usbeth.c new file mode 100644 index 0000000..bc5aeb0 --- /dev/null +++ b/cfe/cfe/usb/usbeth.c @@ -0,0 +1,850 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Ethernet File: usbeth.c + * + * Driver for USB Ethernet devices. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * USB-Ethernet driver - CFE Network Layer Interfaces + * NOTE: Some of the device setup for the Admtek & Realtek devices + * was derived from reverse engineering! So these interfaces + * assume proper device operation. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" +#include "cfe_device.h" +#include "cfe_devfuncs.h" +#include "cfe_error.h" + +#include "usbd.h" +#include "usbeth.h" + +#if 0 +#define USBETH_TRACE( x, y ... ) xprintf( x, ##y ) +#else +#define USBETH_TRACE( x, y ... ) +#endif + +#define FAIL -1 + +static int Dev_cnt = 0; + + +/****************************************************************************** + Debug functions +******************************************************************************/ + +//#define DATA_DUMP +#ifdef DATA_DUMP +static void hexdump( unsigned char * src, int srclen, int rowlen, int rows ) +{ + unsigned char * rowptr; + unsigned char * srcstp; + unsigned char * byteptr; + + srcstp = src + srclen; + + for( rowptr = src; rowptr < src + rowlen * rows; rowptr += rowlen ) { + for( byteptr = rowptr; byteptr < rowptr + rowlen && byteptr < srcstp; byteptr++ ) { + xprintf( "%2X ", *byteptr ); + } + xprintf( "\n" ); + } + xprintf( "\n" ); +} +#endif + + +/* ********************************************************************* + * Interface functions for USB-Ethernet adapters + ********************************************************************* */ + +enum { PEGASUS, PEGASUS_II, NETMATE, REALTEK }; +enum { VEN_NONE, _3_COM, LINKSYS, LINKSYS_10, LINKSYS_100, + CATC_NM, BELKIN_CATC, LINKSYS_100M }; +static char * VENDOR_NAMES[] = +{ + "?", "3-COM", "LinkSys", "LinkSys-10TX", "LinkSys-100TX", + "CATC-Netmate", "Belkin/CATC", "Linksys-100M", "Yikes!" +}; + +typedef struct usbeth_softc_s +{ + usbdev_t *dev; + int bulk_inpipe; + int bulk_outpipe; + int dev_id; + int ven_code; + int embed_tx_len; + uint8_t mac_addr[6]; + usbreq_t *rx_ur; + uint8_t rxbuf[1600]; //artbitrary but enough for ethernet packet +} usbeth_softc_t; + + +/* ************************************** + * CATC I/F Functions + ************************************** */ + +#if 0 +static int catc_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val ) +{ + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), + CATC_GET_REG, 0, reg, val, 1 ); +} +#endif + +static int catc_set_reg( usbdev_t *dev, int16_t reg, int16_t val ) +{ + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), + CATC_SET_REG, val, reg, NULL, 0 ); +} + +static int catc_set_mem( usbdev_t *dev, int16_t addr, + uint8_t *data, int16_t len ) +{ + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), + CATC_SET_MEM, 0, addr, data, len ); +} + +static int catc_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr ) +{ + int status; + + status = usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), + CATC_GET_MAC_ADDR, 0, 0, mac_addr, 6 ); + return( status ); +} + +static void catc_init_device( usbeth_softc_t * softc ) +{ + usbdev_t *dev = softc->dev; + unsigned char *mcast_tbl; + + usb_std_request( dev, (USBREQ_TYPE_STD | USBREQ_REC_INTERFACE), + USB_REQUEST_SET_INTERFACE, + 1, //alt setting 1 + 0, NULL, 0 ); + + catc_set_reg(dev, CATC_TX_BUF_CNT_REG, 0x04 ); + catc_set_reg(dev, CATC_RX_BUF_CNT_REG, 0x10 ); + catc_set_reg(dev, CATC_ADV_OP_MODES_REG, 0x01 ); + catc_set_reg(dev, CATC_LED_CTRL_REG, 0x08 ); + + /* Enable broadcast rx via bit in mutlicast table */ + mcast_tbl = KMALLOC(64, 0); + memset( mcast_tbl, 0, 64 ); + mcast_tbl[31] = 0x80; //i.e. broadcast bit + catc_set_mem( dev, CATC_MCAST_TBL_ADDR, mcast_tbl, 64 ); + KFREE(mcast_tbl); + + //Read the adapter's MAC addr + catc_get_mac_addr( dev, softc->mac_addr ); +} + +static void catc_close_device( usbdev_t *dev ) +{ + // Now disable adapter from receiving packets + catc_set_reg( dev, CATC_ETH_CTRL_REG, 0 ); +} + +static void catc_open_device( usbeth_softc_t * softc ) +{ + int i; + + for(i = 0; i < 6; ++i) + catc_set_reg( softc->dev, (CATC_ETH_ADDR_0_REG - i), softc->mac_addr[i] ); + + // Now enable adapter to receive packets + catc_set_reg( softc->dev, CATC_ETH_CTRL_REG, 0x09 ); +} + +/* ************************************** + * PEGASUS I/F Functions + ************************************** */ + +static int peg_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val, int16_t len ) +{ + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), + PEG_GET_REG, 0, reg, val, len ); +} + +static int peg_set_reg( usbdev_t *dev, int16_t reg, int16_t val ) +{ + unsigned char data = (uint8_t) val & 0xff; + + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), + PEG_SET_REG, val, reg, &data, 1 ); +} + +static int peg_set_regs( usbdev_t *dev, int16_t reg, int8_t *vals, int16_t len ) +{ + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), + PEG_SET_REG, 0, reg, vals, len ); +} + +static int peg_get_eep_word( usbdev_t *dev, int16_t ofs, uint8_t *val ) +{ + int status=0, tries=20; + uint8_t data[2]; + + if( peg_set_reg( dev, PEG_EEPROM_CTL_REG, 0 ) == FAIL ) + return FAIL; + if( peg_set_reg( dev, PEG_EEPROM_OFS_REG, ofs ) == FAIL ) + return FAIL; + if( peg_set_reg( dev, PEG_EEPROM_CTL_REG, 0x02 ) == FAIL ) //read + return FAIL; + while( --tries ) + { + if( peg_get_reg( dev, PEG_EEPROM_CTL_REG, data, 1 ) == FAIL ) + return FAIL; + if( data[0] & 0x04 ) + break; //eeprom data ready + } + if( !tries ) + { + xprintf( "Pegasus Eeprom read failed!\n" ); + return FAIL; + } + if( peg_get_reg( dev, PEG_EEPROM_DATA_REG, data, 2 ) == FAIL ) + return FAIL; + val[0] = data[0]; + val[1] = data[1]; + + return( status ); +} + +static int peg_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr ) +{ + int i, status; + + for( i = 0; i < 3; ++i ) + { + status = peg_get_eep_word( dev, i, &mac_addr[i*2] ); + } + return( status ); +} + +static void peg_init_phy( usbdev_t *dev ) +{ //needed for earlier versions (before Rev B) of the USB-100TX adapters + static uint8_t phy_magic_wr[] = { 0, 4, 0, 0x1b }; + static uint8_t read_status[] = { 0, 0, 0, 1 }; + uint8_t data[4]; + + //reset the MAC ans set up GPIOs + peg_set_reg( dev, PEG_ETH_CTL1_REG, 0x08 ); + peg_get_reg( dev, PEG_ETH_CTL1_REG, data, 1 ); + + //do following steps to enable link activitiy LED + peg_set_reg( dev, PEG_GPIO1_REG, 0x26 ); + peg_set_reg( dev, PEG_GPIO0_REG, 0x24 ); + peg_set_reg( dev, PEG_GPIO0_REG, 0x26 ); + + //do following set of steps to enable LINK LED + memcpy( data, phy_magic_wr, 4 ); + peg_set_regs( dev, PEG_PHY_ADDR_REG, data, 4); //set up for magic word + peg_set_reg( dev, PEG_PHY_CTRL_REG, (0x1b|PHY_WRITE) ); + peg_get_reg( dev, PEG_PHY_CTRL_REG, data, 1 ); //read status of write + memcpy( data, read_status, 4 ); + peg_set_regs( dev, PEG_PHY_ADDR_REG, data, 4); //set up for phy status reg + peg_set_reg( dev, PEG_PHY_CTRL_REG, (1|PHY_READ) ); + peg_get_reg( dev, PEG_PHY_CTRL_REG, data, 1 ); //read status of read + peg_get_reg( dev, PEG_PHY_DATA_REG, data, 2 ); //read status regs +} + +static void peg_init_device( usbeth_softc_t * softc ) +{ + usbdev_t *dev = softc->dev; + + if( softc->dev_id == PEGASUS_II ) + peg_set_reg( dev, PEG_INT_PHY_REG, 0x02 ); //enable internal PHY + else + peg_init_phy( dev ); + + //Read the adapter's MAC addr + peg_get_mac_addr( dev, softc->mac_addr ); +} + +static void peg_close_device( usbdev_t *dev ) +{ + //Now disable adapter from receiving or transmitting packets + peg_set_reg( dev, PEG_ETH_CTL1_REG, 0 ); +} + +static void peg_open_device( usbeth_softc_t * softc ) +{ + usbdev_t *dev = softc->dev; + + //Now setup adapter's receiver with MAC address + peg_set_regs( dev, PEG_MAC_ADDR_0_REG, softc->mac_addr, 6 ); + + //Now enable adapter to receive and transmit packets + peg_set_reg( dev, PEG_ETH_CTL0_REG, 0xc1 ); + peg_set_reg( dev, PEG_ETH_CTL1_REG, 0x30 ); +} + +/* ************************************** + * REALTEK I/F Functions + ************************************** */ + +// +// ********** NOT FULLY WORKING YET!!!!!!!!!! *************** +// + +static int rtek_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val, int16_t len ) +{ + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), + RTEK_REG_ACCESS, reg, 0, val, len ); +} + +static int rtek_set_reg( usbdev_t *dev, int16_t reg, int16_t val ) +{ + unsigned char data = (uint8_t) val & 0xff; + + return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), + RTEK_REG_ACCESS, reg, 0, &data, 1 ); +} + +static int rtek_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr ) +{ + int status; + + status = rtek_get_reg( dev, RTEK_MAC_REG, mac_addr, 6 ); + + return( status ); +} + +static void rtek_init_device( usbeth_softc_t * softc ) +{ + int i; + usbdev_t *dev = softc->dev; + uint8_t val; + + //Reset the adapter + rtek_set_reg( dev, RTEK_CMD_REG, RTEK_RESET ); + for( i = 0; i < 10; ++i ) + { + rtek_get_reg( dev, RTEK_CMD_REG, &val, 1 ); + if( !(val & RTEK_RESET) ) + break; + usb_delay_ms( NULL, 1 ); + } + + //autoload the internal registers + rtek_set_reg( dev, RTEK_CMD_REG, RTEK_AUTOLOAD ); + for( i = 0; i < 50; ++i ) + { + rtek_get_reg( dev, RTEK_CMD_REG, &val, 1 ); + if( !(val & RTEK_AUTOLOAD) ) + break; + usb_delay_ms( NULL, 1 ); + } + + //Read the adapter's MAC addr + rtek_get_mac_addr( dev, softc->mac_addr ); +} + +static void rtek_close_device( usbdev_t *dev ) +{ + //Now disable adapter from receiving or transmitting packets + rtek_set_reg( dev, RTEK_CMD_REG, 0 ); +} + +static void rtek_open_device( usbeth_softc_t * softc ) +{ + //accept broadcast & own packets + rtek_set_reg( softc->dev, RTEK_RXCFG_REG, 0x0c ); + + //Now enable adapter to receive and transmit packets + rtek_set_reg( softc->dev, RTEK_CMD_REG, 0x0c ); +} + +//*********************** USB-ETH I/F Functions **************************** + +static const int ID_TBL[] = +{ + 0x0506, 0x4601, PEGASUS_II, _3_COM, //3-Com + 0x066b, 0x2202, PEGASUS_II, LINKSYS_10, //LinkSys + 0x066b, 0x2203, PEGASUS, LINKSYS_100, + 0x066b, 0x2204, PEGASUS, LINKSYS_100, + 0x066b, 0x2206, PEGASUS, LINKSYS, + 0x066b, 0x400b, PEGASUS_II, LINKSYS_10, + 0x066b, 0x200c, PEGASUS_II, LINKSYS_10, + 0x0bda, 0x8150, REALTEK, LINKSYS_100M, + 0x0423, 0x000a, NETMATE, CATC_NM, //CATC (Netmate I) + 0x0423, 0x000c, NETMATE, BELKIN_CATC, //Belkin & CATC (Netmate II) + -1 +}; + +static int usbeth_init_device( usbeth_softc_t * softc ) +{ + int i; + usb_device_descr_t dev_desc; + uint16_t vendor_id, device_id; + const int *ptr=ID_TBL; + + //find out which device is connected + usb_get_device_descriptor( softc->dev, &dev_desc, 0 ); + vendor_id = (dev_desc.idVendorHigh << 8) + dev_desc.idVendorLow; + device_id = (dev_desc.idProductHigh << 8) + dev_desc.idProductLow; + xprintf( "USB device: vendor id %04x, device id %04x\n", + vendor_id, device_id ); + + while( *ptr != -1 ) + { + if( (vendor_id == ptr[0]) && (device_id == ptr[1]) ) + { + softc->dev_id = ptr[2]; + softc->ven_code = ptr[3]; + break; + } + ptr += 4; + } + if( *ptr == -1 ) + { + xprintf( "Unrecognized USB-Ethernet device\n" ); + return -1; + } + + //init the adapter + if( softc->dev_id == NETMATE ) + { + catc_init_device( softc ); + softc->embed_tx_len = 1; + } + else + { + if( softc->dev_id == REALTEK ) + { + rtek_init_device( softc ); + softc->embed_tx_len = 0; + } + else + { + peg_init_device( softc ); + softc->embed_tx_len = 1; + } + } + + //display adapter info + xprintf( "%s USB-Ethernet Adapter (", VENDOR_NAMES[softc->ven_code] ); + for( i = 0; i < 6; ++i ) + xprintf( "%02x%s", softc->mac_addr[i], (i == 5) ? ")\n" : ":" ); + + return 0; +} + +static int usbeth_get_dev_addr( usbeth_softc_t * softc, uint8_t *mac_addr ) +{ + memcpy( mac_addr, softc->mac_addr, 6 ); + return 0; +} + +static void usbeth_queue_rx( usbeth_softc_t * softc ) +{ + softc->rx_ur = usb_make_request(softc->dev, softc->bulk_inpipe, + softc->rxbuf, sizeof(softc->rxbuf), + (UR_FLAG_IN | UR_FLAG_SHORTOK)); + usb_queue_request(softc->rx_ur); +} + +static void usbeth_close_device( usbeth_softc_t * softc ) +{ + if( softc->dev_id == NETMATE ) + catc_close_device( softc->dev ); + else if( softc->dev_id == REALTEK ) + rtek_close_device( softc->dev ); + else + peg_close_device( softc->dev ); +} + +static void usbeth_open_device( usbeth_softc_t * softc ) +{ + if( softc->dev_id == NETMATE ) + catc_open_device( softc ); + else if( softc->dev_id == REALTEK ) + rtek_open_device( softc ); + else + peg_open_device( softc ); + + //kick start the receive + usbeth_queue_rx( softc ); +} + +static int usbeth_data_rx( usbeth_softc_t * softc ) +{ + usb_poll(softc->dev->ud_bus); + return( !softc->rx_ur->ur_inprogress ); +} + +static int usbeth_get_eth_frame( usbeth_softc_t * softc, unsigned char * buf ) +{ + int len = 0; + + if( !softc->rx_ur->ur_inprogress ) + { + len = softc->rx_ur->ur_xferred; + memcpy( buf, softc->rxbuf, len ); + usb_free_request(softc->rx_ur); + usbeth_queue_rx( softc ); + } + else + xprintf( "Bulk data is not available yet!\n" ); + + return( len ); +} + +static int usbeth_send_eth_frame( usbeth_softc_t * softc, unsigned char * buf, int len ) +{ + usbreq_t *ur; + int txlen = len; + unsigned char * txbuf; + + if(softc->embed_tx_len) + { + txbuf = KMALLOC((len+2), 0); + txbuf[0] = txlen & 0xff; + txbuf[1] = (txlen >> 8) & 0xff; //1st two bytes...little endian + memcpy( &txbuf[2], buf, txlen ); + txlen += 2; + } + else + { + if( softc->dev_id == REALTEK ) + { + //Now for some Realtek chip workarounds + if( txlen < 60 ) //some strange limitation + txlen = 60; + else if( !(txlen % 64) ) //to handle module 64 packets + ++txlen; + } + txbuf = KMALLOC(txlen, 0); + memcpy( txbuf, buf, txlen ); + } + ur = usb_make_request(softc->dev, softc->bulk_outpipe, + txbuf, txlen, UR_FLAG_OUT); + usb_sync_request(ur); + usb_free_request(ur); + KFREE(txbuf); + + return( len ); +} + + +/* ********************************************************************* + * CFE-USB interfaces + ********************************************************************* */ + +/* ********************************************************************* + * usbeth_attach(dev,drv) + * + * This routine is called when the bus scan stuff finds a usb-ethernet + * device. We finish up the initialization by configuring the + * device and allocating our softc here. + * + * Input parameters: + * dev - usb device, in the "addressed" state. + * drv - the driver table entry that matched + * + * Return value: + * 0 + ********************************************************************* */ + +const cfe_driver_t usbethdrv; //forward declaration + +static int usbeth_attach(usbdev_t *dev,usb_driver_t *drv) +{ + usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; + usb_endpoint_descr_t *epdscr; + usb_endpoint_descr_t *indscr = NULL; + usb_endpoint_descr_t *outdscr = NULL; + usb_interface_descr_t *ifdscr; + usbeth_softc_t *softc; + int idx; + + dev->ud_drv = drv; + + softc = (usbeth_softc_t *) KMALLOC( sizeof(usbeth_softc_t), 0 ); + if( softc == NULL ) + { + xprintf( "Failed to allocate softc memory.\n" ); + return -1; + } + memset( softc, 0, sizeof(usbeth_softc_t) ); + dev->ud_private = softc; + softc->dev = dev; + + ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); + if (ifdscr == NULL) + { + xprintf("USBETH: ERROR...no interace descriptor\n"); + return -1; + } + + + for (idx = 0; idx < 2; idx++) + { + epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); + if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) + outdscr = epdscr; + else + indscr = epdscr; + } + + if (!indscr || !outdscr) + { + /* + * Could not get descriptors, something is very wrong. + * Leave device addressed but not configured. + */ + xprintf("USBETH: ERROR...no endpoint descriptors\n"); + return -1; + } + + /* + * Choose the standard configuration. + */ + + usb_set_configuration(dev,cfgdscr->bConfigurationValue); + + // Quit if not able to initialize the device + if (usbeth_init_device(softc) < 0) + return -1; + + /* + * Open the pipes. + */ + + softc->bulk_inpipe = usb_open_pipe(dev,indscr); + softc->bulk_outpipe = usb_open_pipe(dev,outdscr); + + //Now attach this device as a CFE Ethernet device + cfe_attach( (cfe_driver_t *) &usbethdrv, softc, NULL, + usbethdrv.drv_description ); + + ++Dev_cnt; + + return 0; +} + +/* ********************************************************************* + * usbeth_detach(dev) + * + * This routine is called when the bus scanner notices that + * this device has been removed from the system. We should + * do any cleanup that is required. The pending requests + * will be cancelled automagically. + * + * Input parameters: + * dev - usb device + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbeth_detach(usbdev_t *dev) +{ + usbeth_softc_t *softc = (usbeth_softc_t *) dev->ud_private; + + --Dev_cnt; + KFREE(softc); + + //*** SHOULD DETACH THE ETHERNET DEVICE TOO...LATER + + return 0; +} + +// CFE USB device interface structure +usb_driver_t usbeth_driver = +{ + "Ethernet Device", + usbeth_attach, + usbeth_detach +}; + + + +/* ********************************************************************* + * CFE-Ethernet device interfaces + ********************************************************************* */ + + +static int usbeth_ether_open(cfe_devctx_t *ctx) +{ + if( !Dev_cnt ) + return CFE_ERR_NOTREADY; + + USBETH_TRACE( "%s called.\n", __FUNCTION__ ); + usbeth_open_device( (usbeth_softc_t *) ctx->dev_softc ); + + return 0; +} + +static int usbeth_ether_read( cfe_devctx_t * ctx, iocb_buffer_t * buffer ) +{ + if( !Dev_cnt ) + return CFE_ERR_NOTREADY; + + buffer->buf_retlen = usbeth_get_eth_frame( (usbeth_softc_t *)ctx->dev_softc, + buffer->buf_ptr ); + +#ifdef DATA_DUMP + xprintf( "Incoming packet :\n" ); + hexdump( buffer->buf_ptr, buffer->buf_retlen, 16, + buffer->buf_retlen / 16 + 1 ); +#endif + + return 0; +} + + +static int usbeth_ether_inpstat( cfe_devctx_t * ctx, iocb_inpstat_t * inpstat ) +{ + if( !Dev_cnt ) + return CFE_ERR_NOTREADY; + + inpstat->inp_status = usbeth_data_rx( (usbeth_softc_t *) ctx->dev_softc ); + + return 0; +} + + +static int usbeth_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + if( !Dev_cnt ) + return CFE_ERR_NOTREADY; + + // Block until hw notifies you data is sent. + usbeth_send_eth_frame( (usbeth_softc_t *) ctx->dev_softc, buffer->buf_ptr, + buffer->buf_length ); + + return 0; +} + + +static int usbeth_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + int retval = 0; + + if( !Dev_cnt ) + return CFE_ERR_NOTREADY; + + switch( (int)buffer->buf_ioctlcmd ) { + case IOCTL_ETHER_GETHWADDR: + USBETH_TRACE( "IOCTL_ETHER_GETHWADDR called.\n" ); + usbeth_get_dev_addr( (usbeth_softc_t *) ctx->dev_softc, + buffer->buf_ptr ); + break; + case IOCTL_ETHER_SETHWADDR: + xprintf( "IOCTL_ETHER_SETHWADDR not implemented.\n" ); + break; +#if 0 + case IOCTL_ETHER_GETSPEED: + xprintf( "GETSPEED not implemented.\n" ); + retval = -1; + break; + case IOCTL_ETHER_SETSPEED: + xprintf( "SETSPEED not implemented.\n" ); + retval = -1; + break; + case IOCTL_ETHER_GETLINK: + xprintf( "GETLINK not implemented.\n" ); + retval = -1; + break; + case IOCTL_ETHER_GETLOOPBACK: + xprintf( "GETLOOPBACK not implemented.\n" ); + retval = -1; + break; + case IOCTL_ETHER_SETLOOPBACK: + xprintf( "SETLOOPBACK not implemented.\n" ); + retval = -1; + break; +#endif + default: + xprintf( "Invalid IOCTL to usbeth_ether_ioctl.\n" ); + retval = -1; + } + + return retval; +} + + +static int usbeth_ether_close(cfe_devctx_t *ctx) +{ + if( !Dev_cnt ) + return CFE_ERR_NOTREADY; + + USBETH_TRACE( "%s called.\n", __FUNCTION__ ); + usbeth_close_device( (usbeth_softc_t *) ctx->dev_softc ); + + return 0; +} + + +// CFE ethernet device interface structures +const static cfe_devdisp_t usbeth_ether_dispatch = +{ + usbeth_ether_open, + usbeth_ether_read, + usbeth_ether_inpstat, + usbeth_ether_write, + usbeth_ether_ioctl, + usbeth_ether_close, + NULL, + NULL +}; + +const cfe_driver_t usbethdrv = +{ + "USB-Ethernet Device", + "eth", + CFE_DEV_NETWORK, + &usbeth_ether_dispatch, + NULL, //probe...not needed +}; + diff --git a/cfe/cfe/usb/usbeth.h b/cfe/cfe/usb/usbeth.h new file mode 100644 index 0000000..54f32ae --- /dev/null +++ b/cfe/cfe/usb/usbeth.h @@ -0,0 +1,112 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Ethernet File: usbeth.h + * + * Driver for USB Ethernet devices. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * USB-Ethernet adapter driver includes + ********************************************************************* */ + +#ifndef __usbeth_h__ +#define __usbeth_h__ + +/* ************************************** + * CATC Netmate adapter + ************************************** */ + +#define CATC_MCAST_TBL_ADDR 0xFA80 //in Netmate's SRAM +#define CATC_GET_MAC_ADDR 0xF2 +#define CATC_SET_REG 0xFA +#define CATC_GET_REG 0xFB +#define CATC_SET_MEM 0xFC + +#define CATC_TX_BUF_CNT_REG 0x20 +#define CATC_RX_BUF_CNT_REG 0x21 +#define CATC_ADV_OP_MODES_REG 0x22 +#define CATC_RX_FRAME_CNT_REG 0x24 + +#define CATC_ETH_CTRL_REG 0x60 +#define CATC_ENET_STATUS_REG 0x61 +#define CATC_ETH_ADDR_0_REG 0x67 // Byte #0 (leftmost) +#define CATC_LED_CTRL_REG 0x81 + + +/* ************************************** + * Admtek (PEGASUS II) adapter + ************************************** */ + +#define PEG_SET_REG 0xF1 +#define PEG_GET_REG 0xF0 + +#define PEG_MCAST_TBL_REG 0x08 +#define PEG_MAC_ADDR_0_REG 0x10 +#define PEG_EEPROM_OFS_REG 0x20 +#define PEG_EEPROM_DATA_REG 0x21 +#define PEG_EEPROM_CTL_REG 0x23 +#define PEG_PHY_ADDR_REG 0x25 +#define PEG_PHY_DATA_REG 0x26 //& 27 for 2 bytes +#define PEG_PHY_CTRL_REG 0x28 +#define PEG_ETH_CTL0_REG 0x00 +#define PEG_ETH_CTL1_REG 0x01 +#define PEG_ETH_CTL2_REG 0x02 +#define PEG_GPIO0_REG 0x7e +#define PEG_GPIO1_REG 0x7f +#define PEG_INT_PHY_REG 0x7b + +#define PHY_WRITE 0x20 +#define PHY_READ 0x40 + + +/* ************************************** + * Realtek adapter + ************************************** */ + +#define RTEK_REG_ACCESS 0x05 +#define RTEK_MAC_REG 0x0120 +#define RTEK_CMD_REG 0x012E +#define RTEK_RXCFG_REG 0x0130 +#define RTEK_RESET 0x10 +#define RTEK_AUTOLOAD 0x01 + + + +#endif //__usbeth_h_ diff --git a/cfe/cfe/usb/usbhack.c b/cfe/cfe/usb/usbhack.c new file mode 100644 index 0000000..647f213 --- /dev/null +++ b/cfe/cfe/usb/usbhack.c @@ -0,0 +1,528 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Main Module File: usbhack.c + * + * A crude test program to let us tinker with a USB controller + * installed in an X86 Linux PC. Eventually we'll clean up + * this stuff and incorporate it into CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" +#include "ohci.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define OHCI_WRITECSR(softc,x,y) \ + *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t)))) = (y) +#define OHCI_READCSR(softc,x) \ + *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t)))) + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern int usb_noisy; +extern int ohcidebug; + +extern usbdev_t *usbmass_dev; +extern int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, + uint8_t *buffer); + + +/* ********************************************************************* + * Play Area definitions + * + * We use /dev/mem to map two areas - the "play" area and the + * "device" area. + * + * The "play" area maps to the upper 1MB of physical memory. + * You need to calculate this address yourself based on your system + * setup. If you have 256MB of memory, in your lilo.conf file put + * the following line: + * + * append="mem=255M" + * + * where '255' is one less than your system memory size. this + * leaves 1MB out of Linux's physical memory map and therefore + * leaves it to you to play with. /dev/mem will map this + * uncached using the Pentium MTRR registers, but for playing + * around this will be fine. + * + * the second area is the "device area" - this is the address + * the PCI USB controller's BARs were mapped to. You can find + * this by looking through /proc/pci until you find: + * + * Bus 0, device 8, function 0: + * USB Controller: OPTi Unknown device (rev 16). + * Vendor id=1045. Device id=c861. + * Medium devsel. Fast back-to-back capable. IRQ 3. + * Master Capable. Latency=32. + * Non-prefetchable 32 bit memory at 0xd9100000 [0xd9100000]. + * + * The 0xd9100000 will probably be different on your system. + * + * Of course, to make this work you'll need to rebuild the kernel + * without USB support, if you're running a recent kernel. + * Fortunately(?), I've been using RH 6.2, no USB support there + * in the old 2.2 kernels. + * + * Finally, you'll need to run this program as root. Even if + * you mess with the permissions on /dev/mem, there are additional + * checks in the kernel, so you will lose. + * + * But, the good news is that it works well - I've never crashed + * my Linux box, and I can use gdb to debug programs. + * You will NOT be able to use GDB to display things in the + * play area - I believe GDB doesn't know how to deal with + * the uncached nature of the memory there. You can see stuff + * in the area by tracing through instructions that read the play + * area, and viewing the register contents. + ********************************************************************* */ + +#define PLAY_AREA_ADDR (255*1024*1024) /* EDIT ME */ +#define PLAY_AREA_SIZE (1024*1024) +int play_fd = -1; +uint8_t *play_area = MAP_FAILED; + +#define DEVICE_AREA_ADDR 0xd9100000 /* EDIT ME */ +#define DEVICE_AREA_SIZE 4096 +int dev_fd = -1; +uint8_t *device_area = MAP_FAILED; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + + +usbbus_t *bus = NULL; +ohci_softc_t *ohci = NULL; +int running = 1; + +/* ********************************************************************* + * vtop(v) + * + * Given a virtual address in the play area, return its physical + * address. + * + * Input parameters: + * v - virtual address + * + * Return value: + * physical address + ********************************************************************* */ + + +uint32_t vtop(void *v) +{ + uint32_t p = (uint32_t) v; + + if (v == 0) return 0; + + p -= (uint32_t) play_area; + p += PLAY_AREA_ADDR; + + return p; +} + +/* ********************************************************************* + * ptov(v) + * + * Given a phyiscal address in the play area, return the virtual + * address. + * + * Input parameters: + * p - physical address + * + * + * Return value: + * virtual address (void pointer) + ********************************************************************* */ + +void *ptov(uint32_t p) +{ + if (p == 0) return 0; + + p -= PLAY_AREA_ADDR; + p += (uint32_t) play_area; + + return (void *) p; +} + +/* ********************************************************************* + * mydelay(x) + * + * delay for 'x' milliseconds. + * + * Input parameters: + * x - milliseconds + * + * Return value: + * nothing + ********************************************************************* */ + +void mydelay(int x) +{ + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = x * 1000000; /* milliseconds */ + nanosleep(&ts,NULL); +} + +/* ********************************************************************* + * console_log(tmplt,...) + * + * Display a console log message - this is a CFE function + * transplanted here. + * + * Input parameters: + * tmplt - printf string args... + * + * Return value: + * nothing + ********************************************************************* */ + +void console_log(const char *tmplt,...) +{ + char buffer[256]; + va_list marker; + + va_start(marker,tmplt); + vsprintf(buffer,tmplt,marker); + va_end(marker); + printf("%s\n",buffer); +} + +/* ********************************************************************* + * init_devaccess() + * + * Open /dev/mem and create the play area + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok, else error + ********************************************************************* */ + +int init_devaccess(void) +{ + int idx; + + play_fd = open("/dev/mem",O_RDWR); + + if (play_fd < 0) { + perror("open"); + return -1; + } + + dev_fd = open("/dev/mem",O_RDWR | O_SYNC); + + if (dev_fd < 0) { + perror("open"); + close(play_fd); + play_fd = -1; + return -1; + } + + play_area = mmap(NULL, + PLAY_AREA_SIZE, + PROT_READ|PROT_WRITE,MAP_SHARED, + play_fd, + PLAY_AREA_ADDR); + + if (play_area != MAP_FAILED) { + printf("Play area mapped ok at address %p to %p\n",play_area,play_area+PLAY_AREA_SIZE-1); + for (idx = 0; idx < PLAY_AREA_SIZE; idx++) { + play_area[idx] = 0x55; + if (play_area[idx] != 0x55) printf("Offset %x doesn't work\n",idx); + play_area[idx] = 0xaa; + if (play_area[idx] != 0xaa) printf("Offset %x doesn't work\n",idx); + play_area[idx] = 0x0; + if (play_area[idx] != 0x0) printf("Offset %x doesn't work\n",idx); + } + } + else { + perror("mmap"); + close(play_fd); + close(dev_fd); + play_fd = -1; + dev_fd = -1; + return -1; + } + + device_area = mmap(NULL, + DEVICE_AREA_SIZE, + PROT_READ|PROT_WRITE,MAP_SHARED, + dev_fd, + DEVICE_AREA_ADDR); + + if (device_area != MAP_FAILED) { + printf("Device area mapped ok at address %p\n",device_area); + } + else { + perror("mmap"); + munmap(play_area,PLAY_AREA_SIZE); + play_area = MAP_FAILED; + close(play_fd); + close(dev_fd); + play_fd = -1; + dev_fd = -1; + return -1; + } + + return 0; +} + + +/* ********************************************************************* + * uninit_devaccess() + * + * Turn off access to the /dev/mem area. this will also + * set the OHCI controller's state to reset if we were playing + * with it. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void uninit_devaccess(void) +{ + if (ohci->ohci_regs) { + OHCI_WRITECSR(ohci,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET)); + } + + if (play_area != MAP_FAILED) munmap(play_area,PLAY_AREA_SIZE); + if (device_area != MAP_FAILED) munmap(device_area,DEVICE_AREA_SIZE); + + if (play_fd > 0) close(play_fd); + if (dev_fd > 0) close(dev_fd); + + device_area = MAP_FAILED; + play_area = MAP_FAILED; + + dev_fd = -1; + play_fd = -1; +} + +/* ********************************************************************* + * sighandler() + * + * ^C handler - switch off OHCI controller + * + * Input parameters: + * sig - signal + * + * Return value: + * nothing + ********************************************************************* */ + +void sighandler(int sig) +{ + signal(SIGINT,SIG_DFL); + printf("Interrupted, controller reset\n"); + if (ohci->ohci_regs) { + OHCI_WRITECSR(ohci,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET)); + } + running = 0; +} + + +extern usb_hcdrv_t ohci_driver; + +/* ********************************************************************* + * xprintf(str) + * + * Called by lib_malloc, we need to supply it. + * + * Input parameters: + * str - string + * + * Return value: + * 0 + ********************************************************************* */ + +int xprintf(char *str) +{ + printf("%s",str); + return 0; +} + +/* ********************************************************************* + * main(argc,argv) + * + * Main test program + * + * Input parameters: + * argc,argv - guess. + * + * Return value: + * nothing + ********************************************************************* */ + + +int main(int argc,char *argv[]) +{ + int res; + memstats_t stats; + uint8_t *buffer; + + /* + * Parse command line args + */ + + for (res = 1; res < argc; res++) { + if (strcmp(argv[res],"-o") == 0) ohcidebug++; + if (strcmp(argv[res],"-u") == 0) usb_noisy++; + } + + /* + * Open the play area. + */ + + if (init_devaccess() < 0) { + printf("Could not map USB controller\n"); + } + + /* + * Establish signal and exit handlers + */ + + signal(SIGINT,sighandler); + atexit(uninit_devaccess); + + /* + * Initialize a buffer pool to point at the play area. + * the 'malloc' calls inside our driver will therefore + * allocate memory suitable for DMA, just like on real + * hardware. + */ + + KMEMINIT(play_area,PLAY_AREA_SIZE); + + buffer = KMALLOC(512,32); + + printf("-------------------------------------------\n\n"); + + /* + * Create the OHCI driver instance. + */ + + + bus = UBCREATE(&ohci_driver,(void *) device_area); + + /* + * Hack: retrieve copy of softc for our exception handler + */ + + ohci = (ohci_softc_t *) bus->ub_hwsoftc; + + /* + * Start the controller. + */ + + res = UBSTART(bus); + + if (res != 0) { + printf("Could not init hardware\n"); + UBSTOP(bus); + exit(1); + } + + /* + * Init the root hub + */ + + usb_initroot(bus); + + /* + * Main loop - just call interrupt routine to poll + */ + + while (usbmass_dev== NULL) { + usb_poll(bus); + usb_daemon(bus); + } + + for (res = 0; res < 1000; res++) { + usbmass_read_sector(usbmass_dev,0,1,buffer); + } + + printf("----- finished reading all sectors ----\n"); + + while (running) { + usb_poll(bus); + usb_daemon(bus); + } + + /* + * Clean up - get heap statistics to see if we + * screwed up. + */ + + res = KMEMSTATS(&stats); + if (res < 0) printf("Warning: heap is not consistent\n"); + else printf("Heap is ok\n"); + + exit(0); + +} diff --git a/cfe/cfe/usb/usbhack.h b/cfe/cfe/usb/usbhack.h new file mode 100644 index 0000000..9f95840 --- /dev/null +++ b/cfe/cfe/usb/usbhack.h @@ -0,0 +1,66 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * usb test harness definitions File: usbhack.h + * + * Anything special required by the test harness is defined + * here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +/* ********************************************************************* + * Constants + ********************************************************************* */ + + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +void console_log(const char *tmplt,...); + diff --git a/cfe/cfe/usb/usbhack.mk b/cfe/cfe/usb/usbhack.mk new file mode 100644 index 0000000..361973e --- /dev/null +++ b/cfe/cfe/usb/usbhack.mk @@ -0,0 +1,23 @@ + +OBJS = usbhack.o lib_malloc.o lib_queue.o ohci.o usbd.o \ + usbdevs.o usbhub.o usbdebug.o usbhid.o usbmass.o usbserial.o + +CFLAGS = -I../include -g -Wall +VPATH = ../lib + +%.o : %.c + gcc $(CFLAGS) -c -o $@ $< + +all : usbhack + echo done + +usbhack : $(OBJS) + gcc -o usbhack $(OBJS) + +lib_malloc.o : lib_malloc.c + +usbhack.o : usbhack.c + + +clean : + rm -f *.o usbhack diff --git a/cfe/cfe/usb/usbhid.c b/cfe/cfe/usb/usbhid.c new file mode 100644 index 0000000..df84f4e --- /dev/null +++ b/cfe/cfe/usb/usbhid.c @@ -0,0 +1,664 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Human Interface Driver File: usbhid.c + * + * This module deals with keyboards, mice, etc. It's very simple, + * and only the "boot protocol" is supported. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_ +#include +#include +#include +#include +#include "usbhack.h" +#else +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "cfe_console.h" +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define HID_BOOT_PROTOCOL 0 +#define HID_REPORT_PROTOCOL 1 + +#define HID_DEVTYPE_UNKNOWN 0 +#define HID_DEVTYPE_KBD 1 +#define HID_DEVTYPE_MOUSE 2 +#define HID_DEVTYPE_MAX 2 + +#define UBR_KBD_MODS 0 +#define UBR_KBD_RSVD 1 +#define UBR_KBD_KEYS 2 +#define UBR_KBD_NUMKEYS 6 +#define UBR_KBD_MAX 8 + +#define KBD_MOD_LCTRL 0x01 +#define KBD_MOD_LSHIFT 0x02 +#define KBD_MOD_LALT 0x04 +#define KBD_MOD_LWIN 0x08 + +#define KBD_MOD_RCTRL 0x10 +#define KBD_MOD_RSHIFT 0x20 +#define KBD_MOD_RALT 0x40 +#define KBD_MOD_RWIN 0x80 + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define usbhid_set_protocol(dev,protocol,ifc) \ + usb_simple_request(dev,0x21,0x0B,0,ifc) + + +/* ********************************************************************* + * Forward Definitions + ********************************************************************* */ + +static int usbhid_attach(usbdev_t *dev,usb_driver_t *drv); +static int usbhid_detach(usbdev_t *dev); + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct usbhid_softc_s { + int uhid_ipipe; + int uhid_ipipemps; + int uhid_devtype; + uint8_t uhid_imsg[UBR_KBD_MAX]; + uint8_t uhid_lastmsg[UBR_KBD_MAX]; + uint32_t uhid_shiftflags; +} usbhid_softc_t; + +usb_driver_t usbhid_driver = { + "Human-Interface Device", + usbhid_attach, + usbhid_detach +}; + +static char *usbhid_devtypes[3] = { + "Unknown", + "Keyboard", + "Mouse"}; + +#ifdef CFG_VGACONSOLE +extern int pcconsole_enqueue(uint8_t ch); +#endif + + +/* ********************************************************************* + * Constants for keyboard table + ********************************************************************* */ + +#define FLG_NUM 0x0001 /* Toggles: same as bits for LEDs */ +#define FLG_CAPS 0x0002 +#define FLG_SCROLL 0x0004 +#define FLG_SHIFT 0x0008 /* Shifts */ +#define FLG_CTRL 0x0100 +#define FLG_ALT 0x0200 +#define FLG_FKEY 0x0400 /* function keys */ +#define FLG_NKPD 0x0800 /* numeric keypad */ +#define FLG_ASCII 0x1000 /* regular ASCII character */ +#define FLG_NONE 0x2000 + + +/* ********************************************************************* + * Structures for keyboard table + ********************************************************************* */ + +#define KC_RESPLEN 4 +typedef struct keycode_s { + int kc_type; + char kc_normal[KC_RESPLEN]; + char kc_shifted[KC_RESPLEN]; + char kc_ctrl[KC_RESPLEN]; +} keycode_t; + + +/* ********************************************************************* + * Scan code conversion table + ********************************************************************* */ + +static keycode_t usbhid_scantable[] = { + { FLG_NONE, "", "", "" }, /* 0 */ + { FLG_NONE, "", "", "" }, /* 1 */ + { FLG_NONE, "", "", "" }, /* 2 */ + { FLG_NONE, "", "", "" }, /* 3 */ + { FLG_ASCII, "a", "A", "\001" }, /* 4 a */ + { FLG_ASCII, "b", "B", "\002" }, /* 5 b */ + { FLG_ASCII, "c", "C", "\003" }, /* 6 c */ + { FLG_ASCII, "d", "D", "\004" }, /* 7 d */ + { FLG_ASCII, "e", "E", "\005" }, /* 8 e */ + { FLG_ASCII, "f", "F", "\006" }, /* 9 f */ + { FLG_ASCII, "g", "G", "\007" }, /* 10 g */ + { FLG_ASCII, "h", "H", "\010" }, /* 11 h */ + { FLG_ASCII, "i", "I", "\011" }, /* 12 i */ + { FLG_ASCII, "j", "J", "\n" }, /* 13 j */ + { FLG_ASCII, "k", "K", "\013" }, /* 14 k */ + { FLG_ASCII, "l", "L", "\014" }, /* 15 l */ + { FLG_ASCII, "m", "M", "\r" }, /* 16 m */ + { FLG_ASCII, "n", "N", "\016" }, /* 17 n */ + { FLG_ASCII, "o", "O", "\017" }, /* 18 o */ + { FLG_ASCII, "p", "P", "\020" }, /* 19 p */ + { FLG_ASCII, "q", "Q", "\021" }, /* 20 q */ + { FLG_ASCII, "r", "R", "\022" }, /* 21 r */ + { FLG_ASCII, "s", "S", "\023" }, /* 22 s */ + { FLG_ASCII, "t", "T", "\024" }, /* 23 t */ + { FLG_ASCII, "u", "U", "\025" }, /* 24 u */ + { FLG_ASCII, "v", "V", "\026" }, /* 25 v */ + { FLG_ASCII, "w", "W", "\027" }, /* 26 w */ + { FLG_ASCII, "x", "X", "\030" }, /* 27 x */ + { FLG_ASCII, "y", "Y", "\031" }, /* 28 y */ + { FLG_ASCII, "z", "Z", "\032" }, /* 29 z */ + + { FLG_ASCII, "1", "!", "!" }, /* 30 1 */ + { FLG_ASCII, "2", "@", "\000" }, /* 31 2 */ + { FLG_ASCII, "3", "#", "#" }, /* 32 3 */ + { FLG_ASCII, "4", "$", "$" }, /* 33 4 */ + { FLG_ASCII, "5", "%", "%" }, /* 34 5 */ + { FLG_ASCII, "6", "^", "\036" }, /* 35 6 */ + { FLG_ASCII, "7", "&", "&" }, /* 36 7 */ + { FLG_ASCII, "8", "*", "\010" }, /* 37 8 */ + { FLG_ASCII, "9", "(", "(" }, /* 38 9 */ + { FLG_ASCII, "0", ")", ")" }, /* 39 0 */ + + { FLG_ASCII, "\r", "\r", "\n" }, /* 40 ENT */ + { FLG_ASCII, "\033", "\033", "\033" }, /* 41 ESC */ + { FLG_ASCII, "\177", "\177", "\010" }, /* 42 <- */ + { FLG_ASCII, "\t", "\177\t", "\t" }, /* 43 ->| */ + { FLG_ASCII, " ", " ", "\000" }, /* 44 SPC */ + + { FLG_ASCII, "-", "_", "\037" }, /* 45 - */ + { FLG_ASCII, "=", "+", "+" }, /* 46 = */ + { FLG_ASCII, "[", "{", "\033" }, /* 47 [ */ + { FLG_ASCII, "]", "}", "\035" }, /* 48 ] */ + { FLG_ASCII, "\\", "|", "\034" }, /* 49 \ */ + + { FLG_NONE, "", "", "" }, /* 50 pound */ + + { FLG_ASCII, ";", ":", ";" }, /* 51 ; */ + { FLG_ASCII, "'", "\"", "'" }, /* 52 ' */ + { FLG_ASCII, "`", "~", "`" }, /* 53 ` */ + { FLG_ASCII, ",", "<", "<" }, /* 54 , */ + { FLG_ASCII, ".", ">", ">" }, /* 55 . */ + { FLG_ASCII, "/", "?", "\037" }, /* 56 / */ + { FLG_CAPS, "", "", "" }, /* 57 CAPS */ + + { FLG_FKEY, "\033[M", "\033[Y", "\033[k" }, /* 58 f1 */ + { FLG_FKEY, "\033[N", "\033[Z", "\033[l" }, /* 59 f2 */ + { FLG_FKEY, "\033[O", "\033[a", "\033[m" }, /* 60 f3 */ + { FLG_FKEY, "\033[P", "\033[b", "\033[n" }, /* 61 f4 */ + { FLG_FKEY, "\033[Q", "\033[c", "\033[o" }, /* 62 f5 */ + { FLG_FKEY, "\033[R", "\033[d", "\033[p" }, /* 63 f6 */ + { FLG_FKEY, "\033[S", "\033[e", "\033[q" }, /* 64 f7 */ + { FLG_FKEY, "\033[T", "\033[f", "\033[r" }, /* 65 f8 */ + { FLG_FKEY, "\033[U", "\033[g", "\033[s" }, /* 66 f9 */ + { FLG_FKEY, "\033[V", "\033[h", "\033[t" }, /* 67 f10 */ + { FLG_FKEY, "\033[W", "\033[i", "\033[u" }, /* 68 f11 */ + { FLG_FKEY, "\033[X", "\033[j", "\033[v" }, /* 69 f12 */ + + { FLG_NONE, "", "", "" }, /* 70 prtsc */ + { FLG_SCROLL, "", "", "" }, /* 71 SCRLK */ + { FLG_NONE, "", "", "" }, /* 72 pause */ + { FLG_NONE, "", "", "" }, /* 73 KPins */ + { FLG_NONE, "", "", "" }, /* 74 KPhome */ + { FLG_NONE, "", "", "" }, /* 75 KPpgup */ + { FLG_NONE, "", "", "" }, /* 76 KPdel */ + { FLG_NONE, "", "", "" }, /* 77 KPend */ + { FLG_NONE, "", "", "" }, /* 78 KPpgdn */ + + { FLG_FKEY, "\033[C", "", "" }, /* 79 KPright */ + { FLG_FKEY, "\033[D", "", "" }, /* 80 KPleft */ + { FLG_FKEY, "\033[B", "", "" }, /* 81 KPdown */ + { FLG_FKEY, "\033[A", "", "" }, /* 82 KPup */ + + { FLG_NUM, "", "", "" }, /* 83 NUMLK */ + { FLG_NKPD, "/", "/", "/" }, /* 84 KP/ */ + { FLG_NKPD, "*", "*", "*" }, /* 85 KP* */ + { FLG_NKPD, "-", "-", "-" }, /* 86 KP- */ + { FLG_NKPD, "+", "+", "+" }, /* 87 KP+ */ + { FLG_NKPD, "\r", "\r", "\n" }, /* 88 KPent */ + + { FLG_NKPD, "1", "\033[F", "1" }, /* 89 KP1 */ + { FLG_NKPD, "2", "\033[B", "2" }, /* 90 KP2 */ + { FLG_NKPD, "3", "\033[G", "3" }, /* 91 KP3 */ + { FLG_NKPD, "4", "\033[D", "4" }, /* 92 KP4 */ + { FLG_NKPD, "5", "\033[E", "5" }, /* 93 KP5 */ + { FLG_NKPD, "6", "\033[C", "6" }, /* 94 KP6 */ + { FLG_NKPD, "7", "\033[H", "7" }, /* 95 KP7 */ + { FLG_NKPD, "8", "\033[A", "8" }, /* 96 KP8 */ + { FLG_NKPD, "9", "\033[I", "9" }, /* 97 KP9 */ + { FLG_NKPD, "0", "\033[L", "0" }, /* 98 KP0 */ + + { FLG_NKPD, ".", "\177", "." }, /* 99 KP. */ + + { FLG_NONE, "", "", "" }, /* 100 non\ */ + +}; + +#define usbhid_scantablesize (sizeof(usbhid_scantable)/sizeof(keycode_t)) + + +/* ********************************************************************* + * usbhid_kbd_mod1(uhid) + * + * Process modifier key changes for the current USB event, + * which was stored in uhid_imsg. Basically all this does + * is update uhid_shiftflags, converting the bits into the ones + * we use in our keyboard table. + * + * Input parameters: + * uhid - the hid softc. + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhid_kbd_mod1(usbhid_softc_t *uhid) +{ + uint8_t changed; + uint8_t mod; + + /* + * See if anything changed. + */ + + changed = (uhid->uhid_imsg[UBR_KBD_MODS] ^ uhid->uhid_lastmsg[UBR_KBD_MODS]); + if (changed == 0) return; + + /* + * Something changed. Reflect changes in our local copy of the + * shift state. + */ + + mod = uhid->uhid_imsg[UBR_KBD_MODS]; + + uhid->uhid_shiftflags &= ~(FLG_SHIFT|FLG_ALT|FLG_CTRL); + + if (mod & (KBD_MOD_LCTRL|KBD_MOD_RCTRL)) uhid->uhid_shiftflags |= FLG_CTRL; + if (mod & (KBD_MOD_LSHIFT|KBD_MOD_RSHIFT)) uhid->uhid_shiftflags |= FLG_SHIFT; + if (mod & (KBD_MOD_LALT|KBD_MOD_RALT)) uhid->uhid_shiftflags |= FLG_ALT; +} + +/* ********************************************************************* + * usbhid_kbd_scan1(uhid,scan,breakflg) + * + * Handle a single keyboard event. Using the scan code, look up + * the key in the table and convert it to one or more characters + * for the keyboard event queue. + * + * Input parameters: + * uhid - the hid softc + * scan - scan code from keyboard report + * breakflg - true if key is being released, false if pressed + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhid_kbd_scan1(usbhid_softc_t *uhid,uint8_t scan,int breakflg) +{ + keycode_t *code = 0; + char *str; + + /* + * Check scan code for reality. + */ + + if (scan >= usbhid_scantablesize) return; + code = &usbhid_scantable[scan]; + + /* + * If the change is a toggle, handle the toggle. These + * keys also deal with the LEDs on the keyboard. + */ + + if (code->kc_type & (FLG_CAPS|FLG_SCROLL|FLG_NUM)) { + if (!breakflg) uhid->uhid_shiftflags ^= code->kc_type; +// if (ks->ks_setleds) { +// (*(ks->ks_setleds))(ks,ks->ks_shiftflags & (FLG_CAPS|FLG_SCROLL|FLG_NUM)); +// } + } + + /* + * Regular keys - just look up in table and + * queue the characters to the upper layers. + */ + + if (code->kc_type & (FLG_ASCII | FLG_FKEY | FLG_NKPD)) { + if (uhid->uhid_shiftflags & (FLG_SHIFT|FLG_CAPS)) str = code->kc_shifted; + else if (uhid->uhid_shiftflags & FLG_CTRL) str = code->kc_ctrl; + else str = code->kc_normal; + if (!breakflg) { +#if CFG_VGACONSOLE + while (*str) { + pcconsole_enqueue(*str++); + } +#else + printf("%s",str); +#endif +#ifndef _CFE_ + fflush(stdout); +#endif + } + } + +} + + +/* ********************************************************************* + * usbhid_kbd_scan(uhid) + * + * Main processing routine for keyboard report messages. Once + * we've determined that it is a keyboard mesage, we end up + * here. The work involves seeing what new keys have arrived + * in the list (presses), and which ones are no longer there + * (releases). To do this, we us the current and previous + * report structure. + * + * Input parameters: + * uhid - the hid softc + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhid_kbd_scan(usbhid_softc_t *uhid) +{ + int n,o; + + /* + * Modifier keys (shift, alt, control) + */ + + if (uhid->uhid_imsg[UBR_KBD_MODS] ^ uhid->uhid_lastmsg[UBR_KBD_MODS]) { + usbhid_kbd_mod1(uhid); + } + + /* + * "Make" codes (keys pressed down) + * Look for keys in 'uhid_imsg' that are not in 'uhid_lastmsg' + */ + + for (n = UBR_KBD_KEYS; n < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); n++) { + if (uhid->uhid_imsg[n] == 0) break; /* no more keys */ + for (o = UBR_KBD_KEYS; o < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); o++) { + if (uhid->uhid_imsg[n] == uhid->uhid_lastmsg[o]) break; + } + if (o == (UBR_KBD_KEYS + UBR_KBD_NUMKEYS)) { /* key not found, must be pressed */ + usbhid_kbd_scan1(uhid,uhid->uhid_imsg[n],0); + } + } + + /* + * "Break" codes (keys released) + * Look for keys in 'uhid_lastmsg' that are not in 'uhid_imsg' + */ + + + for (n = UBR_KBD_KEYS; n < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); n++) { + if (uhid->uhid_lastmsg[n] == 0) break; /* no more keys */ + for (o = UBR_KBD_KEYS; o < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); o++) { + if (uhid->uhid_lastmsg[n] == uhid->uhid_imsg[o]) break; + } + if (o == (UBR_KBD_KEYS + UBR_KBD_NUMKEYS)) { /* key not found, must be released */ + usbhid_kbd_scan1(uhid,uhid->uhid_lastmsg[n],1); + } + } +} + + +/* ********************************************************************* + * usbhid_ireq_callback(ur) + * + * This routine is called when our interrupt transfer completes + * and there is report data to be processed. + * + * Input parameters: + * ur - usb request + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbhid_ireq_callback(usbreq_t *ur) +{ + usbhid_softc_t *uhid = (ur->ur_dev->ud_private); + + /* + * If the driver is unloaded, the request will be cancelled. + */ + + if (ur->ur_status == 0xFF) { + usb_free_request(ur); + return 0; + } + + /* + * What we do now depends on the type of device. + */ + + switch (uhid->uhid_devtype) { + case HID_DEVTYPE_KBD: + /* + * Handle keyboard event + */ + usbhid_kbd_scan(uhid); + + /* + * Save old event to compare for next time. + */ + memcpy(uhid->uhid_lastmsg,uhid->uhid_imsg,8); + break; + + case HID_DEVTYPE_MOUSE: +#if 0 + /* + * No need to handle mice, but here's the good stuff. + */ + printf("Mouse: [%s %s %s] X:%d Y:%d Wheel:%d\n", + (ur->ur_buffer[0] & 1) ? "left" : "", + (ur->ur_buffer[0] & 4) ? "middle" : "", + (ur->ur_buffer[0] & 2) ? "right" : "", + (int)(signed char)ur->ur_buffer[1], + (int)(signed char)ur->ur_buffer[2], + (int)(signed char)ur->ur_buffer[3]); +#endif + break; + } + + /* + * Re-queue request to get next keyboard event. + */ + + usb_queue_request(ur); + + return 0; +} + + +/* ********************************************************************* + * usbhid_queue_intreq(dev,softc) + * + * Queue an interrupt request for this usb device. The + * driver will place this request on the queue that corresponds + * to the endpoint, and will call the callback routine when + * something happens. + * + * Input parameters: + * dev - usb device + * softc - the usb hid softc + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhid_queue_intreq(usbdev_t *dev,usbhid_softc_t *softc) +{ + usbreq_t *ur; + + ur = usb_make_request(dev, + softc->uhid_ipipe, + softc->uhid_imsg,softc->uhid_ipipemps, + UR_FLAG_IN); + + ur->ur_callback = usbhid_ireq_callback; + + usb_queue_request(ur); +} + + +/* ********************************************************************* + * usbhid_attach(dev,drv) + * + * This routine is called when the bus scan stuff finds a HID + * device. We finish up the initialization by configuring the + * device and allocating our softc here. + * + * Input parameters: + * dev - usb device, in the "addressed" state. + * drv - the driver table entry that matched + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbhid_attach(usbdev_t *dev,usb_driver_t *drv) +{ + usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; + usb_endpoint_descr_t *epdscr; + usb_interface_descr_t *ifdscr; + usbhid_softc_t *softc; + + dev->ud_drv = drv; + + softc = KMALLOC(sizeof(usbhid_softc_t),0); + memset(softc,0,sizeof(usbhid_softc_t)); + dev->ud_private = softc; + + epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,0); + ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); + + if (!epdscr || !ifdscr) { + /* + * Could not get descriptors, something is very wrong. + * Leave device addressed but not configured. + */ + return 0; + } + + /* + * Choose the standard configuration. + */ + + usb_set_configuration(dev,cfgdscr->bConfigurationValue); + + /* + * Set the protocol to the "boot" protocol, so we don't + * have to deal with fancy HID stuff. + */ + + usbhid_set_protocol(dev,HID_BOOT_PROTOCOL,ifdscr->bInterfaceNumber); + + /* + * Open the interrupt pipe. + */ + + softc->uhid_ipipe = usb_open_pipe(dev,epdscr); + softc->uhid_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize); + + /* + * Figure out the device type from the protocol. Keyboards, + * mice use this field to distinguish themselves. + */ + + softc->uhid_devtype = ifdscr->bInterfaceProtocol; + if (softc->uhid_devtype > HID_DEVTYPE_MAX) { + softc->uhid_devtype = HID_DEVTYPE_UNKNOWN; + } + + console_log("USBHID: %s Configured.\n", + usbhid_devtypes[softc->uhid_devtype]); + + /* + * Queue a transfer on the interrupt endpoint to catch + * our first characters. + */ + + usbhid_queue_intreq(dev,softc); + + return 0; +} + +/* ********************************************************************* + * usbhid_detach(dev) + * + * This routine is called when the bus scanner notices that + * this device has been removed from the system. We should + * do any cleanup that is required. The pending requests + * will be cancelled automagically. + * + * Input parameters: + * dev - usb device + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbhid_detach(usbdev_t *dev) +{ + return 0; +} + + + diff --git a/cfe/cfe/usb/usbhub.c b/cfe/cfe/usb/usbhub.c new file mode 100644 index 0000000..1e571ed --- /dev/null +++ b/cfe/cfe/usb/usbhub.c @@ -0,0 +1,912 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Hub and device discovery code File: usbhub.c + * + * This module deals with hubs and device discovery. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_ +#include +#include +#include +#include +#include "usbhack.h" +#else +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "cfe_console.h" +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" + +/* ********************************************************************* + * Macros for common hub requests + ********************************************************************* */ + +#define usbhub_set_port_feature(dev,port,feature) \ + usb_simple_request(dev,0x23,USB_HUBREQ_SET_FEATURE,feature,port) + +#define usbhub_set_hub_feature(dev,feature) \ + usb_simple_request(dev,0x20,USB_HUBREQ_SET_FEATURE,feature,0) + +#define usbhub_clear_port_feature(dev,port,feature) \ + usb_simple_request(dev,0x23,USB_HUBREQ_CLEAR_FEATURE,feature,port) + +#define usbhub_clear_hub_feature(dev,feature) \ + usb_simple_request(dev,0x20,USB_HUBREQ_CLEAR_FEATURE,feature,0) + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern int usb_noisy; + +/* ********************************************************************* + * Forward declarations + ********************************************************************* */ + +static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv); +static int usbhub_detach(usbdev_t *dev); + +/* ********************************************************************* + * Hub-specific data structures + ********************************************************************* */ + +#define UHUB_MAX_DEVICES 8 + +#define UHUB_FLG_NEEDSCAN 1 + +typedef struct usbhub_softc_s { + usb_hub_descr_t uhub_descr; + usb_hub_status_t uhub_status; + int uhub_ipipe; + int uhub_ipipemps; + int uhub_nports; + unsigned int uhub_flags; + uint8_t uhub_imsg[8]; + usbdev_t *uhub_devices[UHUB_MAX_DEVICES]; +} usbhub_softc_t; + +usb_driver_t usbhub_driver = { + "USB Hub", + usbhub_attach, + usbhub_detach +}; + + +/* ********************************************************************* + * usbhub_ireq_callback(ur) + * + * this routine is called when the transfer we queued to the + * interrupt endpoint on the hub completes. It means that + * *some* port on the hub needs attention. The data indicates + * which port, but for our purposes we don't really care - if + * we get this callback, we'll set a flag and re-probe the bus. + * + * Input parameters: + * ur - usbreq that completed + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbhub_ireq_callback(usbreq_t *ur) +{ + int idx; + usbhub_softc_t *uhub = (ur->ur_dev->ud_private); + + /* + * Check to see if the request was cancelled by someone + * deleting our endpoint. + */ + + if (ur->ur_status == 0xFF) { + usb_free_request(ur); + return 0; + } + + /* + * Check to see if any of our ports need attention + */ + + for (idx = 1; idx <= uhub->uhub_nports; idx++) { + if (ur->ur_buffer[0] & (1<uhub_flags |= UHUB_FLG_NEEDSCAN; + ur->ur_dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN; + } + } + + + /* + * Do NOT requeue the request here. We will do this + * during exploration. + */ + + usb_free_request(ur); + + return 0; +} + + +/* ********************************************************************* + * usbhub_get_hub_descriptor(dev,dscr,idx,maxlen) + * + * Obtain the hub descriptor (special for hubs) from the + * device. + * + * Input parameters: + * dev - usb device + * dscr - place to put hub descriptor + * idx - which hub descriptor to get (usually zero) + * maxlen - max # of bytes to return + * + * Return value: + * # of bytes returned + ********************************************************************* */ + +static int usbhub_get_hub_descriptor(usbdev_t *dev,usb_hub_descr_t *dscr,int idx,int maxlen) +{ + return usb_std_request(dev,0xA0, + USB_HUBREQ_GET_DESCRIPTOR, + 0,0, + (uint8_t *) dscr, + maxlen); +} + + +/* ********************************************************************* + * usbhub_get_hub_status(dev,status) + * + * Obtain the hub status (special for hubs) from the + * device. + * + * Input parameters: + * dev - usb device + * status - where to put hub status structure + * + * Return value: + * # of bytes returned + ********************************************************************* */ + +#if 0 +static int usbhub_get_hub_status(usbdev_t *dev,usb_hub_status_t *status) +{ + return usb_std_request(dev, + 0xA0, + 0x00, + 0, + 0, + (uint8_t *) status, + sizeof(usbhub_status_t)); +} +#endif + + +/* ********************************************************************* + * usbhub_get_port_status(dev,port,status) + * + * Obtain the port status for a particular port from + * device. + * + * Input parameters: + * dev - usb device + * port - 1-based port number + * status - where to put port status structure + * + * Return value: + * # of bytes returned + ********************************************************************* */ + +static int usbhub_get_port_status(usbdev_t *dev,int port,usb_port_status_t *status) +{ + return usb_std_request(dev, + 0xA3, + 0, + 0, + port, + (uint8_t *) status, + sizeof(usb_port_status_t)); +} + + +/* ********************************************************************* + * usbhub_queue_intreq(dev,softc) + * + * Queue the transfer to the interrupt pipe that will catch + * the hub's port status changes + * + * Input parameters: + * dev - usb device + * softc - hub-specific data + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhub_queue_intreq(usbdev_t *dev,usbhub_softc_t *softc) +{ + usbreq_t *ur; + + ur = usb_make_request(dev, + softc->uhub_ipipe, + softc->uhub_imsg,softc->uhub_ipipemps, + UR_FLAG_IN | UR_FLAG_SHORTOK); + + ur->ur_callback = usbhub_ireq_callback; + + usb_queue_request(ur); +} + + +/* ********************************************************************* + * usbhub_attach(dev,drv) + * + * This routine is called when the hub attaches to the system. + * We complete initialization for the hub and set things up so + * that an explore will happen soon. + * + * Input parameters: + * dev - usb device + * drv - driver structure + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv) +{ + usb_device_status_t devstatus; + usb_config_descr_t *cfgdscr; + usb_interface_descr_t *ifdscr; + usb_endpoint_descr_t *epdscr; + usbhub_softc_t *softc; + + /* + * Remember the driver dispatch. + */ + + dev->ud_drv = drv; + + softc = KMALLOC(sizeof(usbhub_softc_t),0); + memset(softc,0,sizeof(usbhub_softc_t)); + dev->ud_private = softc; + + /* + * Dig out the data from the configuration descriptor + * (we got this from the device before attach time) + */ + + cfgdscr = dev->ud_cfgdescr; + epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,0); + ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); + + /* + * Get device status (is this really necessary?) + */ + + usb_get_device_status(dev,&devstatus); + + /* + * Set us to configuration index 0 + */ + + usb_set_configuration(dev,cfgdscr->bConfigurationValue); + + /* + * Get the hub descriptor. Get the first 8 bytes first, then get the rest + * if there is more. + */ + + if (usbhub_get_hub_descriptor(dev,&(softc->uhub_descr),0,USB_HUB_DESCR_SIZE) > USB_HUB_DESCR_SIZE) { + usbhub_get_hub_descriptor(dev,&(softc->uhub_descr),0,softc->uhub_descr.bDescriptorLength); + } + + /* + * remember stuff from the hub descriptor + */ + + softc->uhub_nports = softc->uhub_descr.bNumberOfPorts; + + /* + * Open the interrupt pipe + */ + + softc->uhub_ipipe = usb_open_pipe(dev,epdscr); + softc->uhub_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize); + + /* + * Mark the bus and the hub as needing service. + */ + + softc->uhub_flags |= UHUB_FLG_NEEDSCAN; + dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN; + + /* + * Okay, that's it. The top-level USB daemon will notice + * that the bus needs service and will invoke the exploration code. + * This may in turn require additional explores until + * everything settles down. + */ + + return 0; +} + + +/* ********************************************************************* + * usbhub_detach(dev) + * + * Called when a hub is removed from the system - we remove + * all subordinate devicees. + * + * Input parameters: + * dev - device (hub) that was removed + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbhub_detach(usbdev_t *dev) +{ + usbhub_softc_t *hub; + usbdev_t *deldev; + int idx; + + if (!IS_HUB(dev)) return 0; /* should not happen */ + + hub = dev->ud_private; + for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) { + deldev = hub->uhub_devices[idx]; + if (deldev) { + console_log("USB: Removing device attached to bus %d hub %d port %d", + dev->ud_bus->ub_num, + dev->ud_address,idx+1); + if (deldev->ud_drv) { + (*(deldev->ud_drv->udrv_detach))(deldev); + } + else { + if (usb_noisy > 0) { + console_log("USB: Detached device on bus %d hub %d port %d " + "has no methods", + dev->ud_bus->ub_num, + dev->ud_address,idx+1); + } + } + if (deldev->ud_cfgdescr) KFREE(deldev->ud_cfgdescr); + usb_destroy_device(deldev); + } + } + + KFREE(hub); /* remove softc */ + + return 0; +} + + + +/* ********************************************************************* + * usbhub_map_tree1(dev,level,func,arg) + * + * This routine is used in recursive device tree exploration. + * We call 'func' for each device at this tree, and descend + * when we run into hubs + * + * Input parameters: + * dev - current device pointer + * level - current nesting level + * func - function to call + * arg - argument to pass to function + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhub_map_tree1(usbdev_t *dev,int level, + int (*func)(usbdev_t *dev,void *arg),void *arg) +{ + usbhub_softc_t *hub; + int idx; + + (*func)(dev,arg); + + if (IS_HUB(dev)) { + hub = dev->ud_private; + for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) { + if (hub->uhub_devices[idx]) { + usbhub_map_tree1(hub->uhub_devices[idx],level+1,func,arg); + } + } + } +} + +/* ********************************************************************* + * usbhub_map_tree(bus,func,arg) + * + * Call a function for each device in the tree + * + * Input parameters: + * bus - bus to scan + * func - function to call + * arg - argument to pass to function + * + * Return value: + * nothing + ********************************************************************* */ + +void usbhub_map_tree(usbbus_t *bus,int (*func)(usbdev_t *dev,void *arg),void *arg) +{ + usbhub_map_tree1(bus->ub_roothub,0,func,arg); +} + + +/* ********************************************************************* + * usbhub_dumpbus1(dev,arg) + * + * map function to dump devices in the device tree + * + * Input parameters: + * dev - device we're working on + * arg - argument from map_tree call + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbhub_dumpbus1(usbdev_t *dev,void *arg) +{ + uint32_t *verbose = (uint32_t *) arg; + + if ((*verbose & 0x00FF) && (dev->ud_address != (*verbose & 0x00FF))) return 0; + + if (*verbose & 0x100) { + printf("============================================================================\n"); + } + + printf("Bus %d Device %d Class %d Vendor %04X Product %04X ", + dev->ud_bus->ub_num, + dev->ud_address, + dev->ud_devdescr.bDeviceClass, + GETUSBFIELD(&(dev->ud_devdescr),idVendor), + GETUSBFIELD(&(dev->ud_devdescr),idProduct)); + + + if (IS_HUB(dev)) { + printf("[HUB]\n"); + } + else { + printf("[DEVICE]\n"); + } + + if (*verbose & 0x100) { + usb_dbg_dumpdescriptors(dev,(uint8_t *) &(dev->ud_devdescr),dev->ud_devdescr.bLength); + usb_dbg_dumpcfgdescr(dev); + } + + return 0; +} + + +/* ********************************************************************* + * usbhub_dumpbus(bus,verbose) + * + * Dump information about devices on the USB bus. + * + * Input parameters: + * bus - bus to dump + * verbose - nonzero to display more info, like descriptors + * + * Return value: + * nothing + ********************************************************************* */ + +void usbhub_dumpbus(usbbus_t *bus,uint32_t verbose) +{ + usbhub_map_tree(bus,usbhub_dumpbus1,&verbose); +} + + + +/* ********************************************************************* + * usbhub_reset_devicee(dev,port,status) + * + * Reset a device on a hub port. This routine does a + * USB_PORT_FEATURE_RESET on the specified port, waits for the + * bit to clear, and returns. It is used to get a device into the + * DEFAULT state according to the spec. + * + * Input parameters: + * dev - hub device + * port - port number(1-based) + * status - place to return port_status structure after + * reset completes + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhub_reset_device(usbdev_t *dev,int port,usb_port_status_t *portstatus) +{ + console_log("USB: Resetting device on bus %d port %d",dev->ud_bus->ub_num,port); +#ifndef _CFE_ + fflush(stdout); +#endif + + usbhub_set_port_feature(dev,port,USB_PORT_FEATURE_RESET); + + usbhub_get_port_status(dev,port,portstatus); + + for (;;) { + usbhub_get_port_status(dev,port,portstatus); + if ((GETUSBFIELD((portstatus),wPortStatus) & USB_PORT_STATUS_RESET) == 0) break; + usb_delay_ms(dev->ud_bus,250); + } + usb_delay_ms(dev->ud_bus,250); + + usbhub_clear_port_feature(dev,port,USB_PORT_FEATURE_C_PORT_RESET); +} + + + +/* ********************************************************************* + * usbhub_scan_ports(dev,arg) + * + * Scan the ports on this hub for new or removed devices. + * + * Input parameters: + * dev - hub device + * arg - passed from bus scan main routines + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbhub_scan_ports(usbdev_t *dev,void *arg) +{ + uint16_t current; + uint16_t changed; + usbhub_softc_t *softc; + int idx; + int res; + int len; + uint8_t *buf; + usbdev_t *newdev; + usb_driver_t *newdrv; + int addr; + usb_port_status_t portstatus; + usb_config_descr_t cfgdescr; + unsigned int powerondelay; + + if (!IS_HUB(dev)) return; /* should not happen. */ + + /* + * We know this is a hub. Get the softc back. + */ + + softc = (usbhub_softc_t *) dev->ud_private; + + powerondelay = ((unsigned int) softc->uhub_descr.bPowerOnToPowerGood)*2 + 20; + + /* + * Turn on the power to the ports whose power is not yet on. + */ + + for (idx = 0; idx < softc->uhub_nports; idx++) { + + usbhub_get_port_status(dev,idx+1,&portstatus); + + current = GETUSBFIELD((&portstatus),wPortStatus); + changed = GETUSBFIELD((&portstatus),wPortChange); + if (usb_noisy > 1) { + printf("BeforePowerup: port %d status %04X changed %04X\n",idx+1,current,changed); + } + + if (!(current & USB_PORT_STATUS_POWER)) { + if (usb_noisy > 1) console_log("USB: Powering up bus %d port %d", + dev->ud_bus->ub_num,idx+1); + usbhub_set_port_feature(dev,idx+1,USB_PORT_FEATURE_POWER); + usb_delay_ms(dev->ud_bus,powerondelay); + } + } + + /* + * Begin exploration at this level. + */ + + for (idx = 0; idx < softc->uhub_nports; idx++) { + + usbhub_get_port_status(dev,idx+1,&portstatus); + + current = GETUSBFIELD((&portstatus),wPortStatus); + changed = GETUSBFIELD((&portstatus),wPortChange); + + if (usb_noisy > 0) { + printf("USB: Explore: Bus %d Hub %d port %d status %04X changed %04X\n", + dev->ud_bus->ub_num, + dev->ud_address,idx+1,current,changed); + usb_dbg_dumpportstatus(idx+1,&portstatus,1); + } + + +// if (changed & USB_PORT_STATUS_RESET) { +// usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_RESET); +// } + + if (changed & USB_PORT_STATUS_ENABLED) { + usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_ENABLE); + } + + if (changed & USB_PORT_STATUS_CONNECT) { + /* + * A device was either connected or disconnected. + * Clear the status change first. + */ + + usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_CONNECTION); + + if (current & USB_PORT_STATUS_CONNECT) { + + /* + * The device has been CONNECTED. + */ + + console_log("USB: New device connected to bus %d hub %d port %d", + dev->ud_bus->ub_num, + dev->ud_address,idx+1); + + /* + * Reset the device. Reuse our old port status structure + * so we get the latest status. Some devices do not report + * lowspeed until they are reset. + */ + + usbhub_reset_device(dev,idx+1,&portstatus); + current = GETUSBFIELD((&portstatus),wPortStatus); + changed = GETUSBFIELD((&portstatus),wPortChange); + + /* + * Create a device for this port. + */ + + newdev = usb_create_device(dev->ud_bus,(current & USB_PORT_STATUS_LOWSPD) ? 1 : 0); + + /* + * Get the device descriptor. + */ + + res = usb_get_device_descriptor(newdev,&(newdev->ud_devdescr),TRUE); + + if (usb_noisy > 0) usb_dbg_dumpdescriptors(newdev,(uint8_t *) &(newdev->ud_devdescr),8); + + /* + * Set up the max packet size for the control endpoint, + * then get the rest of the descriptor. + */ + + usb_set_ep0mps(newdev,newdev->ud_devdescr.bMaxPacketSize0); + res = usb_get_device_descriptor(newdev,&(newdev->ud_devdescr),FALSE); + + /* + * Obtain a new address and set the address of the + * root hub to this address. + */ + + addr = usb_new_address(newdev->ud_bus); + res = usb_set_address(newdev,addr); + + /* + * Get the configuration descriptor and all the + * associated interface and endpoint descriptors. + */ + + res = usb_get_config_descriptor(newdev,&cfgdescr,0, + sizeof(usb_config_descr_t)); + if (res != sizeof(usb_config_descr_t)) { + printf("[a]usb_get_config_descriptor returns %d\n",res); + } + + len = GETUSBFIELD(&cfgdescr,wTotalLength); + buf = KMALLOC(len,0); + + res = usb_get_config_descriptor(newdev,(usb_config_descr_t *)buf,0,len); + if (res != len) { + printf("[b]usb_get_config_descriptor returns %d\n",res); + } + + newdev->ud_cfgdescr = (usb_config_descr_t *) buf; + + if (usb_noisy > 0) usb_dbg_dumpdescriptors(newdev,buf,len); + + /* + * Point the hub at the devices it owns + */ + + softc->uhub_devices[idx] = newdev; + + /* + * Find the driver for this. It had better be the hub + * driver. + */ + + newdrv = usb_find_driver(newdev); + + /* + * Call the attach method. + */ + + if (newdrv) { + dev->ud_drv = newdrv; /* remember driver dispatch in device */ + (*(newdrv->udrv_attach))(newdev,newdrv); + } + } + + else { + + /* + * The device has been DISCONNECTED. + */ + + console_log("USB: Device disconnected from bus %d hub %d port %d", + dev->ud_bus->ub_num, + dev->ud_address,idx+1); + + /* + * Recover pointer to device below hub and clear + * this pointer. + */ + + newdev = softc->uhub_devices[idx]; /* Get device pointer */ + softc->uhub_devices[idx] = NULL; /* remove device from hub */ + + /* + * Deassign the USB device's address and then + * call detach method to free resources. Devices that + * do not have drivers will not have any methods. + */ + + if (newdev) { + if (newdev->ud_drv) { + (*(newdev->ud_drv->udrv_detach))(newdev); + } + else { + if (usb_noisy > 0) { + console_log("USB: Detached device on bus %d hub %d port %d " + "has no methods", + dev->ud_bus->ub_num, + dev->ud_address,idx+1); + } + } + + if (newdev->ud_cfgdescr) KFREE(newdev->ud_cfgdescr); + + usb_destroy_device(newdev); + } + + } + } + + } + + + /* + * Queue up a request for the interrupt pipe. This will catch further + * changes at this port. + */ + + usbhub_queue_intreq(dev,softc); + +} + +/* ********************************************************************* + * usbhub_scan1(dev,arg) + * + * Scan one device at this level, or descend if we run into a hub + * This is part of the device discovery code. + * + * Input parameters: + * dev - current device, maybe a hub + * arg - passed from main scan routine + * + * Return value: + * 0 + ********************************************************************* */ + + +static int usbhub_scan1(usbdev_t *dev,void *arg) +{ + usbhub_softc_t *hub; + + /* + * If the device is not a hub, we've reached the leaves of the + * tree. + */ + + if (!IS_HUB(dev)) return 0; + + /* + * Otherwise, scan the ports on this hub. + */ + + hub = dev->ud_private; + + if (hub->uhub_flags & UHUB_FLG_NEEDSCAN) { + hub->uhub_flags &= ~UHUB_FLG_NEEDSCAN; + usbhub_scan_ports(dev,arg); + } + + return 0; +} + +/* ********************************************************************* + * usb_scan(bus) + * + * Scan the bus looking for new or removed devices + * + * Input parameters: + * bus - bus to scan + * + * Return value: + * nothing + ********************************************************************* */ + +void usb_scan(usbbus_t *bus) +{ + /* + * Call our tree walker with the scan function. + */ + + usbhub_map_tree(bus,usbhub_scan1,NULL); +} + + + + diff --git a/cfe/cfe/usb/usbmain.c b/cfe/cfe/usb/usbmain.c new file mode 100644 index 0000000..c39a7f6 --- /dev/null +++ b/cfe/cfe/usb/usbmain.c @@ -0,0 +1,367 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Main Module File: usbmain.c + * + * Main module that invokes the top of the USB stack from CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "lib_queue.h" +#include "lib_physio.h" + +#include "cfe_timer.h" +#include "ui_command.h" + +#if CFG_PCI +#include "pcireg.h" +#include "pcivar.h" +#endif + +#include "usbchap9.h" +#include "usbd.h" + +#include "bsp_config.h" + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern usb_hcdrv_t ohci_driver; /* OHCI Driver dispatch */ + +extern int ohcidebug; /* OHCI debug control */ +extern int usb_noisy; /* USBD debug control */ + +int usb_init(void); /* forward */ +int ui_init_usbcmds(void); /* forward */ + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +/* + * We keep track of the pointers to USB buses in globals. + * One entry in this array per USB bus (the Opti controller + * on the SWARM has two functions, so it's two buses) + */ + +#define USB_MAX_BUS 4 +int usb_buscnt = 0; +usbbus_t *usb_buses[USB_MAX_BUS]; + + +/* ********************************************************************* + * usb_cfe_timer(arg) + * + * This routine is called periodically by CFE's timer routines + * to give the USB subsystem some time. Basically we scan + * for work to do to manage configuration updates, and handle + * interrupts from the USB controllers. + * + * Input parameters: + * arg - value we passed when the timer was initialized + * (not used) + * + * Return value: + * nothing + ********************************************************************* */ + +static void usb_cfe_timer(void *arg) +{ + int idx; + static int in_poll = 0; + + /* + * We sometimes call the timer routines in here, which calls + * the polling loop. This code is not reentrant, so + * prevent us from running the interrupt routine or + * bus daemon while we are already in there. + */ + + if (in_poll) return; + + /* + * Do not allow nested "interrupts." + */ + + in_poll = 1; + + for (idx = 0; idx < usb_buscnt; idx++) { + if (usb_buses[idx]) { + usb_poll(usb_buses[idx]); + usb_daemon(usb_buses[idx]); + } + } + + /* + * Okay to call polling again. + */ + + in_poll = 0; +} + + +/* ********************************************************************* + * usb_init_one_ohci(addr) + * + * Initialize one USB controller. + * + * Input parameters: + * addr - physical address of OHCI registers + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ +static int usb_init_one_ohci(uint32_t addr) +{ + usbbus_t *bus; + int res; + + bus = UBCREATE(&ohci_driver, addr); + + if (bus == NULL) { + printf("USB: Could not create OHCI driver structure for controller at 0x%08X\n",addr); + return -1; + } + + bus->ub_num = usb_buscnt; + + res = UBSTART(bus); + + if (res != 0) { + printf("USB: Could not init OHCI controller at 0x%08X\n",addr); + UBSTOP(bus); + return -1; + } + else { + usb_buses[usb_buscnt++] = bus; + usb_initroot(bus); + } + + return 0; +} + +#if CFG_PCI +/* ********************************************************************* + * usb_init_pci_ohci() + * + * Initialize all PCI-based OHCI controllers + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ +static int usb_init_pci_ohci(void) +{ + int res; + pcitag_t tag; + uint32_t pciclass; + physaddr_t bar; + int idx; + + idx = 0; + + while (pci_find_class(PCI_CLASS_SERIALBUS,idx,&tag) == 0) { + pciclass = pci_conf_read(tag,PCI_CLASS_REG); + if ((PCI_SUBCLASS(pciclass) == PCI_SUBCLASS_SERIALBUS_USB) && + (PCI_INTERFACE(pciclass) == 0x10)) { + bar = (physaddr_t) pci_conf_read(tag,PCI_MAPREG_START); + pci_tagprintf(tag,"OHCI USB controller found at %08X\n",(uint32_t) bar); + + /* On the BCM1250, this sets the address to "match bits" mode, + which eliminates the need for byte swaps of data to/from the registers. */ + bar |= 0x20000000; + + res = usb_init_one_ohci(bar); + if (res < 0) break; + } + idx++; + } + + return 0; +} +#endif + + + +/* ********************************************************************* + * usb_init() + * + * Initialize the USB subsystem + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int usb_init(void) +{ + static int initdone = 0; + + if (initdone) { + printf("USB has already been initialized.\n"); + return -1; + } + + printf("Initializing USB.\n"); + + initdone = 1; + + usb_buscnt = 0; + +#if CFG_PCI + usb_init_pci_ohci(); +#endif + +#if CFG_USB_OHCI_BASE + usb_init_one_ohci(CFG_USB_OHCI_BASE); +#endif + + cfe_bg_add(usb_cfe_timer,NULL); + + return 0; +} + + + +static int ui_cmd_usb_start(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int res = 0; + + if (cmd_sw_isset(cmd,"-o")) ohcidebug++; + if (cmd_sw_isset(cmd,"-oo")) ohcidebug+=2; + if (cmd_sw_isset(cmd,"-u")) usb_noisy++; + if (cmd_sw_isset(cmd,"-uu")) usb_noisy+=2; + + if (usb_buscnt == 0) { + res = usb_init(); + } + + return res; +} + + +static int ui_cmd_usb_show(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int busnum; + int devnum; + char *x; + int idx; + uint32_t arg; + + x = cmd_getarg(cmd,1); + if (!x) devnum = 0; + else devnum = atoi(x); + + x = cmd_getarg(cmd,0); + if (!x) x = "*"; + busnum = atoi(x); + + if (busnum >= usb_buscnt) { + printf("Invalid bus number, %d USB Buses currently configured.\n",usb_buscnt); + return -1; + } + + arg = cmd_sw_isset(cmd,"-v") ? 0x100 : 0; + arg |= (devnum & 0xFF); + + if (x[0] == '*') { + for (idx = 0; idx < usb_buscnt; idx++) { + usbhub_dumpbus(usb_buses[idx],arg); + } + } + else { + usbhub_dumpbus(usb_buses[busnum],arg); + } + + return 0; + +} + +/* ********************************************************************* + * ui_init_usbcmds(void) + * + * Initialize the USB commands + * + * Input parameters: + * nothing + * + * Return value: + * 0 + ********************************************************************* */ + +int ui_init_usbcmds(void) +{ + cmd_addcmd("usb init", + ui_cmd_usb_start, + NULL, + "Initialize the USB controller.", + "usb init", + "-o;OHCI debug messages|" + "-oo;more OHCI debug messages|" + "-u;USBD debug messages|" + "-uu;more USBD debug messages"); + + + cmd_addcmd("show usb", + ui_cmd_usb_show, + NULL, + "Display devices connected to USB bus.", + "usb show [bus [device]]\n\n" + "Displays the configuration descriptors for devices connected to the USB\n" + "If you specify a bus, the entire bus is displayed. If you specify the\n" + "device number as well, only the specified device is displayed\n", + "-v;Display descriptors from the devices"); + + return 0; +} diff --git a/cfe/cfe/usb/usbmass.c b/cfe/cfe/usb/usbmass.c new file mode 100644 index 0000000..ae3856d --- /dev/null +++ b/cfe/cfe/usb/usbmass.c @@ -0,0 +1,1199 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Mass-Storage driver File: usbmass.c + * + * This driver deals with mass-storage devices that support + * the SCSI Transparent command set and USB Bulk-Only protocol + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_ +#include +#include +#include +#include +#include "usbhack.h" +#else +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "cfe_timer.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_error.h" +#include "cfe_console.h" +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" + +/* ********************************************************************* + * USB Mass-Storage class Constants + ********************************************************************* */ + +#define USBMASS_CBI_PROTOCOL 0 +#define USBMASS_CBI_NOCOMPLETE_PROTOCOL 1 +#define USBMASS_BULKONLY_PROTOCOL 0x50 + +#define USBMASS_SUBCLASS_RBC 0x01 +#define USBMASS_SUBCLASS_SFF8020 0x02 +#define USBMASS_SUBCLASS_QIC157 0x03 +#define USBMASS_SUBCLASS_UFI 0x04 +#define USBMASS_SUBCLASS_SFF8070 0x05 +#define USBMASS_SUBCLASS_SCSI 0x06 + +#define USBMASS_CSW_PASS 0x00 +#define USBMASS_CSW_FAILED 0x01 +#define USBMASS_CSW_PHASEERR 0x02 + +#define USBMASS_CBW_SIGNATURE 0x43425355 +#define USBMASS_CSW_SIGNATURE 0x53425355 + +/* ********************************************************************* + * USB Mass-Storage class Structures + ********************************************************************* */ + +typedef struct usbmass_cbw_s { + uint8_t dCBWSignature0,dCBWSignature1,dCBWSignature2,dCBWSignature3; + uint8_t dCBWTag0,dCBWTag1,dCBWTag2,dCBWTag3; + uint8_t dCBWDataTransferLength0,dCBWDataTransferLength1, + dCBWDataTransferLength2,dCBWDataTransferLength3; + uint8_t bmCBWFlags; + uint8_t bCBWLUN; + uint8_t bCBWCBLength; + uint8_t CBWCB[16]; +} usbmass_cbw_t; + +typedef struct usbmass_csw_s { + uint8_t dCSWSignature0,dCSWSignature1,dCSWSignature2,dCSWSignature3; + uint8_t dCSWTag0,dCSWTag1,dCSWTag2,dCSWTag3; + uint8_t dCSWDataResidue0,dCSWDataResidue1,dCSWDataResidue2,dCSWDataResidue3; + uint8_t bCSWStatus; +} usbmass_csw_t; + +#define GETCBWFIELD(s,f) ((uint32_t)((s)->f##0) | ((uint32_t)((s)->f##1) << 8) | \ + ((uint32_t)((s)->f##2) << 16) | ((uint32_t)((s)->f##3) << 24)) +#define PUTCBWFIELD(s,f,v) (s)->f##0 = (v & 0xFF); \ + (s)->f##1 = ((v)>>8 & 0xFF); \ + (s)->f##2 = ((v)>>16 & 0xFF); \ + (s)->f##3 = ((v)>>24 & 0xFF); + + +int usbmass_request_sense(usbdev_t *dev); + +/* ********************************************************************* + * Linkage to CFE + ********************************************************************* */ + +#ifdef _CFE_ + +/* + * Softc for the CFE side of the disk driver. + */ +#define MAX_SECTORSIZE 2048 +typedef struct usbdisk_s { + uint32_t usbdisk_sectorsize; + uint32_t usbdisk_ttlsect; + uint32_t usbdisk_devtype; + int usbdisk_unit; +} usbdisk_t; + +/* + * This table points at the currently configured USB disk + * devices. This lets us leave the CFE half of the driver lying + * around while the USB devices come and go. We use the unit number + * from the original CFE attach to index this table, and devices + * that are not present are "not ready." + */ + +#define USBDISK_MAXUNITS 4 +static usbdev_t *usbdisk_units[USBDISK_MAXUNITS]; + +/* + * CFE device driver routine forwards + */ + +static void usbdisk_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +static int usbdisk_open(cfe_devctx_t *ctx); +static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int usbdisk_close(cfe_devctx_t *ctx); + +/* + * CFE device driver descriptor + */ + +const static cfe_devdisp_t usbdisk_dispatch = { + usbdisk_open, + usbdisk_read, + usbdisk_inpstat, + usbdisk_write, + usbdisk_ioctl, + usbdisk_close, + NULL, + NULL +}; + +const cfe_driver_t usb_disk = { + "USB Disk", + "usbdisk", + CFE_DEV_DISK, + &usbdisk_dispatch, + usbdisk_probe +}; + + +#endif + + + +/* ********************************************************************* + * Forward Definitions + ********************************************************************* */ + +static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv); +static int usbmass_detach(usbdev_t *dev); + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct usbmass_softc_s { + int umass_inpipe; + int umass_outpipe; + int umass_devtype; + uint32_t umass_curtag; + int umass_unit; +} usbmass_softc_t; + +usb_driver_t usbmass_driver = { + "Mass-Storage Device", + usbmass_attach, + usbmass_detach +}; + +usbdev_t *usbmass_dev = NULL; /* XX hack for testing only */ + +/* ********************************************************************* + * usbmass_mass_storage_reset(dev,ifc) + * + * Do a bulk-only mass-storage reset. + * + * Input parameters: + * dev - device to reset + * ifc - interface number to reset (bInterfaceNum) + * + * Return value: + * status + ********************************************************************* */ + +#define usbmass_mass_storage_reset(dev,ifc) \ + usb_simple_request(dev,0x21,0xFF,ifc,0) + +#if 0 +/* ********************************************************************* + * usbmass_get_max_lun(dev,lunp) + * + * Get maximum LUN from device + * + * Input parameters: + * dev - device to reset + * lunp - pointer to int to receive max lun + * + * Return value: + * status + ********************************************************************* */ + +static int usbmass_get_max_lun(usbdev_t *dev,int *lunp) +{ + uint8_t buf = 0; + int res; + + res = usb_std_request(dev,0xA1,0xFE,0,0,&buf,1); + + if (res < 0) return res; + + if (lunp) *lunp = (int) buf; + return 0; +} + +#endif + + +/* ********************************************************************* + * usbmass_stall_recovery(dev) + * + * Do whatever it takes to unstick a stalled mass-storage device. + * + * Input parameters: + * dev - usb device + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbmass_stall_recovery(usbdev_t *dev) +{ + usbmass_softc_t *softc; + + softc = (usbmass_softc_t *) dev->ud_private; + + usb_clear_stall(dev,softc->umass_inpipe); + + usbmass_request_sense(dev); +} + + +/* ********************************************************************* + * usbmass_read_capacity(dev,sectornum,buffer) + * + * Reads a sector from the device. + * + * Input parameters: + * dev - usb device + * sectornum - sector number to read + * buffer - place to put sector we read + * + * Return value: + * status + ********************************************************************* */ + +int usbmass_request_sense(usbdev_t *dev) +{ + uint8_t *cbwcsw; + uint8_t *sector; + usbmass_cbw_t *cbw; + usbmass_csw_t *csw; + usbreq_t *ur; + usbmass_softc_t *softc; + int res; + + softc = (usbmass_softc_t *) dev->ud_private; + + cbwcsw = KMALLOC(64,32); + sector = KMALLOC(64,32); + + memset(sector,0,64); + + cbw = (usbmass_cbw_t *) cbwcsw; + csw = (usbmass_csw_t *) cbwcsw; + + /* + * Fill in the fields of the CBW + */ + + PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); + PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); + PUTCBWFIELD(cbw,dCBWDataTransferLength,18); + cbw->bmCBWFlags = 0x80; /* IN */ + cbw->bCBWLUN = 0; + cbw->bCBWCBLength = 12; + cbw->CBWCB[0] = 0x3; /* REQUEST SENSE */ + cbw->CBWCB[1] = 0; + cbw->CBWCB[2] = 0; + cbw->CBWCB[3] = 0; + cbw->CBWCB[4] = 18; /* allocation length */ + cbw->CBWCB[5] = 0; + cbw->CBWCB[6] = 0; + cbw->CBWCB[7] = 0; + cbw->CBWCB[8] = 0; + cbw->CBWCB[9] = 0; + + softc->umass_curtag++; + + /* + * Send the CBW + */ + + ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, + sizeof(usbmass_cbw_t),UR_FLAG_OUT); + res = usb_sync_request(ur); + usb_free_request(ur); + + /* + * Get the data + */ + + memset(sector,0,18); + ur = usb_make_request(dev,softc->umass_inpipe,sector, + 18,UR_FLAG_IN | UR_FLAG_SHORTOK); + res = usb_sync_request(ur); + usb_free_request(ur); + + /* + * Get the Status + */ + + memset(csw,0,sizeof(usbmass_csw_t)); + ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, + sizeof(usbmass_csw_t),UR_FLAG_IN); + res = usb_sync_request(ur); + usb_free_request(ur); + + KFREE(cbwcsw); + + KFREE(sector); + + return 0; + +} + +/* ********************************************************************* + * usbmass_read_sector(dev,sectornum,seccnt,buffer) + * + * Reads a sector from the device. + * + * Input parameters: + * dev - usb device + * sectornum - sector number to read + * seccnt - count of sectors to read + * buffer - place to put sector we read + * + * Return value: + * status + ********************************************************************* */ + +int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, + uint8_t *buffer); +int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, + uint8_t *buffer) +{ + uint8_t *cbwcsw; + uint8_t *sector; + usbmass_cbw_t *cbw; + usbmass_csw_t *csw; + usbreq_t *ur; + usbmass_softc_t *softc; + int res; + + softc = (usbmass_softc_t *) dev->ud_private; + + cbwcsw = KMALLOC(64,32); + sector = buffer; + + cbw = (usbmass_cbw_t *) cbwcsw; + csw = (usbmass_csw_t *) cbwcsw; + + /* + * Fill in the fields of the CBW + */ + + PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); + PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); + PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt)); + cbw->bmCBWFlags = 0x80; /* IN */ + cbw->bCBWLUN = 0; + cbw->bCBWCBLength = 10; + cbw->CBWCB[0] = 0x28; /* READ */ + cbw->CBWCB[1] = 0; + cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */ + cbw->CBWCB[3] = (sectornum >> 16) & 0xFF; + cbw->CBWCB[4] = (sectornum >> 8) & 0xFF; + cbw->CBWCB[5] = (sectornum >> 0) & 0xFF; + cbw->CBWCB[6] = 0; + cbw->CBWCB[7] = 0; + cbw->CBWCB[8] = seccnt; + cbw->CBWCB[9] = 0; + + softc->umass_curtag++; + + /* + * Send the CBW + */ + + ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, + sizeof(usbmass_cbw_t),UR_FLAG_OUT); + res = usb_sync_request(ur); + usb_free_request(ur); + if (res == 4) { + usbmass_stall_recovery(dev); + KFREE(cbwcsw); + return -1; + } + + + /* + * Get the data + */ + + ur = usb_make_request(dev,softc->umass_inpipe,sector, + 512*seccnt,UR_FLAG_IN | UR_FLAG_SHORTOK); + res = usb_sync_request(ur); + usb_free_request(ur); + if (res == 4) { + usbmass_stall_recovery(dev); + KFREE(cbwcsw); + return -1; + } + + + /* + * Get the Status + */ + + memset(csw,0,sizeof(usbmass_csw_t)); + ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, + sizeof(usbmass_csw_t),UR_FLAG_IN); + res = usb_sync_request(ur); + usb_free_request(ur); + if (res == 4) { + usbmass_stall_recovery(dev); + KFREE(cbwcsw); + return -1; + } + + +#if 0 + printf("CSW: Signature=%08X Tag=%08X Residue=%08X Status=%02X\n", + GETCBWFIELD(csw,dCSWSignature), + GETCBWFIELD(csw,dCSWTag), + GETCBWFIELD(csw,dCSWDataResidue), + csw->bCSWStatus); +#endif + + res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1; + + KFREE(cbwcsw); + + return res; + +} + +/* ********************************************************************* + * usbmass_write_sector(dev,sectornum,seccnt,buffer) + * + * Writes a sector to the device + * + * Input parameters: + * dev - usb device + * sectornum - sector number to write + * seccnt - count of sectors to write + * buffer - place to get sector to write + * + * Return value: + * status + ********************************************************************* */ + +static int usbmass_write_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt, + uint8_t *buffer) +{ + uint8_t *cbwcsw; + uint8_t *sector; + usbmass_cbw_t *cbw; + usbmass_csw_t *csw; + usbreq_t *ur; + usbmass_softc_t *softc; + int res; + + softc = (usbmass_softc_t *) dev->ud_private; + + cbwcsw = KMALLOC(64,32); + sector = buffer; + + cbw = (usbmass_cbw_t *) cbwcsw; + csw = (usbmass_csw_t *) cbwcsw; + + /* + * Fill in the fields of the CBW + */ + + PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); + PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); + PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt)); + cbw->bmCBWFlags = 0x00; /* OUT */ + cbw->bCBWLUN = 0; + cbw->bCBWCBLength = 10; + cbw->CBWCB[0] = 0x2A; /* WRITE */ + cbw->CBWCB[1] = 0; + cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */ + cbw->CBWCB[3] = (sectornum >> 16) & 0xFF; + cbw->CBWCB[4] = (sectornum >> 8) & 0xFF; + cbw->CBWCB[5] = (sectornum >> 0) & 0xFF; + cbw->CBWCB[6] = 0; + cbw->CBWCB[7] = 0; + cbw->CBWCB[8] = seccnt; + cbw->CBWCB[9] = 0; + + softc->umass_curtag++; + + /* + * Send the CBW + */ + + ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, + sizeof(usbmass_cbw_t),UR_FLAG_OUT); + res = usb_sync_request(ur); + usb_free_request(ur); + + /* + * Send the data + */ + + ur = usb_make_request(dev,softc->umass_outpipe,sector, + 512*seccnt,UR_FLAG_OUT); + res = usb_sync_request(ur); + usb_free_request(ur); + + /* + * Get the Status + */ + + memset(csw,0,sizeof(usbmass_csw_t)); + ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, + sizeof(usbmass_csw_t),UR_FLAG_IN); + res = usb_sync_request(ur); + usb_free_request(ur); + +#if 0 + printf("CSW: Signature=%08X Tag=%08X Residue=%08X Status=%02X\n", + GETCBWFIELD(csw,dCSWSignature), + GETCBWFIELD(csw,dCSWTag), + GETCBWFIELD(csw,dCSWDataResidue), + csw->bCSWStatus); +#endif + + res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1; + + KFREE(cbwcsw); + + return res; +} + +/* ********************************************************************* + * usbmass_read_capacity(dev,sectornum,buffer) + * + * Reads a sector from the device. + * + * Input parameters: + * dev - usb device + * sectornum - sector number to read + * buffer - place to put sector we read + * + * Return value: + * status + ********************************************************************* */ + +int usbmass_read_capacity(usbdev_t *dev,uint32_t *size); +int usbmass_read_capacity(usbdev_t *dev,uint32_t *size) +{ + uint8_t *cbwcsw; + uint8_t *sector; + usbmass_cbw_t *cbw; + usbmass_csw_t *csw; + usbreq_t *ur; + usbmass_softc_t *softc; + int res; + + softc = (usbmass_softc_t *) dev->ud_private; + + cbwcsw = KMALLOC(64,32); + sector = KMALLOC(64,32); + + memset(sector,0,64); + + cbw = (usbmass_cbw_t *) cbwcsw; + csw = (usbmass_csw_t *) cbwcsw; + + *size = 0; + + /* + * Fill in the fields of the CBW + */ + + PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE); + PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag); + PUTCBWFIELD(cbw,dCBWDataTransferLength,8); + cbw->bmCBWFlags = 0x80; /* IN */ + cbw->bCBWLUN = 0; + cbw->bCBWCBLength = 10; + cbw->CBWCB[0] = 0x25; /* READ CAPACITY */ + cbw->CBWCB[1] = 0; + cbw->CBWCB[2] = 0; + cbw->CBWCB[3] = 0; + cbw->CBWCB[4] = 0; + cbw->CBWCB[5] = 0; + cbw->CBWCB[6] = 0; + cbw->CBWCB[7] = 0; + cbw->CBWCB[8] = 0; + cbw->CBWCB[9] = 0; + + softc->umass_curtag++; + + /* + * Send the CBW + */ + + ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw, + sizeof(usbmass_cbw_t),UR_FLAG_OUT); + res = usb_sync_request(ur); + usb_free_request(ur); + + if (res == 4) { + usbmass_stall_recovery(dev); + KFREE(cbwcsw); + KFREE(sector); + return -1; + } + + /* + * Get the data + */ + + ur = usb_make_request(dev,softc->umass_inpipe,sector, + 8,UR_FLAG_IN | UR_FLAG_SHORTOK); + res = usb_sync_request(ur); + usb_free_request(ur); + + if (res == 4) { + usbmass_stall_recovery(dev); + KFREE(cbwcsw); + KFREE(sector); + return -1; + } + + /* + * Get the Status + */ + + memset(csw,0,sizeof(usbmass_csw_t)); + ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw, + sizeof(usbmass_csw_t),UR_FLAG_IN); + res = usb_sync_request(ur); + usb_free_request(ur); + + KFREE(cbwcsw); + + *size = (((uint32_t) sector[0]) << 24) | + (((uint32_t) sector[1]) << 16) | + (((uint32_t) sector[2]) << 8) | + (((uint32_t) sector[3]) << 0); + + KFREE(sector); + + return 0; + +} + + + +/* ********************************************************************* + * usbmass_attach(dev,drv) + * + * This routine is called when the bus scan stuff finds a mass-storage + * device. We finish up the initialization by configuring the + * device and allocating our softc here. + * + * Input parameters: + * dev - usb device, in the "addressed" state. + * drv - the driver table entry that matched + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv) +{ + usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; + usb_endpoint_descr_t *epdscr; + usb_endpoint_descr_t *indscr = NULL; + usb_endpoint_descr_t *outdscr = NULL; + usb_interface_descr_t *ifdscr; + usbmass_softc_t *softc; + int idx; + + dev->ud_drv = drv; + + softc = KMALLOC(sizeof(usbmass_softc_t),0); + memset(softc,0,sizeof(usbmass_softc_t)); + dev->ud_private = softc; + + ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); + if (ifdscr == NULL) { + return -1; + } + + if ((ifdscr->bInterfaceSubClass != USBMASS_SUBCLASS_SCSI) || + (ifdscr->bInterfaceProtocol != USBMASS_BULKONLY_PROTOCOL)) { + console_log("USBMASS: Do not understand devices with SubClass 0x%02X, Protocol 0x%02X", + ifdscr->bInterfaceSubClass, + ifdscr->bInterfaceProtocol); + return -1; + } + + for (idx = 0; idx < 2; idx++) { + epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); + + if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) { + outdscr = epdscr; + } + else { + indscr = epdscr; + } + } + + + if (!indscr || !outdscr) { + /* + * Could not get descriptors, something is very wrong. + * Leave device addressed but not configured. + */ + return -1; + } + + /* + * Choose the standard configuration. + */ + + usb_set_configuration(dev,cfgdscr->bConfigurationValue); + + /* + * Open the pipes. + */ + + softc->umass_inpipe = usb_open_pipe(dev,indscr); + softc->umass_outpipe = usb_open_pipe(dev,outdscr); + softc->umass_curtag = 0x12345678; + + /* + * Save pointer in global unit table so we can + * match CFE devices up with USB ones + */ + + +#ifdef _CFE_ + softc->umass_unit = -1; + for (idx = 0; idx < USBDISK_MAXUNITS; idx++) { + if (usbdisk_units[idx] == NULL) { + softc->umass_unit = idx; + usbdisk_units[idx] = dev; + break; + } + } + + console_log("USBMASS: Unit %d connected",softc->umass_unit); +#endif + + usbmass_dev = dev; + + return 0; +} + +/* ********************************************************************* + * usbmass_detach(dev) + * + * This routine is called when the bus scanner notices that + * this device has been removed from the system. We should + * do any cleanup that is required. The pending requests + * will be cancelled automagically. + * + * Input parameters: + * dev - usb device + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbmass_detach(usbdev_t *dev) +{ + usbmass_softc_t *softc; + softc = (usbmass_softc_t *) dev->ud_private; + +#ifdef _CFE_ + console_log("USBMASS: USB unit %d disconnected",softc->umass_unit); + if (softc->umass_unit >= 0) usbdisk_units[softc->umass_unit] = NULL; +#endif + + KFREE(softc); + return 0; +} + + + +#ifdef _CFE_ + + +/* ********************************************************************* + * usbdisk_sectorshift(size) + * + * Given a sector size, return log2(size). We cheat; this is + * only needed for 2048 and 512-byte sectors. + * Explicitly using shifts and masks in sector number calculations + * helps on 32-bit-only platforms, since we probably won't need + * a helper library. + * + * Input parameters: + * size - sector size + * + * Return value: + * # of bits to shift + ********************************************************************* */ + +#define usbdisk_sectorshift(size) (((size)==2048)?11:9) + + +/* ********************************************************************* + * usbdisk_probe(drv,probe_a,probe_b,probe_ptr) + * + * Our probe routine. Attach an empty USB disk device to the firmware. + * + * Input parameters: + * drv - driver structure + * probe_a - not used + * probe_b - not used + * probe_ptr - not used + * + * Return value: + * nothing + ********************************************************************* */ + +static void usbdisk_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + usbdisk_t *softc; + char descr[128]; + + softc = (usbdisk_t *) KMALLOC(sizeof(usbdisk_t),0); + + memset(softc,0,sizeof(usbdisk_t)); + + softc->usbdisk_sectorsize = 512; + softc->usbdisk_devtype = BLOCK_DEVTYPE_DISK; + softc->usbdisk_ttlsect = 0; /* not calculated yet */ + softc->usbdisk_unit = (int)probe_a; + + xsprintf(descr,"USB Disk unit %d",(int)probe_a); + + cfe_attach(drv,softc,NULL,descr); +} + + +/* ********************************************************************* + * usbdisk_open(ctx) + * + * Process the CFE OPEN call for this device. For IDE disks, + * the device is reset and identified, and the geometry is + * determined. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + + +static int usbdisk_open(cfe_devctx_t *ctx) +{ + usbdisk_t *softc = ctx->dev_softc; + usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; + uint32_t size; + int res; + + if (!dev) return CFE_ERR_NOTREADY; + + usbmass_request_sense(dev); + + res = usbmass_read_capacity(dev,&size); + if (res < 0) return res; + + softc->usbdisk_ttlsect = size; + + return 0; +} + +/* ********************************************************************* + * usbdisk_read(ctx,buffer) + * + * Process a CFE READ command for the IDE device. This is + * more complex than it looks, since CFE offsets are byte offsets + * and we may need to read partial sectors. + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * number of bytes read, or <0 if an error occured + ********************************************************************* */ + +static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + usbdisk_t *softc = ctx->dev_softc; + usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; + unsigned char *bptr; + int blen; + int numsec; + int res = 0; + int amtcopy; + uint64_t lba; + uint64_t offset; + unsigned char sector[MAX_SECTORSIZE]; + int sectorshift; + + if (!dev) return CFE_ERR_NOTREADY; + + sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize); + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + offset = buffer->buf_offset; + numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift; + + if (offset & (softc->usbdisk_sectorsize-1)) { + lba = (offset >> sectorshift); + res = usbmass_read_sector(dev,lba,1,sector); + if (res < 0) goto out; + amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1)); + if (amtcopy > blen) amtcopy = blen; + memcpy(bptr,§or[offset & (softc->usbdisk_sectorsize-1)],amtcopy); + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + if (blen >= softc->usbdisk_sectorsize) { + int seccnt; + + lba = (offset >> sectorshift); + seccnt = (blen >> sectorshift); + + res = usbmass_read_sector(dev,lba,seccnt,bptr); + if (res < 0) goto out; + + amtcopy = seccnt << sectorshift; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + if (blen) { + lba = (offset >> sectorshift); + res = usbmass_read_sector(dev,lba,1,sector); + if (res < 0) goto out; + amtcopy = blen; + memcpy(bptr,sector,amtcopy); + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + +out: + buffer->buf_retlen = bptr - buffer->buf_ptr; + + return res; +} + +/* ********************************************************************* + * usbdisk_inpstat(ctx,inpstat) + * + * Test input status for the IDE disk. Disks are always ready + * to read. + * + * Input parameters: + * ctx - device context + * inpstat - input status structure + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) +{ + /* usbdisk_t *softc = ctx->dev_softc; */ + + inpstat->inp_status = 1; + return 0; +} + +/* ********************************************************************* + * usbdisk_write(ctx,buffer) + * + * Process a CFE WRITE command for the IDE device. If the write + * involves partial sectors, the affected sectors are read first + * and the changes are merged in. + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * number of bytes write, or <0 if an error occured + ********************************************************************* */ + +static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + usbdisk_t *softc = ctx->dev_softc; + usbdev_t *dev = usbdisk_units[softc->usbdisk_unit]; + unsigned char *bptr; + int blen; + int numsec; + int res = 0; + int amtcopy; + uint64_t offset; + uint64_t lba; + unsigned char sector[MAX_SECTORSIZE]; + int sectorshift; + + if (!dev) return CFE_ERR_NOTREADY; + + sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize); + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + offset = buffer->buf_offset; + numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift; + + if (offset & (softc->usbdisk_sectorsize-1)) { + lba = (offset >> sectorshift); + res = usbmass_read_sector(dev,lba,1,sector); + if (res < 0) goto out; + amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1)); + if (amtcopy > blen) amtcopy = blen; + memcpy(§or[offset & (softc->usbdisk_sectorsize-1)],bptr,amtcopy); + res = usbmass_write_sector(dev,lba,1,sector); + if (res < 0) goto out; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + while (blen >= softc->usbdisk_sectorsize) { + amtcopy = softc->usbdisk_sectorsize; + lba = (offset >> sectorshift); + res = usbmass_write_sector(dev,lba,1,bptr); + if (res < 0) goto out; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + + if (blen) { + lba = (offset >> sectorshift); + res = usbmass_read_sector(dev,lba,1,sector); + if (res < 0) goto out; + amtcopy = blen; + memcpy(sector,bptr,amtcopy); + res = usbmass_write_sector(dev,lba,1,sector); + if (res < 0) goto out; + bptr += amtcopy; + offset += amtcopy; + blen -= amtcopy; + } + +out: + buffer->buf_retlen = bptr - buffer->buf_ptr; + + return res; +} + + +/* ********************************************************************* + * usbdisk_ioctl(ctx,buffer) + * + * Process device I/O control requests for the IDE device. + * + * Input parameters: + * ctx - device context + * buffer - buffer descriptor + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) +{ + usbdisk_t *softc = ctx->dev_softc; + unsigned int *info = (unsigned int *) buffer->buf_ptr; + unsigned long long *linfo = (unsigned long long *) buffer->buf_ptr; + blockdev_info_t *devinfo; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_BLOCK_GETBLOCKSIZE: + *info = softc->usbdisk_sectorsize; + break; + case IOCTL_BLOCK_GETTOTALBLOCKS: + *linfo = softc->usbdisk_ttlsect; + break; + case IOCTL_BLOCK_GETDEVTYPE: + devinfo = (blockdev_info_t *) buffer->buf_ptr; + devinfo->blkdev_totalblocks = softc->usbdisk_ttlsect; + devinfo->blkdev_blocksize = softc->usbdisk_sectorsize; + devinfo->blkdev_devtype = softc->usbdisk_devtype; + break; + default: + return -1; + } + + return 0; +} + +/* ********************************************************************* + * usbdisk_close(ctx) + * + * Close the I/O device. + * + * Input parameters: + * ctx - device context + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int usbdisk_close(cfe_devctx_t *ctx) +{ + /* usbdisk_t *softc = ctx->dev_softc; */ + + return 0; +} + + +#endif diff --git a/cfe/cfe/usb/usbserial.c b/cfe/cfe/usb/usbserial.c new file mode 100644 index 0000000..737d8b4 --- /dev/null +++ b/cfe/cfe/usb/usbserial.c @@ -0,0 +1,713 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * USB Serial Port Driver File: usbserial.c + * + * This device can talk to a few of those usb->serial converters + * out there. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#ifndef _CFE_ +#include +#include +#include +#include +#include "usbhack.h" +#else +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_ioctl.h" +#include "cfe_console.h" +#include "bsp_config.h" +#endif + +#include "lib_malloc.h" +#include "lib_queue.h" +#include "usbchap9.h" +#include "usbd.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define USER_FIFOSIZE 256 + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct usbser_linedata_s { + uint8_t dLineDataBaud0,dLineDataBaud1,dLineDataBaud2,dLineDataBaud3; + uint8_t bLineDataStopBits; /* 0=1, 1=1.5, 2=2 */ + uint8_t bLineDataParity; /* 0=none, 1=odd, 2=even, 3=mark, 4=space */ + uint8_t bLineDataBits; /* 5,6,7,8 */ +} usbser_linedata_t; + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define GETDWFIELD(s,f) ((uint32_t)((s)->f##0) | ((uint32_t)((s)->f##1) << 8) | \ + ((uint32_t)((s)->f##2) << 16) | ((uint32_t)((s)->f##3) << 24)) +#define PUTDWFIELD(s,f,v) (s)->f##0 = (v & 0xFF); \ + (s)->f##1 = ((v)>>8 & 0xFF); \ + (s)->f##2 = ((v)>>16 & 0xFF); \ + (s)->f##3 = ((v)>>24 & 0xFF); + + + +/* ********************************************************************* + * Forward Definitions + ********************************************************************* */ + +static int usbserial_attach(usbdev_t *dev,usb_driver_t *drv); +static int usbserial_detach(usbdev_t *dev); + +#ifdef _CFE_ +static void usb_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr); + +static int usb_uart_open(cfe_devctx_t *ctx); +static int usb_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int usb_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); +static int usb_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int usb_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); +static int usb_uart_close(cfe_devctx_t *ctx); + +const static cfe_devdisp_t usb_uart_dispatch = { + usb_uart_open, + usb_uart_read, + usb_uart_inpstat, + usb_uart_write, + usb_uart_ioctl, + usb_uart_close, + NULL, + NULL +}; + +const cfe_driver_t usb_uart = { + "USB UART", + "uart", + CFE_DEV_SERIAL, + &usb_uart_dispatch, + usb_uart_probe +}; + +typedef struct usb_uart_s { + int uart_unit; + int uart_speed; + int uart_flowcontrol; +} usb_uart_t; + +#define USBUART_MAXUNITS 4 +static usbdev_t *usbuart_units[USBUART_MAXUNITS]; +#endif + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct usbserial_softc_s { + int user_inpipe; + int user_outpipe; + int user_outmps; + int user_intpipe; + uint8_t user_inbuf[USER_FIFOSIZE]; + int user_inbuf_in; + int user_inbuf_out; + uint8_t *user_devinbuf; + int user_devinbufsize; + int user_unit; + uint8_t *user_intbuf; + usbser_linedata_t user_linedata; +} usbserial_softc_t; + +usb_driver_t usbserial_driver = { + "USB Serial Port", + usbserial_attach, + usbserial_detach +}; + +usbdev_t *usbserial_dev = NULL; + + +#if 0 +/* ********************************************************************* + * usbserial_get_linedata(dev,linedata) + * + * Request line data from the device. + * + * Input parameters: + * dev - USB device + * linedata - pointer to structure + * + * Return value: + * # of bytes returned + * <0 if error + ********************************************************************* */ + +static int usbserial_get_linedata(usbdev_t *dev,usbser_linedata_t *ldata) +{ + uint8_t *respbuf; + int res; + + respbuf = KMALLOC(32,0); + + res = usb_std_request(dev,0xA1,0x21,0,0,respbuf,sizeof(usbser_linedata_t)); + + KFREE(respbuf); + + if ((res >= 0) && ldata) memcpy(ldata,respbuf,sizeof(usbser_linedata_t)); + + return res; +} +#endif + +/* ********************************************************************* + * usbserial_set_linedata(dev,linedata) + * + * Set line data to the device. + * + * Input parameters: + * dev - USB device + * linedata - pointer to structure + * + * Return value: + * # of bytes returned + * <0 if error + ********************************************************************* */ + +static int usbserial_set_linedata(usbdev_t *dev,usbser_linedata_t *ldata) +{ + int res; + + /* + * Send request to device. + */ + + res = usb_std_request(dev,0x21,0x20,0,0,(uint8_t *) ldata,sizeof(usbser_linedata_t)); + + return res; +} + +#if 0 +/* ********************************************************************* + * usbserial_song_and_dance(usbdev_t *dev) + * + * Magic incantations from using the CATC on this device. + * + * Input parameters: + * dev + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbserial_song_and_dance(usbdev_t *dev) +{ + int res; + char databuf[1]; + + res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */ + + res = usb_std_request(dev,0x40,0x01,0x0404,0,NULL,0); /* WRITE */ + + res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */ + res = usb_std_request(dev,0xc0,0x01,0x8383,0,databuf,1); /* READ */ + res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */ + + res = usb_std_request(dev,0x40,0x01,0x0404,1,NULL,0); /* WRITE */ + + res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */ + res = usb_std_request(dev,0xc0,0x01,0x8383,0,databuf,1); /* READ */ + + res = usb_std_request(dev,0x40,0x01,0x0,1, NULL,0); /* WRITE */ + res = usb_std_request(dev,0x40,0x01,0x1,0xC0,NULL,0); /* WRITE */ + res = usb_std_request(dev,0x40,0x01,0x2,4, NULL,0); /* WRITE */ + + return 0; +} +#endif + +/* ********************************************************************* + * usbserial_tx_data(dev,buffer,len) + * + * Synchronously transmit data via the USB. + * + * Input parameters: + * dev - device pointer + * buffer,len - data we want to send + * + * Return value: + * number of bytes sent. + ********************************************************************* */ + +static int usbserial_tx_data(usbdev_t *dev,uint8_t *buffer,int len) +{ + uint8_t *bptr; + usbreq_t *ur; + usbserial_softc_t *softc = (dev->ud_private); + int res; + + bptr = KMALLOC(len,0); + + memcpy(bptr,buffer,len); + + ur = usb_make_request(dev,softc->user_outpipe,bptr,len,UR_FLAG_OUT); + res = usb_sync_request(ur); + +// printf("Data sent, status=%d, xferred=%d\n",res,ur->ur_xferred); + + res = ur->ur_xferred; + + usb_free_request(ur); + + KFREE(bptr); + + return res; +} + +/* ********************************************************************* + * usbserial_int_callback(ur) + * + * Callback routine for the interrupt request, for devices + * that have an interrupt pipe. We ignore this. + * + * Input parameters: + * ur - usb request + * + * Return value: + * nothing + ********************************************************************* */ + +static int usbserial_int_callback(usbreq_t *ur) +{ +// int idx; + + /* + * Check to see if the request was cancelled by someone + * deleting our endpoint. + */ + + if (ur->ur_status == 0xFF) { + usb_free_request(ur); + return 0; + } + +// printf("serial int msg: "); +// for (idx = 0; idx < ur->ur_xferred; idx++) printf("%02X ",ur->ur_buffer[idx]); +// printf("\n"); + + usb_queue_request(ur); + + return 0; + +} + + +/* ********************************************************************* + * usbserial_rx_callback(ur) + * + * Callback routine for the regular data pipe. + * + * Input parameters: + * ur - usb request + * + * Return value: + * nothing + ********************************************************************* */ + +static int usbserial_rx_callback(usbreq_t *ur) +{ + int idx; + int iptr; + usbserial_softc_t *user = (ur->ur_dev->ud_private); + + /* + * Check to see if the request was cancelled by someone + * deleting our endpoint. + */ + + if (ur->ur_status == 0xFF) { + usb_free_request(ur); + return 0; + } + + /* + * Add characters to the receive fifo + */ + + for (idx = 0; idx < ur->ur_xferred; idx++) { + iptr = (user->user_inbuf_in + 1) & (USER_FIFOSIZE-1); + if (iptr == user->user_inbuf_out) break; /* overflow */ + user->user_inbuf[user->user_inbuf_in] = ur->ur_buffer[idx]; + user->user_inbuf_in = iptr; + } + + /* + * Requeue the request + */ + + usb_queue_request(ur); + + return 0; + +} + + +/* ********************************************************************* + * usbserial_attach(dev,drv) + * + * This routine is called when the bus scan stuff finds a mass-storage + * device. We finish up the initialization by configuring the + * device and allocating our softc here. + * + * Input parameters: + * dev - usb device, in the "addressed" state. + * drv - the driver table entry that matched + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbserial_attach(usbdev_t *dev,usb_driver_t *drv) +{ + usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; + usb_endpoint_descr_t *epdscr; + usb_endpoint_descr_t *indscr = NULL; + usb_endpoint_descr_t *outdscr = NULL; + usb_endpoint_descr_t *intdscr = NULL; + usb_interface_descr_t *ifdscr; + usbser_linedata_t *ldata; + usbserial_softc_t *softc; + usbreq_t *ur; + int idx; + + dev->ud_drv = drv; + + softc = KMALLOC(sizeof(usbserial_softc_t),0); + memset(softc,0,sizeof(usbserial_softc_t)); + dev->ud_private = softc; + + ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); + if (ifdscr == NULL) { + printf("Could not get interface descriptor\n"); + return -1; + } + + for (idx = 0; idx < ifdscr->bNumEndpoints; idx++) { + epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); + + if ((epdscr->bmAttributes & USB_ENDPOINT_TYPE_MASK) == + USB_ENDPOINT_TYPE_INTERRUPT) { + intdscr = epdscr; + } + else if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) { + outdscr = epdscr; + } + else { + indscr = epdscr; + } + } + + + if (!indscr || !outdscr) { + printf("IN or OUT endpoint descriptors are missing\n"); + /* + * Could not get descriptors, something is very wrong. + * Leave device addressed but not configured. + */ + return 0; + } + + /* + * Choose the standard configuration. + */ + + usb_set_configuration(dev,cfgdscr->bConfigurationValue); + + /* + * Open the pipes. + */ + + softc->user_inpipe = usb_open_pipe(dev,indscr); + softc->user_devinbufsize = GETUSBFIELD(indscr,wMaxPacketSize); + softc->user_devinbuf = KMALLOC(softc->user_devinbufsize,0); + softc->user_outpipe = usb_open_pipe(dev,outdscr); + softc->user_outmps = GETUSBFIELD(outdscr,wMaxPacketSize); + if (intdscr) { + softc->user_intpipe = usb_open_pipe(dev,intdscr); + } + else { + softc->user_intpipe = -1; + } + + ur = usb_make_request(dev,softc->user_inpipe,softc->user_devinbuf, + softc->user_devinbufsize, + UR_FLAG_IN | UR_FLAG_SHORTOK); + ur->ur_callback = usbserial_rx_callback; + usb_queue_request(ur); + + + if (softc->user_intpipe) { + softc->user_intbuf = KMALLOC(32,0); + ur = usb_make_request(dev,softc->user_intpipe,softc->user_intbuf, + GETUSBFIELD(intdscr,wMaxPacketSize), + UR_FLAG_IN | UR_FLAG_SHORTOK); + ur->ur_callback = usbserial_int_callback; + usb_queue_request(ur); + } + +#ifdef _CFE_ + softc->user_unit = -1; + for (idx = 0; idx < USBUART_MAXUNITS; idx++) { + if (usbuart_units[idx] == NULL) { + softc->user_unit = idx; + usbuart_units[idx] = dev; + break; + } + } + + console_log("USBSERIAL: Unit %d connected",softc->user_unit); +#endif + +// usbserial_song_and_dance(dev); + + ldata = &(softc->user_linedata); + PUTDWFIELD(ldata,dLineDataBaud,115200); + ldata->bLineDataStopBits = 0; + ldata->bLineDataParity = 2; + ldata->bLineDataBits = 8; + + usbserial_set_linedata(dev,ldata); +// usbserial_get_linedata(dev,NULL); + + usbserial_dev = dev; + + return 0; +} + +/* ********************************************************************* + * usbserial_detach(dev) + * + * This routine is called when the bus scanner notices that + * this device has been removed from the system. We should + * do any cleanup that is required. The pending requests + * will be cancelled automagically. + * + * Input parameters: + * dev - usb device + * + * Return value: + * 0 + ********************************************************************* */ + +static int usbserial_detach(usbdev_t *dev) +{ + usbserial_softc_t *softc; + + softc = dev->ud_private; + + +#ifdef _CFE_ + console_log("USBSERIAL: USB unit %d disconnected",softc->user_unit); + if (softc->user_unit >= 0) usbuart_units[softc->user_unit] = NULL; +#endif + + if (softc) { + if (softc->user_devinbuf) KFREE(softc->user_devinbuf); + if (softc->user_intbuf) KFREE(softc->user_intbuf); + KFREE(softc); + } + + return 0; +} + + + +#ifdef _CFE_ + + + +static void usb_uart_probe(cfe_driver_t *drv, + unsigned long probe_a, unsigned long probe_b, + void *probe_ptr) +{ + usb_uart_t *softc; + char descr[80]; + + softc = (usb_uart_t *) KMALLOC(sizeof(usb_uart_t),0); + + memset(softc,0,sizeof(usb_uart_t)); + + softc->uart_unit = (int)probe_a; + + xsprintf(descr,"USB UART unit %d",(int)probe_a); + + cfe_attach(drv,softc,NULL,descr); +} + + +static int usb_uart_open(cfe_devctx_t *ctx) +{ +// usb_uart_t *softc = ctx->dev_softc; +// int baudrate = CFG_SERIAL_BAUD_RATE; +// usbdev_t *dev = usbuart_units[softc->uart_unit]; + + /* + * XXX call the uart setup here + */ + + return 0; +} + +static int usb_uart_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + usb_uart_t *softc = ctx->dev_softc; + usbdev_t *dev = usbuart_units[softc->uart_unit]; + usbserial_softc_t *user = dev->ud_private; + unsigned char *bptr; + int blen; + + if (!dev) return 0; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + while ((blen > 0) && (user->user_inbuf_out != user->user_inbuf_in)) { + *bptr++ = user->user_inbuf[user->user_inbuf_out]; + user->user_inbuf_out = (user->user_inbuf_out + 1) & (USER_FIFOSIZE-1); + blen--; + } + + buffer->buf_retlen = buffer->buf_length - blen; + return 0; +} + +static int usb_uart_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) +{ + usb_uart_t *softc = ctx->dev_softc; + usbdev_t *dev = usbuart_units[softc->uart_unit]; + usbserial_softc_t *user = dev->ud_private; + + inpstat->inp_status = 0; + + if (!dev) return 0; + + inpstat->inp_status = (user->user_inbuf_in != user->user_inbuf_out); + + return 0; +} + +static int usb_uart_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + usb_uart_t *softc = ctx->dev_softc; + unsigned char *bptr; + int blen; + usbdev_t *dev = usbuart_units[softc->uart_unit]; + usbserial_softc_t *user = dev->ud_private; + + bptr = buffer->buf_ptr; + blen = buffer->buf_length; + + if (!dev) { + buffer->buf_retlen = blen; + return 0; + } + + if (blen > user->user_outmps) blen = user->user_outmps; + + usbserial_tx_data(dev,bptr,blen); + + buffer->buf_retlen = blen; + return 0; +} + +static int usb_uart_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) +{ + usb_uart_t *softc = ctx->dev_softc; + usbdev_t *dev = usbuart_units[softc->uart_unit]; +// usbserial_softc_t *user = dev->ud_private; + + if (!dev) return -1; + + unsigned int *info = (unsigned int *) buffer->buf_ptr; + + switch ((int)buffer->buf_ioctlcmd) { + case IOCTL_SERIAL_GETSPEED: + *info = softc->uart_speed; + break; + case IOCTL_SERIAL_SETSPEED: + softc->uart_speed = *info; + /* NYI */ + break; + case IOCTL_SERIAL_GETFLOW: + *info = softc->uart_flowcontrol; + break; + case IOCTL_SERIAL_SETFLOW: + softc->uart_flowcontrol = *info; + /* NYI */ + break; + default: + return -1; + } + + return 0; +} + +static int usb_uart_close(cfe_devctx_t *ctx) +{ +// usb_uart_t *softc = ctx->dev_softc; + + return 0; +} + + + +#endif + diff --git a/cfe/cfe/vendor/Makefile b/cfe/cfe/vendor/Makefile new file mode 100644 index 0000000..a9fb42c --- /dev/null +++ b/cfe/cfe/vendor/Makefile @@ -0,0 +1,2 @@ + +ALLOBJS += cfe_vendor_xreq.o cfe_vendor_iocb_dispatch.o cfe_vendor_cmds.o diff --git a/cfe/cfe/vendor/cfe_vendor_cmds.c b/cfe/cfe/vendor/cfe_vendor_cmds.c new file mode 100644 index 0000000..34a159d --- /dev/null +++ b/cfe/cfe/vendor/cfe_vendor_cmds.c @@ -0,0 +1,27 @@ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "ui_command.h" +#include "cfe.h" + +#include "bsp_config.h" + +int ui_init_vendorcmds(void); + + +int ui_init_vendorcmds(void) +{ + return 0; +} diff --git a/cfe/cfe/vendor/cfe_vendor_iocb.h b/cfe/cfe/vendor/cfe_vendor_iocb.h new file mode 100644 index 0000000..33581cb --- /dev/null +++ b/cfe/cfe/vendor/cfe_vendor_iocb.h @@ -0,0 +1,87 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB definitions File: cfe_iocb.h + * + * This module describes CFE's IOCB structure, the main + * data structure used to communicate API requests with CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _CFE_VENDOR_IOCB_H +#define _CFE_VENDOR_IOCB_H + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_CMD_VENDOR_SAMPLE (CFE_CMD_VENDOR_USE+0) + +#define CFE_CMD_VENDOR_MAX (CFE_CMD_VENDOR_USE+1) + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +/* + * Vendor note: The fields in this structure leading up to the + * union *must* match the ones in cfe_iocb.h + * + * You can declare your own parameter list members here, since + * only your functions will be using them. + */ + + +typedef struct cfe_vendor_iocb_s { + cfe_uint_t iocb_fcode; /* IOCB function code */ + cfe_int_t iocb_status; /* return status */ + cfe_int_t iocb_handle; /* file/device handle */ + cfe_uint_t iocb_flags; /* flags for this IOCB */ + cfe_uint_t iocb_psize; /* size of parameter list */ + union { + /* add/replace parameter list here */ + iocb_buffer_t iocb_buffer; /* buffer parameters */ + } plist; +} cfe_vendor_iocb_t; + + +#endif + diff --git a/cfe/cfe/vendor/cfe_vendor_iocb_dispatch.c b/cfe/cfe/vendor/cfe_vendor_iocb_dispatch.c new file mode 100644 index 0000000..fb00c03 --- /dev/null +++ b/cfe/cfe/vendor/cfe_vendor_iocb_dispatch.c @@ -0,0 +1,179 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB dispatcher File: cfe_vendor_iocb_dispatch.c + * + * This routine is the main API dispatch for CFE. User API + * calls, via the ROM entry point, get dispatched to routines + * in this module. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_vendor_iocb.h" +#include "cfe_error.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_mem.h" +#include "cfe_fileops.h" +#include "cfe_boot.h" +#include "env_subr.h" +#include "cfe.h" +#include "cfe_console.h" +#include "bsp_config.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define HV 1 /* handle valid */ + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +extern cfe_devctx_t *cfe_handle_table[CFE_MAX_HANDLE]; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int cfe_vendor_iocb_dispatch(cfe_iocb_t *iocb); + +/* ********************************************************************* + * Dispatch table + ********************************************************************* */ + +struct cfe_vendor_cmd_dispatch_s { + int plistsize; + int flags; + int (*func)(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +}; + + +static int cfe_cmd_vendor_sample(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +const static struct cfe_vendor_cmd_dispatch_s + cfe_vendor_cmd_dispatch_table[CFE_CMD_VENDOR_MAX - CFE_CMD_VENDOR_USE] = { + {sizeof(iocb_buffer_t), 0, cfe_cmd_vendor_sample}, /* 0 : CFE_CMD_VENDOR_SAMPLE */ +}; + +/* ********************************************************************* + * IOCB dispatch routines + ********************************************************************* */ + + +int cfe_vendor_iocb_dispatch(cfe_iocb_t *iocb) +{ + const struct cfe_vendor_cmd_dispatch_s *disp; + int res; + cfe_devctx_t *ctx; + + /* + * Check for commands codes out of range + */ + + if ((iocb->iocb_fcode < CFE_CMD_VENDOR_USE) || + (iocb->iocb_fcode >= CFE_CMD_VENDOR_MAX)) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for command codes in range but invalid + */ + + disp = &cfe_vendor_cmd_dispatch_table[iocb->iocb_fcode - CFE_CMD_VENDOR_USE]; + + if (disp->plistsize < 0) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for invalid parameter list size + */ + + if (disp->plistsize != iocb->iocb_psize) { + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + + /* + * Determine handle + */ + + ctx = NULL; + if (disp->flags & HV) { + if ((iocb->iocb_handle >= CFE_MAX_HANDLE) || + (iocb->iocb_handle < 0) || + (cfe_handle_table[iocb->iocb_handle] == NULL)){ + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + ctx = cfe_handle_table[iocb->iocb_handle]; + } + + /* + * Dispatch to handler routine + */ + + res = (*disp->func)(ctx,iocb); + + iocb->iocb_status = res; + return res; +} + + + +/* ********************************************************************* + * Implementation routines for each IOCB function + ********************************************************************* */ + +static int cfe_cmd_vendor_sample(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + return CFE_OK; +} diff --git a/cfe/cfe/vendor/cfe_vendor_xiocb.h b/cfe/cfe/vendor/cfe_vendor_xiocb.h new file mode 100644 index 0000000..950ebcf --- /dev/null +++ b/cfe/cfe/vendor/cfe_vendor_xiocb.h @@ -0,0 +1,91 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB definitions File: cfe_iocb.h + * + * This module describes CFE's IOCB structure, the main + * data structure used to communicate API requests with CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#ifndef _CFE_VENDOR_XIOCB_H +#define _CFE_VENDOR_XIOCB_H + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_CMD_VENDOR_SAMPLE (CFE_CMD_VENDOR_USE+0) + +#define CFE_CMD_VENDOR_MAX (CFE_CMD_VENDOR_USE+1) + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +/* + * Vendor note: The fields in this structure leading up to the + * union *must* match the ones in cfe_xiocb.h + * + * You can declare your own parameter list members here, since + * only your functions will be using them. + * + * You can also use some of the parameter list members in + * the regular xiocb.h if they are appropriate for your + * extended function calls. + */ + + +typedef struct cfe_vendor_xiocb_s { + cfe_xuint_t xiocb_fcode; /* IOCB function code */ + cfe_xint_t xiocb_status; /* return status */ + cfe_xint_t xiocb_handle; /* file/device handle */ + cfe_xuint_t xiocb_flags; /* flags for this IOCB */ + cfe_xuint_t xiocb_psize; /* size of parameter list */ + union { + /* add/replace parameter list here */ + xiocb_buffer_t xiocb_buffer; /* buffer parameters */ + } plist; +} cfe_vendor_xiocb_t; + + +#endif + diff --git a/cfe/cfe/vendor/cfe_vendor_xreq.c b/cfe/cfe/vendor/cfe_vendor_xreq.c new file mode 100644 index 0000000..f2ad541 --- /dev/null +++ b/cfe/cfe/vendor/cfe_vendor_xreq.c @@ -0,0 +1,222 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB dispatcher File: cfe_vendor_xreq.c + * + * This routine is the main API dispatch for CFE. User API + * calls, via the ROM entry point, get dispatched to routines + * in this module. + * + * This version of cfe_xreq is used for vendor extensions to + * CFE. + * + * This module looks similar to cfe_iocb_dispatch - it is different + * in that the data structure used, cfe_xiocb_t, uses fixed + * size field members (specifically, all 64-bits) no matter how + * the firmware is compiled. This ensures a consistent API + * interface on any implementation. When you call CFE + * from another program, the entry vector comes here first. + * + * Should the normal cfe_iocb interface change, this one should + * be kept the same for backward compatibility reasons. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_vendor_iocb.h" +#include "cfe_xiocb.h" +#include "cfe_vendor_xiocb.h" +#include "cfe_error.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_mem.h" +#include "env_subr.h" +#include "cfe.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* enum values for various plist types */ + +#define PLBUF 1 /* iocb_buffer_t */ + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +struct cfe_vendor_xcmd_dispatch_s { + int xplistsize; + int iplistsize; + int plisttype; +}; + + +/* ********************************************************************* + * Command conversion table + * This table contains useful information for converting + * iocbs to xiocbs. + ********************************************************************* */ + +const static struct cfe_vendor_xcmd_dispatch_s + cfe_vendor_xcmd_dispatch_table[CFE_CMD_VENDOR_MAX-CFE_CMD_VENDOR_USE] = { + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 0 : CFE_CMD_VENDOR_SAMPLE */ +}; + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern int cfe_vendor_iocb_dispatch(cfe_vendor_iocb_t *iocb); +extern cfe_int_t cfe_vendor_doxreq(cfe_vendor_xiocb_t *xiocb); + +/* ********************************************************************* + * cfe_vendor_doxreq(xiocb) + * + * Process an xiocb request. This routine converts an xiocb + * into an iocb, calls the IOCB dispatcher, converts the results + * back into the xiocb, and returns. + * + * Input parameters: + * xiocb - pointer to user xiocb + * + * Return value: + * command status, <0 if error occured + ********************************************************************* */ + +cfe_int_t cfe_vendor_doxreq(cfe_vendor_xiocb_t *xiocb) +{ + const struct cfe_vendor_xcmd_dispatch_s *disp; + cfe_vendor_iocb_t iiocb; + cfe_int_t res; + + /* + * Check for commands codes out of range + */ + + if ((xiocb->xiocb_fcode < CFE_CMD_VENDOR_USE) || + (xiocb->xiocb_fcode >= CFE_CMD_VENDOR_MAX)) { + xiocb->xiocb_status = CFE_ERR_INV_COMMAND; + return xiocb->xiocb_status; + } + + /* + * Check for command codes in range but invalid + */ + + disp = &cfe_vendor_xcmd_dispatch_table[xiocb->xiocb_fcode - CFE_CMD_VENDOR_USE]; + + if (disp->xplistsize < 0) { + xiocb->xiocb_status = CFE_ERR_INV_COMMAND; + return xiocb->xiocb_status; + } + + /* + * Check for invalid parameter list size + */ + + if (disp->xplistsize != xiocb->xiocb_psize) { + xiocb->xiocb_status = CFE_ERR_INV_PARAM; + return xiocb->xiocb_status; + } + + /* + * Okay, copy parameters into the internal IOCB. + * First, the fixed header. + */ + + iiocb.iocb_fcode = (unsigned int) xiocb->xiocb_fcode; + iiocb.iocb_status = (int) xiocb->xiocb_status; + iiocb.iocb_handle = (int) xiocb->xiocb_handle; + iiocb.iocb_flags = (unsigned int) xiocb->xiocb_flags; + iiocb.iocb_psize = (unsigned int) disp->iplistsize; + + /* + * Now the parameter list + */ + + switch (disp->plisttype) { + case PLBUF: + iiocb.plist.iocb_buffer.buf_offset = (cfe_offset_t) xiocb->plist.xiocb_buffer.buf_offset; + iiocb.plist.iocb_buffer.buf_ptr = (unsigned char *) (uintptr_t) xiocb->plist.xiocb_buffer.buf_ptr; + iiocb.plist.iocb_buffer.buf_length = (unsigned int) xiocb->plist.xiocb_buffer.buf_length; + iiocb.plist.iocb_buffer.buf_retlen = (unsigned int) xiocb->plist.xiocb_buffer.buf_retlen; + iiocb.plist.iocb_buffer.buf_ioctlcmd = (unsigned int) xiocb->plist.xiocb_buffer.buf_ioctlcmd; + break; + } + + /* + * Do the internal function dispatch + */ + + res = (cfe_int_t) cfe_vendor_iocb_dispatch(&iiocb); + + /* + * Now convert the parameter list members back + */ + + switch (disp->plisttype) { + case PLBUF: + xiocb->plist.xiocb_buffer.buf_offset = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_offset; + xiocb->plist.xiocb_buffer.buf_ptr = (cfe_xptr_t) (uintptr_t) iiocb.plist.iocb_buffer.buf_ptr; + xiocb->plist.xiocb_buffer.buf_length = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_length; + xiocb->plist.xiocb_buffer.buf_retlen = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_retlen; + xiocb->plist.xiocb_buffer.buf_ioctlcmd = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_ioctlcmd; + break; + } + + /* + * And the fixed header + */ + + xiocb->xiocb_status = (cfe_int_t) iiocb.iocb_status; + xiocb->xiocb_handle = (cfe_int_t) iiocb.iocb_handle; + xiocb->xiocb_flags = (cfe_uint_t) iiocb.iocb_flags; + + return xiocb->xiocb_status; +} diff --git a/cfe/cfe/verif/Makefile b/cfe/cfe/verif/Makefile new file mode 100644 index 0000000..939b494 --- /dev/null +++ b/cfe/cfe/verif/Makefile @@ -0,0 +1,7 @@ + +# +# Object files needed by VAPI +# + +CFLAGS += -DCFG_VAPI=1 +ALLOBJS += vapi.o vapisubr.o vapitest.o ui_vapi.o diff --git a/cfe/cfe/verif/readme.txt b/cfe/cfe/verif/readme.txt new file mode 100644 index 0000000..4a35dee --- /dev/null +++ b/cfe/cfe/verif/readme.txt @@ -0,0 +1,342 @@ +CFE Diagnostic Entry Points +--------------------------- + +--------------------------------------------------------------------------- + +The CFE diagnostic entry points are used when running verification +programs under the control of the firmware. They are fixed (constant) +addresses and have register-based calling sequences. These entry +points are designed to be as minimal as possible so that as much of the +verification code as possible can be reused. + +You can call the KSEG0 or KSEG1 version of the routine. It is +recommended that you call the cached version from cached code and +vice versa. + +The firmware will reserve the top megabyte of memory for itself. The +diagnostic must not touch this memory. + +The firmware will be compiled to *NOT* use relocatable data and +code segments. + +The firmware will need one general register that it is allowed to +trash without saving - I'll be using this to generate the pointer to +the save area. + +The diagnostics can generate records in a log buffer. This buffer +is allocated in the diagnostic's memory space but is filled in +by the firmware through the diagnostic entry points. At the end +of the diagnostic run, user commands in the firmware may be used +to look through accumulated log records. + +If you mess with the caches or with the console device, the +VAPI functions that print messages to the console may not work. + +Log records follow this format: + + +0 SIGNATURE, FORMAT, and ID-CODE + +8 Number of 64-bit words in 'Log Data' field. + Upper 32 bits are CP0 count register + +16 Return address of routine generating this record + +24 Log Data + +The "Log Record size" field is the number of bytes in the "log data" +field. No log data would use a value of zero. + +The bytes in the SIGNATURE word are broken down as follows: + + S1 S2 P1 F1 I1 I2 I3 I4 + CF E1 pp xx ii ii ii ii + +The "F1" byte is the format code; it describes the type +of log record being generated. + + 0x00 - General register and CP0 dump + 0x01 - SOC state dump + 0x02 - Generic log data (multiple of 8 bytes) + 0x03 - trace RAM + 0x04 - Diagnostic termination status (8 bytes) + 0x05 - Floating point registers + +The "P1" byte is the processor number, 0 or 1. + +The "I1" through "I4" bytes are supplied by the diagnostic +and can take on any value. You can use these bytes to identify +what part of the program generated this particular log record. + +For example, if the diagnostic logs a single value of +0x0123_4567_89ab_cdef the log entry might look like: + + 0xCCFF_EE02_0000_0001 + 0x0001_3F22_0000_0008 + 0xFFFF_FFFF_8000_0120 + 0x0123_4567_89AB_CDEF + + +RETURN TO FIRMWARE +------------------ + +Description: + + Returns control to the firmware and displays the test status. + The status result is in register A0. + + The firmware will store a "diagnostic termination status" + record in the log with the A0 register value. The ID code + will be zero for this record. + + CFE's log scanning commands can be used to display log + records accumulated by the test. + + +Routine address: 0xBFC00510 (KSEG1) + 0x9FC00510 (KSEG0) + +On entry: A0 ($4) Exit status (9=ok, nonzero=fail) +On return: Does not return +Registers used: All + + +DUMP GENERAL REGISTERS +---------------------- + +Description: + + This routine causes CFE to display a register dump on the console + port. It is assumed that the console hardware state has not been + altered by the diagnostic. + + The format of the register dump is: TBD [XXX should it look like the + one that the functional simulator uses?] + + The firmware needs one scratch register. + + +Routine address: 0xBFC00520 (KSEG1) + 0x9FC00520 (KSEG0) + +On Entry: RA ($31) Return Address +On Return: nothing +Registers used: K0 ($26) Scratch register for CFE + + +SET LOG BUFFER +-------------- + +Description: + + This routine sets the address of the log buffer. This + call must be made once at the beginning of the diagnostic + or else the "SAVE" functions will be considered as + NOPs. + + The buffer addresses must be 64-bit aligned. + +Routine address: 0xBFC00530 (KSEG1) + 0x9FC00530 (KSEG0) + +On Entry: RA ($31) Return Address + A0 ($4) Address of start of buffer + A1 ($5) Address of end of buffer +On Return: Nothing +Registers Used: K0 ($26) Scratch register for CFE + + + +LOG SINGLE VALUE +---------------- + +Description: + + This routine saves a single 64-bit value in the log. + + +Routine address: 0xBFC00540 (KSEG1) + 0x9FC00540 (KSEG0) + +On Entry: RA ($31) Return Address + A0 ($4) Low 32 bits are ID code for value + A1 ($5) Value to log +On Return: Nothing +Registers Used: K0 ($26) Scratch register for CFE + + + +LOG MEMORY DATA +--------------- + +Description: + + This routine saves a block of memory in the log. The source + buffer must be 64-bit aligned. + + +Routine address: 0xBFC00550 (KSEG1) + 0x9FC00550 (KSEG0) + +On Entry: RA ($31) Return Address + A0 ($4) Low 32 bits are ID code for values + A1 ($5) Address of buffer containing values + A2 ($6) Number of 64-bit words to store +On Return: Nothing +Registers Used: K0 ($26) Scratch register for CFE + + + + + +SAVE SOC STATE +-------------- + +Description: + + This routine saves the SOC state in a user-supplied buffer. + The buffer must be large enough to accomodate the SOC state. + The SOC state will be written as records with the following + format: + + uint64_t phys_address + uint64_t value + uint64_t phys_address + uint64_t value + ... + uint64_t phys_address + uint64_t value + + The table of SOC registers to dump will be maintained by + the firmware. + + The firmware needs one scratch register. + +Routine address: 0xBFC00570 (KSEG1) + 0x9FC00570 (KSEG0) + +On entry: A0 ($4) Low 32 bits are ID code for values + A1 ($5) Bitmask of agents to store in log +On return: nothing +Registers used: K0 ($26) Scratch register for CFE + + +SAVE CPU REGISTERS +------------------ + +Description: + + This routine saves the CPU general registers and certain CP0 + registers in a user-supplied buffer. + + This buffer must be large enough to accomodate the data + that will be saved. The registers will be written in + the following format: + + uint64_t general_registers[32] + uint64_t C0_INX + uint64_t C0_RAND + uint64_t C0_TLBLO0 + uint64_t C0_TLBLO1 + uint64_t C0_CTEXT + uint64_t C0_PGMASK + uint64_t C0_WIRED + uint64_t C0_BADVADDR + uint64_t C0_COUNT + uint64_t C0_TLBHI + uint64_t C0_COMPARE + uint64_t C0_SR + uint64_t C0_CAUSE + uint64_t C0_EPC + uint64_t C0_PRID + uint64_t C0_CONFIG + uint64_t C0_LLADDR + uint64_t C0_WATCHLO + uint64_t C0_WATCHHI + uint64_t C0_XCTEXT + uint64_t C0_ECC + uint64_t C0_CACHEERR + uint64_t C0_TAGLO + uint64_t C0_TAGHI + uint64_t C0_ERREPC + + The firmware needs one scratch register. + +Routine address: 0xBFC00580 (KSEG1) + 0x9FC00580 (KSEG0) + +On entry: RA ($31) Return address + A0 ($4) Low 32 bits are ID code for values +On return: nothing +Registers used: K0 ($26) Scratch register for CFE + + +SAVE FPU REGISTERS +------------------ + +Description: + + This routine saves the floating point and floating point + control registers. The registers will be written in + the following format: + + uint64_t fp_registers[32] + uint64_t fp_fir + uint64_t fp_status + uint64_t fp_condition_codes + uint64_t fp_exceptions + uint64_t fp_enables + + The firmware needs one scratch register. + +Routine address: 0xBFC005B0 (KSEG1) + 0x9FC005B0 (KSEG0) + +On entry: RA ($31) Return address + A0 ($4) Low 32 bits are ID code for values +On return: nothing +Registers used: K0 ($26) Scratch register for CFE + + +DUMP STRING +----------- + +Description: + + This routine displays a zero-terminated ASCII text string on the + console port. + + The firmware needs one scratch register. + + +Routine address: 0xBFC00590 (KSEG1) + 0x9FC00590 (KSEG0) + +On entry: RA ($31) Return address + A0 ($4) Pointer to null-terminated string +On return: nothing +Registers used: K0 ($26) Scratch register for CFE + + + +SHOW LED MESSAGE +---------------- + +Description: + + This routine writes four characters onto the SWARM board LEDs. + Writing to the LEDs is very fast compared to writing to the + console and can be useful for providing progress feedback + during a run. + + The characters are packed into the low 4 bytes of register A0. + The string ABCD would be hex 0x0000_0000_4142_4344 + + The firmware needs one scratch register + +Routine address: 0xBFC005A0 (KSEG1) + 0x9FC005A0 (KSEG0) + +On entry: RA ($31) Return Address + A0 ($4) Four characters +On return: nothing +Registers used: K0 ($26) Scratch register for CFE + +------------------------------------------------------------------------ + diff --git a/cfe/cfe/verif/ui_vapi.c b/cfe/cfe/verif/ui_vapi.c new file mode 100644 index 0000000..4575322 --- /dev/null +++ b/cfe/cfe/verif/ui_vapi.c @@ -0,0 +1,300 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * VAPI commands File: ui_vapi.c + * + * User interface for the verification API + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "bsp_config.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "env_subr.h" +#include "ui_command.h" +#include "cfe.h" + +#if CFG_VAPI + +#include "vapi.h" + +int ui_init_vapicmds(void); + +extern void vapitest(void); + +extern void vapi_run(int); + +extern uint64_t vapi_logstart; +extern uint64_t vapi_logend; +extern uint64_t vapi_logptr; +extern uint64_t vapi_status; + +int ui_cmd_vapirun(ui_cmdline_t *cmd,int argc,char *argv[]); +int ui_cmd_vapitest(ui_cmdline_t *cmd,int argc,char *argv[]); +int ui_cmd_vapishow(ui_cmdline_t *cmd,int argc,char *argv[]); +int ui_cmd_vapidump(ui_cmdline_t *cmd,int argc,char *argv[]); +int ui_cmd_vapistatus(ui_cmdline_t *cmd,int argc,char *argv[]); + +static char *rectypes[7] = { + "GPRS ", + "SOC ", + "DATA ", + "BUF ", + "TRC ", + "EXIT ", + "FPRS " +}; + +int ui_cmd_vapidump(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + uint64_t *ptr; + uint64_t *eptr; + int recnum = 0; + + if (vapi_logptr == 0) { + xprintf("Diagnostic did not record any log records\n"); + return -1; + } + + ptr = (uint64_t *) (intptr_t) vapi_logstart; + eptr = (uint64_t *) (intptr_t) vapi_logptr; + + xprintf("*** VAPI LOG START %s\n", +#ifdef __MIPSEB + "big-endian" +#else + "little-endian" +#endif + ); + + while (ptr < eptr) { + xprintf("%6d %016llX %016llX %016llX %016llX\n", + recnum, + ptr[0],ptr[1],ptr[2],ptr[3]); + ptr += 4; + recnum++; + } + + xprintf("*** VAPI LOG END\n"); + + return 0; + + +} + +int ui_cmd_vapishow(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + uint64_t *ptr; + uint64_t *eptr; + uint32_t a,b; + uint32_t ts,len,fmt; + unsigned int idx; + int recnum = 0; + + if (vapi_logptr == 0) { + xprintf("Diagnostic did not record any log records\n"); + return -1; + } + + ptr = (uint64_t *) (intptr_t) vapi_logstart; + eptr = (uint64_t *) (intptr_t) vapi_logptr; + + while (ptr < eptr) { + a = (ptr[VAPI_IDX_SIGNATURE]) >> 32; + b = (ptr[VAPI_IDX_SIGNATURE]) & 0xFFFFFFFF; + if ((a & VAPI_SEAL_MASK) != VAPI_CFESEAL) { + xprintf("Incorrect record seal at %08X\n",ptr); + break; + } + + fmt = (a & VAPI_FMT_MASK); + + xprintf("%5d ID=%08X CPU%d %s RA=%08X ", + recnum, + b, + (a & VAPI_PRID_MASK) >> VAPI_PRNUM_SHIFT, + rectypes[fmt], + ptr[VAPI_IDX_RA]); + + ts = (ptr[VAPI_IDX_SIZE]) >> 32; + len = ((ptr[VAPI_IDX_SIZE]) & 0xFFFFFFFF); + + xprintf("TS=%08X ",ts); + + switch (fmt) { + case VAPI_FMT_GPRS: + xprintf("Len=%d\n",len); + for (idx = 0; idx < len; idx += 2) { + xprintf(" %016llX %016llX\n", + ptr[VAPI_IDX_DATA+idx], + ptr[VAPI_IDX_DATA+idx+1]); + } + break; + case VAPI_FMT_SOC: + xprintf("Len=%d\n",len); + for (idx = 0; idx < len; idx += 2) { + xprintf(" Reg=%016llX Val=%016llX\n", + ptr[VAPI_IDX_DATA+idx], + ptr[VAPI_IDX_DATA+idx+1]); + } + break; + case VAPI_FMT_DATA: + xprintf("Data=%016llX\n",ptr[VAPI_IDX_DATA]); + break; + case VAPI_FMT_BUFFER: + xprintf("Addr=%08X\n",(intptr_t) ptr[VAPI_IDX_DATA]); + for (idx = 0; idx < len-1; idx += 2) { + xprintf(" %016llX %016llX\n", + ptr[VAPI_IDX_DATA+idx+1], + ptr[VAPI_IDX_DATA+idx+2]); + } + if (idx != (len-1)) { + xprintf(" %016llX\n", + ptr[VAPI_IDX_DATA+idx+1]); + } + break; + case VAPI_FMT_TRACE: + xprintf("\n"); + break; + case VAPI_FMT_EXIT: + xprintf("Stat=%016llX\n",ptr[VAPI_IDX_DATA]); + break; + default: + xprintf("\n"); + break; + } + + ptr += 3 + len; + recnum++; + } + + return 0; + +} + +int ui_cmd_vapitest(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + + vapitest(); + + xprintf("LogStart=%llX LogEnd=%llX LogPtr=%llX\n", + vapi_logstart,vapi_logend,vapi_logptr); + + return 0; +} + +int ui_cmd_vapistatus(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + + xprintf("VAPI Exit Status = <%016llX>\n", vapi_status); + return 0; +} + +int ui_cmd_vapirun(ui_cmdline_t *cmd,int argc,char *argv[]) +{ + int mode; /* 0 = cached, 1 = uncached, 2 = mc mode */ + + mode = 0; + if (cmd_sw_isset(cmd,"-uncached")) mode = 1; + if (cmd_sw_isset(cmd,"-mc")) mode = 2; + + vapi_run(mode); + return -1; +} + + +int ui_init_vapicmds(void) +{ + cmd_addcmd("vapi run", + ui_cmd_vapirun, + NULL, + "Run a program using the VAPI reset vector.", + "vapi run\n" + "Executes a previously loaded VAPI program by resetting the\n" + "CPUs and jumping directly to user code. The program\n" + "must be located at absolute address 0x8002_0000\n", + "-uncached;Start execution at 0xA002_0000 (KSEG1)|" + "-mc;Start execution at 0xBFD0_0000"); + + cmd_addcmd("vapi test", + ui_cmd_vapitest, + NULL, + "Test VAPI interface.", + "vapi test\n\n" + "Do some basic calls to the VAPI interface, then return to CFE\n\n", + ""); + + cmd_addcmd("vapi dump", + ui_cmd_vapidump, + NULL, + "Show VAPI log in an easily processed format.", + "vapi dump\n\n" + "Display the VAPI log in a format that is more easily postprocessed\n" + "by external programs.\n\n", + ""); + + cmd_addcmd("vapi show", + ui_cmd_vapishow, + NULL, + "Show VAPI log.\n", + "vapi show\n\n" + "Display the VAPI log in a human readable form (sort of)\n\n", + ""); + + cmd_addcmd("vapi status", + ui_cmd_vapistatus, + NULL, + "Print last VAPI exit status.\n", + "vapi status\n\n" + "Display the exit status of the last VAPI program that was run\n", + ""); + + return 0; +} + +#endif diff --git a/cfe/cfe/verif/vapi.S b/cfe/cfe/verif/vapi.S new file mode 100644 index 0000000..a65fb6d --- /dev/null +++ b/cfe/cfe/verif/vapi.S @@ -0,0 +1,1150 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Verification Test APIs File: vapi.S + * + * This module contains special low-level routines for use + * by verification programs. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "bsp_config.h" +#include "mipsmacros.h" + +#if CFG_VAPI + +#if (CFG_EMBEDDED_PIC) +#error "CFG_VAPI is not compatible with relocatable code" +#endif + +#include "cfe_devfuncs.h" + +#include "sb1250_defs.h" +#include "sb1250_regs.h" +#include "sb1250_scd.h" + +#include "vapi.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CALLKSEG1(x) \ + la t0,x ; \ + or t0,K1BASE ; \ + jal t0 + +#ifndef CFG_STACK_SIZE +#define STACK_SIZE 8192 +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +#define REGIDX(x) ((x)*8) + +#define SAVE_RA REGIDX(0) +#define SAVE_GP REGIDX(1) +#define SAVE_AT REGIDX(2) +#define SAVE_T0 REGIDX(3) +#define SAVE_T1 REGIDX(4) +#define SAVE_T2 REGIDX(5) +#define SAVE_T3 REGIDX(6) +#define SAVE_A0 REGIDX(7) +#define SAVE_A1 REGIDX(8) +#define SAVE_A2 REGIDX(9) + +#define SAVE_SIZE REGIDX(10) + +#define SAVETEMPS(x) \ + .set noat ; \ + la k0,x ; \ + sd ra,SAVE_RA(k0) ; \ + sd gp,SAVE_GP(k0) ; \ + sd AT,SAVE_AT(k0) ; \ + sd t0,SAVE_T0(k0) ; \ + sd t1,SAVE_T1(k0) ; \ + sd t2,SAVE_T2(k0) ; \ + sd t3,SAVE_T3(k0) ; \ + sd a0,SAVE_A0(k0) ; \ + sd a1,SAVE_A1(k0) ; \ + sd a2,SAVE_A2(k0) ; \ + .set at ; \ + la gp,_gp + + +#define RESTORETEMPS(x) \ + .set noat ; \ + la k0,x ; \ + ld ra,SAVE_RA(k0) ; \ + ld gp,SAVE_GP(k0) ; \ + ld AT,SAVE_AT(k0) ; \ + ld t0,SAVE_T0(k0) ; \ + ld t1,SAVE_T1(k0) ; \ + ld t2,SAVE_T2(k0) ; \ + ld t3,SAVE_T3(k0) ; \ + ld a0,SAVE_A0(k0) ; \ + ld a1,SAVE_A1(k0) ; \ + ld a2,SAVE_A2(k0) ; \ + .set at + +#define RECPTR t3 + +#define CHECKPTR(label) \ + ld RECPTR,vapi_logptr ; \ + ld t0,vapi_logend ; \ + beq RECPTR,zero,label ; \ + bge RECPTR,t0,label + +#define SETRECTYPE(x,id) \ + ld RECPTR,vapi_logptr ; \ + li t2,(VAPI_CFESEAL | (x)) ; \ + mfc0 t0,C0_PRID ; \ + srl t0,t0,25 ; \ + and t0,t0,7 ; \ + sll t0,t0,VAPI_PRNUM_SHIFT ; \ + or t2,t2,t0 ; \ + dsll t2,t2,32 ; \ + or t2,id ; \ + sd t2,VAPI_REC_SIGNATURE(RECPTR) ; \ + mfc0 t2,C0_COUNT ; \ + dsll t2,t2,32 ; \ + sd t2,VAPI_REC_SIZE(RECPTR) ; \ + sd ra,VAPI_REC_RA(RECPTR) + + + +#define SETRECLEN_CONST(len) \ + ld t2,VAPI_REC_SIZE(RECPTR) ; \ + or t2,len ; \ + sd t2,VAPI_REC_SIZE(RECPTR) + +#define SETRECLEN_REG(r) \ + ld t2,VAPI_REC_SIZE(RECPTR) ; \ + or t2,r ; \ + sd t2,VAPI_REC_SIZE(RECPTR) + + +/* ********************************************************************* + * Data + ********************************************************************* */ + + .sdata + + .globl vapi_logstart + .globl vapi_logend + .globl vapi_logptr + .globl vapi_status + .globl vapi_logover + +vapi_logstart: .dword 0 +vapi_logend: .dword 0 +vapi_logptr: .dword 0 +vapi_status: .dword -1 +vapi_logover: .dword 0 + + .extern mem_heapstart + + .bss + + .comm vapi_regsave,REGIDX(64) + + .text + + .globl vapi_socregs +vapi_socregs: + +#ifdef _P5064_ + .word 0, 0 +#else +#include "sb1250_socregs.inc" +#endif + + .text + + .extern cfe_warmstart + + .set reorder + + +/* ********************************************************************* + * VAPI_KSEG0_SWITCH + * + * Hack the return address so we will come back in KSEG0 + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(vapi_kseg0_switch) + + and ra,(K0SIZE-1) + or ra,K0BASE + jr ra + +END(vapi_kseg0_switch) + +/* ********************************************************************* + * VAPI_EXIT(status) + * + * Return from diagnostic to firmware + * + * Input parameters: + * a0 - exit status (0=ok, else error) + * + * Return value: + * does not return + ********************************************************************* */ + + +LEAF(vapi_exit) + + move k1,a0 + + +/* + * Reinitialize the CPU and the caches + */ + + bal vapi_kseg1_switch + CALLKSEG1(sb1_cpu_init) +/* + * Don't initialize the caches again. Some diags + * leave data in the caches and if we invalidate it + * now we won't be able to see what happened. + */ +/* CALLKSEG1(sb1250_l1cache_init) */ +/* CALLKSEG1(sb1250_l2cache_init) */ + +#ifdef __long64 +/* + * Set back to 64-bit mode. Don't worry about the hazard + * here, it'll be eons before we need to use the KX space. + */ + mfc0 t0,C0_SR + or t0,t0,M_SR_KX + mtc0 t0,C0_SR +#endif + + bal vapi_kseg0_switch + + li a0,0x42424242 # 'BBBB' + jal board_setleds + + move a0,k1 + + la gp,_gp + sd a0,vapi_status + LR sp,mem_heapstart + ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) + +/* + * Create a log record for the EXIT status. + */ + ld t0,vapi_logptr + beq t0,zero,nolog + + SETRECTYPE(VAPI_FMT_EXIT,0) + SETRECLEN_CONST(1) + sd a0,VAPI_REC_DATA(RECPTR) + add RECPTR,32 + sd RECPTR,vapi_logptr +nolog: + li a0,0x45454545 # 'EEEE' + jal board_setleds + +#if CFG_MULTI_CPUS + + /* + * Restart the other CPU if it was left in RESET. + */ + + la t2,PHYS_TO_K1(A_SCD_SYSTEM_CFG) + ld t0,0(t2) + dli t1,M_SYS_CPU_RESET_1 # Reset mask + and t0,t1 # Test if CPU is in reset + beq t0,zero,1f # skip if not in reset + + li a0,1 # Whack the CPU + jal altcpu_cmd_stop # and put it back in idle +1: +#endif + + ld a0,vapi_status + j cfe_warmstart + +END(vapi_exit) + + + +/* ********************************************************************* + * VAPI_DUMPGPRS() + * + * Dump the GPRs to the console + * + * Input parameters: + * nothing + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +LEAF(vapi_dumpgprs) + + .set noat + la k0,vapi_regsave + sd $0,REGIDX(0)(k0) + sd $1,REGIDX(1)(k0) + sd $2,REGIDX(2)(k0) + sd $3,REGIDX(3)(k0) + sd $4,REGIDX(4)(k0) + sd $5,REGIDX(5)(k0) + sd $6,REGIDX(6)(k0) + sd $7,REGIDX(7)(k0) + sd $8,REGIDX(8)(k0) + sd $9,REGIDX(9)(k0) + sd $10,REGIDX(10)(k0) + sd $11,REGIDX(11)(k0) + sd $12,REGIDX(12)(k0) + sd $13,REGIDX(13)(k0) + sd $14,REGIDX(14)(k0) + sd $15,REGIDX(15)(k0) + sd $16,REGIDX(16)(k0) + sd $17,REGIDX(17)(k0) + sd $18,REGIDX(18)(k0) + sd $19,REGIDX(19)(k0) + sd $20,REGIDX(20)(k0) + sd $21,REGIDX(21)(k0) + sd $22,REGIDX(22)(k0) + sd $23,REGIDX(23)(k0) + sd $24,REGIDX(24)(k0) + sd $25,REGIDX(25)(k0) + sd $26,REGIDX(26)(k0) /* k0 */ + sd $27,REGIDX(27)(k0) + sd $28,REGIDX(28)(k0) + sd $29,REGIDX(29)(k0) + sd $30,REGIDX(30)(k0) + sd $31,REGIDX(31)(k0) + .set at + +# Save some CP0 registers here. +#define LSAVECP0(cp0,idx) \ + dmfc0 t0,cp0 ; \ + sd t0,REGIDX(idx)(k0) + + LSAVECP0(C0_INX,32) + LSAVECP0(C0_RAND,33) + LSAVECP0(C0_TLBLO0,34) + LSAVECP0(C0_TLBLO1,35) + LSAVECP0(C0_CTEXT,36) + LSAVECP0(C0_PGMASK,37) + LSAVECP0(C0_WIRED,38) + LSAVECP0(C0_BADVADDR,39) + LSAVECP0(C0_COUNT,40) + LSAVECP0(C0_TLBHI,41) + LSAVECP0(C0_COMPARE,42) + LSAVECP0(C0_SR,43) + LSAVECP0(C0_CAUSE,44) + LSAVECP0(C0_EPC,45) + LSAVECP0(C0_PRID,46) + LSAVECP0(C0_CONFIG,47) + LSAVECP0(C0_LLADDR,48) + LSAVECP0(C0_WATCHLO,49) + LSAVECP0(C0_WATCHHI,50) + LSAVECP0(C0_XCTEXT,51) + LSAVECP0(C0_ECC,52) + LSAVECP0(C0_CACHEERR,53) + LSAVECP0(C0_TAGLO,54) + LSAVECP0(C0_TAGHI,55) + LSAVECP0(C0_ERREPC,56) + + + move a0,k0 /* pass addr of regs */ + la gp,_gp + LR sp,mem_heapstart + ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) + jal vapi_dodumpregs /* dump registers in 'C' */ + + .set noat + la k0,vapi_regsave + ld $1,REGIDX(1)(k0) + ld $2,REGIDX(2)(k0) + ld $3,REGIDX(3)(k0) + ld $4,REGIDX(4)(k0) + ld $5,REGIDX(5)(k0) + ld $6,REGIDX(6)(k0) + ld $7,REGIDX(7)(k0) + ld $8,REGIDX(8)(k0) + ld $9,REGIDX(9)(k0) + ld $10,REGIDX(10)(k0) + ld $11,REGIDX(11)(k0) + ld $12,REGIDX(12)(k0) + ld $13,REGIDX(13)(k0) + ld $14,REGIDX(14)(k0) + ld $15,REGIDX(15)(k0) + ld $16,REGIDX(16)(k0) + ld $17,REGIDX(17)(k0) + ld $18,REGIDX(18)(k0) + ld $19,REGIDX(19)(k0) + ld $20,REGIDX(20)(k0) + ld $21,REGIDX(21)(k0) + ld $22,REGIDX(22)(k0) + ld $23,REGIDX(23)(k0) + ld $24,REGIDX(24)(k0) + ld $25,REGIDX(25)(k0) + /*ld $26,REGIDX(26)(k0) don't restore k0 */ + ld $27,REGIDX(27)(k0) + ld $28,REGIDX(28)(k0) + ld $29,REGIDX(29)(k0) + ld $30,REGIDX(30)(k0) + ld $31,REGIDX(31)(k0) + .set at + + j ra + +END(vapi_dumpgprs) + + +/* ********************************************************************* + * VAPI_SETLOG(start,end) + * + * Set the address of the log buffer. This call is required + * before any data will be stored in the log. + * + * Input parameters: + * a0 - start of log buffer, 64-bit aligned + * a1 - end of log buffer, 64-bit aligned + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +LEAF(vapi_setlog) + + SAVETEMPS(vapi_regsave) + + sd a0,vapi_logstart + sd a0,vapi_logptr + sd a1,vapi_logend + sd zero,vapi_logover + + RESTORETEMPS(vapi_regsave) + + j ra + +END(vapi_setlog) + +/* ********************************************************************* + * VAPI_LOGTRACE(id) + * + * Store a the contents of the trace buffer to the log + * + * Input parameters: + * a0 - low 32 bits are the ID code to store with the entry + * in the log. + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +LEAF(vapi_logtrace) + + j ra + +END(vapi_logtrace) + + +/* ********************************************************************* + * VAPI_LOGSINGLE(id,value) + * + * Store a single value in the log. + * + * Input parameters: + * a0 - low 32 bits are the ID code to store with the entry + * in the log. + * a1 - value to store in the log + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +LEAF(vapi_logsingle) + + + SAVETEMPS(vapi_regsave) + + CHECKPTR(99f) + + SETRECTYPE(VAPI_FMT_DATA,a0) + SETRECLEN_CONST(1) + + sd a1,VAPI_REC_DATA(RECPTR) + + add RECPTR,32 # one record + sd RECPTR,vapi_logptr + +99: RESTORETEMPS(vapi_regsave) + + j ra + +END(vapi_logsingle) + +/* ********************************************************************* + * VAPI_LOGDATA(id,addr,cnt) + * + * Store multiple values in the log + * + * Input parameters: + * a0 - low 32 bits are the ID code to store with the entry + * in the log. + * a1 - Address of values to store in the log + * a2 - number of 64-bit values to store in the log + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +LEAF(vapi_logdata) + + SAVETEMPS(vapi_regsave) + + CHECKPTR(99f) + + SETRECTYPE(VAPI_FMT_BUFFER,a0) + + add t1,RECPTR,VAPI_REC_DATA # a1 = ptr to data ara + + sd a1,0(t1) + add t1,8 + + move k0,a2 # counter for words + +1: beq k0,zero,2f + ld t0,0(a1) + sd t0,0(t1) + add a1,8 + add t1,8 + sub k0,1 + b 1b + +2: add k0,a2,1 # total number of words + SETRECLEN_REG(k0) + sll k0,k0,3 # number of words we wrote + add k0,24 # size of header + add RECPTR,k0 + sd RECPTR,vapi_logptr + +99: RESTORETEMPS(vapi_regsave) + + j ra + +END(vapi_logdata) + + +/* ********************************************************************* + * VAPI_SAVESOC(id) + * + * Save the SOC registers in the log + * + * Input parameters: + * a0 - low 32 bits are the ID code to store with the entry + * in the log + * a1 - bitmask of SOC agents to save + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +LEAF(vapi_savesoc) + + SAVETEMPS(vapi_regsave) + + CHECKPTR(99f) + + li t0,VAPI_CFESEAL | VAPI_FMT_SOC + dsll t0,t0,32 + or t0,a0 + mfc0 t1,C0_PRID + srl t1,t1,25 + and t1,t1,7 + sll t1,t1,VAPI_PRNUM_SHIFT + or t0,t0,t1 + ld t1,vapi_logptr + + sd t0,VAPI_REC_SIGNATURE(t1) + mfc0 t0,C0_COUNT + dsll t0,t0,32 + sd t0,VAPI_REC_SIZE(t1) + sd ra,VAPI_REC_RA(t1) + + move a2,zero # Counts how many we write + + la t2,vapi_socregs + +1: lw t0,0(t2) # get flags + beq t0,zero,2f + and t0,t0,a1 # test flags + beq t0,zero,3f # skip if no flags set + + lw t0,4(t2) # get address of register + + sd t0,VAPI_REC_DATA(t1) # store address of register + add t1,8 # next destination addr + add a2,1 # count the words written + + or t0,K1BASE # Make K1seg + ld t0,0(t0) # Read SOC register + + sd t0,VAPI_REC_DATA(t1) # Store in log + add t1,8 # next destination addr + add a2,1 # count the words written + +3: add t2,8 # next reg from table + + b 1b + +2: ld t0,vapi_logptr # get original pointer + ld a1,VAPI_REC_SIZE(t0) # Get C0_COUNT value + or a1,a2 # OR in the record size + sd a1,VAPI_REC_SIZE(t0) # put the record size back + + add t1,24 # Account for extra fields in record + sd t1,vapi_logptr # Update the pointer + +99: RESTORETEMPS(vapi_regsave) + + j ra + +END(vapi_savesoc) + +/* ********************************************************************* + * VAPI_LOGGPRS(id) + * + * Save the general purpose registers and certain CP0 values + * in the log. + * + * Input parameters: + * a0 - low 32 bits are the ID code to store with the entry + * in the log + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +#define REGLOG(x) (VAPI_REC_DATA+REGIDX(x)) +#define MAXREGS 57 +#define REGLOGMAX REGLOG(MAXREGS) + +LEAF(vapi_loggprs) + + SAVETEMPS(vapi_regsave) + CHECKPTR(99f) + + .set noat + ld k0,vapi_logptr + sd $0,REGLOG(0)(k0) + sd $1,REGLOG(1)(k0) + sd $2,REGLOG(2)(k0) + sd $3,REGLOG(3)(k0) + sd $4,REGLOG(4)(k0) + sd $5,REGLOG(5)(k0) + sd $6,REGLOG(6)(k0) + sd $7,REGLOG(7)(k0) + sd $8,REGLOG(8)(k0) + sd $9,REGLOG(9)(k0) + sd $10,REGLOG(10)(k0) + sd $11,REGLOG(11)(k0) + sd $12,REGLOG(12)(k0) + sd $13,REGLOG(13)(k0) + sd $14,REGLOG(14)(k0) + sd $15,REGLOG(15)(k0) + sd $16,REGLOG(16)(k0) + sd $17,REGLOG(17)(k0) + sd $18,REGLOG(18)(k0) + sd $19,REGLOG(19)(k0) + sd $20,REGLOG(20)(k0) + sd $21,REGLOG(21)(k0) + sd $22,REGLOG(22)(k0) + sd $23,REGLOG(23)(k0) + sd $24,REGLOG(24)(k0) + sd $25,REGLOG(25)(k0) + sd $26,REGLOG(26)(k0) + sd $27,REGLOG(27)(k0) + sd $28,REGLOG(28)(k0) + sd $29,REGLOG(29)(k0) + sd $30,REGLOG(30)(k0) + sd $31,REGLOG(31)(k0) + .set at + + +# Save some CP0 registers here. +#define SAVECP0(cp0,idx) \ + dmfc0 t0,cp0 ; \ + sd t0,REGLOG(idx)(k0) + + SAVECP0(C0_INX,32) + SAVECP0(C0_RAND,33) + SAVECP0(C0_TLBLO0,34) + SAVECP0(C0_TLBLO1,35) + SAVECP0(C0_CTEXT,36) + SAVECP0(C0_PGMASK,37) + SAVECP0(C0_WIRED,38) + SAVECP0(C0_BADVADDR,39) + SAVECP0(C0_COUNT,40) + SAVECP0(C0_TLBHI,41) + SAVECP0(C0_COMPARE,42) + SAVECP0(C0_SR,43) + SAVECP0(C0_CAUSE,44) + SAVECP0(C0_EPC,45) + SAVECP0(C0_PRID,46) + SAVECP0(C0_CONFIG,47) + SAVECP0(C0_LLADDR,48) + SAVECP0(C0_WATCHLO,49) + SAVECP0(C0_WATCHHI,50) + SAVECP0(C0_XCTEXT,51) + SAVECP0(C0_ECC,52) + SAVECP0(C0_CACHEERR,53) + SAVECP0(C0_TAGLO,54) + SAVECP0(C0_TAGHI,55) + SAVECP0(C0_ERREPC,56) + + SETRECTYPE(VAPI_FMT_GPRS,a0) + SETRECLEN_CONST(MAXREGS) + add RECPTR,REGLOGMAX + sd RECPTR,vapi_logptr + +99: RESTORETEMPS(vapi_regsave) + + j ra # go home + +END(vapi_loggprs) + + +/* ********************************************************************* + * VAPI_LOGFPRS(id) + * + * Save the floating point unit's registers + * in the log. + * + * Input parameters: + * a0 - low 32 bits are the ID code to store with the entry + * in the log + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + + +#define SAVEFPR(cp1,idx) \ + dmfc1 t0,cp1 ; \ + sd t0,FPREGLOG(idx)(k0) +#define SAVECP1(cp1,idx) \ + cfc1 t0,cp1 ; \ + sd t0,FPREGLOG(idx)(k0) + +#define FPREGLOG(x) (VAPI_REC_DATA+REGIDX(x)) +#define FPMAXREGS 37 +#define FPREGLOGMAX FPREGLOG(FPMAXREGS) + +LEAF(vapi_logfprs) + + SAVETEMPS(vapi_regsave) + CHECKPTR(99f) + + ld k0,vapi_logptr + SAVEFPR($0,0) + SAVEFPR($1,1) + SAVEFPR($2,2) + SAVEFPR($3,3) + SAVEFPR($4,4) + SAVEFPR($5,5) + SAVEFPR($6,6) + SAVEFPR($7,7) + SAVEFPR($8,8) + SAVEFPR($9,9) + SAVEFPR($10,10) + SAVEFPR($11,11) + SAVEFPR($12,12) + SAVEFPR($13,13) + SAVEFPR($14,14) + SAVEFPR($15,15) + SAVEFPR($16,16) + SAVEFPR($17,17) + SAVEFPR($18,18) + SAVEFPR($19,19) + SAVEFPR($20,20) + SAVEFPR($21,21) + SAVEFPR($22,22) + SAVEFPR($23,23) + SAVEFPR($24,24) + SAVEFPR($25,25) + SAVEFPR($26,26) + SAVEFPR($27,27) + SAVEFPR($28,28) + SAVEFPR($29,29) + SAVEFPR($30,30) + SAVEFPR($31,31) + + SAVECP1($0,32) /* FIR */ + SAVECP1($31,33) /* Status */ + SAVECP1($25,34) /* condition codes */ + SAVECP1($26,35) /* Exceptions */ + SAVECP1($28,36) /* enables */ + + SETRECTYPE(VAPI_FMT_FPRS,a0) + SETRECLEN_CONST(FPMAXREGS) + add RECPTR,FPREGLOGMAX + sd RECPTR,vapi_logptr + +99: RESTORETEMPS(vapi_regsave) + + j ra # go home + +END(vapi_logfprs) + +/* ********************************************************************* + * VAPI_PUTS(string) + * + * Display a string on the console + * + * Input parameters: + * a0 - pointer to null-terminated string + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + +LEAF(vapi_puts) + + .set noat + la k0,vapi_regsave + sd $0,REGIDX(0)(k0) + sd $1,REGIDX(1)(k0) + sd $2,REGIDX(2)(k0) + sd $3,REGIDX(3)(k0) + sd $4,REGIDX(4)(k0) + sd $5,REGIDX(5)(k0) + sd $6,REGIDX(6)(k0) + sd $7,REGIDX(7)(k0) + sd $8,REGIDX(8)(k0) + sd $9,REGIDX(9)(k0) + sd $10,REGIDX(10)(k0) + sd $11,REGIDX(11)(k0) + sd $12,REGIDX(12)(k0) + sd $13,REGIDX(13)(k0) + sd $14,REGIDX(14)(k0) + sd $15,REGIDX(15)(k0) + sd $16,REGIDX(16)(k0) + sd $17,REGIDX(17)(k0) + sd $18,REGIDX(18)(k0) + sd $19,REGIDX(19)(k0) + sd $20,REGIDX(20)(k0) + sd $21,REGIDX(21)(k0) + sd $22,REGIDX(22)(k0) + sd $23,REGIDX(23)(k0) + sd $24,REGIDX(24)(k0) + sd $25,REGIDX(25)(k0) + sd $26,REGIDX(26)(k0) /* k0 */ + sd $27,REGIDX(27)(k0) + sd $28,REGIDX(28)(k0) + sd $29,REGIDX(29)(k0) + sd $30,REGIDX(30)(k0) + sd $31,REGIDX(31)(k0) + .set at + + la gp,_gp + LR sp,mem_heapstart + ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) + jal vapi_doputs /* dump registers in 'C' */ + + .set noat + la k0,vapi_regsave + ld $1,REGIDX(1)(k0) + ld $2,REGIDX(2)(k0) + ld $3,REGIDX(3)(k0) + ld $4,REGIDX(4)(k0) + ld $5,REGIDX(5)(k0) + ld $6,REGIDX(6)(k0) + ld $7,REGIDX(7)(k0) + ld $8,REGIDX(8)(k0) + ld $9,REGIDX(9)(k0) + ld $10,REGIDX(10)(k0) + ld $11,REGIDX(11)(k0) + ld $12,REGIDX(12)(k0) + ld $13,REGIDX(13)(k0) + ld $14,REGIDX(14)(k0) + ld $15,REGIDX(15)(k0) + ld $16,REGIDX(16)(k0) + ld $17,REGIDX(17)(k0) + ld $18,REGIDX(18)(k0) + ld $19,REGIDX(19)(k0) + ld $20,REGIDX(20)(k0) + ld $21,REGIDX(21)(k0) + ld $22,REGIDX(22)(k0) + ld $23,REGIDX(23)(k0) + ld $24,REGIDX(24)(k0) + ld $25,REGIDX(25)(k0) + /*ld $26,REGIDX(26)(k0) don't restore k0 */ + ld $27,REGIDX(27)(k0) + ld $28,REGIDX(28)(k0) + ld $29,REGIDX(29)(k0) + ld $30,REGIDX(30)(k0) + ld $31,REGIDX(31)(k0) + .set at + + j ra + +END(vapi_puts) + +/* ********************************************************************* + * VAPI_SETLEDS(leds) + * + * Set the onboard LEDS on the swarm board. + * + * Input parameters: + * a0 - LED value, "ABCD" is 0x41424344 + * + * Return value: + * nothing + * + * Registers used: + * k0 - scratch register for CFE + ********************************************************************* */ + + +LEAF(vapi_setleds) + + SAVETEMPS(vapi_regsave) + + jal board_setleds + + RESTORETEMPS(vapi_regsave) + + j ra + +END(vapi_setleds) + +/* ********************************************************************* + * VAPI_KSEG1_SWITCH + * + * Hack the return address so we will come back in KSEG1 (uncached) + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(vapi_kseg1_switch) + + and ra,(K0SIZE-1) + or ra,K1BASE + jr ra + +END(vapi_kseg1_switch) + + +/* ********************************************************************* + * VAPI_RUN() + * + * Jump to the diagnostic program, which must be loaded at the + * special address (typically 8002_0000). First we flush the + * cache, then set magic #'s in the mailbox. Finally, the core + * is reset. On restart, we do minimal initialization and jump + * directly to the diagnostic. + * + * Input parameters: + * a0 - nonzero to restart uncached. + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(vapi_run) + + /* + * Run uncached + */ + + bal vapi_kseg1_switch # now running in KSEG1 + + /* + * Flush the caches + */ + + move s0,a0 # L2 flush trashes A0 + CALLKSEG1(sb1250_l1cache_flush_d) + CALLKSEG1(sb1250_l1cache_inval_i) + CALLKSEG1(sb1250_l2cache_flush) + move a0,s0 + +#ifdef _P5064_ + + /* In the case of the P5064, just jump directly to the entry point */ + + li t0,VAPI_DIAG_ENTRY + j t0 + +#else + + /* + * Set the magic code in the mailbox. + */ + + li t0,-1 + la t1,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CLR_CPU)) + sd t0,0(t1) + + dli t0,VAPI_MAGIC_NUMBER + beq a0,0,1f + dli t0,VAPI_MAGIC_NUMBER_UNC + beq a0,1,1f + dli t0,VAPI_MAGIC_NUMBER_MC +1: la t1,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_SET_CPU)) + sd t0,0(t1) + + /* + * Whack the reset line. + */ +#if defined(_PTSWARM_) + li k0,PHYS_TO_K1(0x1B0A0000+32+8*3) +#else + li k0,PHYS_TO_K1(0x100A0000+32+8*3) +#endif + li k1,'!' + + li t1,PHYS_TO_K1(A_SCD_SYSTEM_CFG) + ld t2,0(t1) + dli t0,M_SYS_CPU_RESET_0 | M_SYS_CPU_RESET_1 + or t2,t2,t0 + bal vapi_kseg0_switch + .align 5 +#if defined(_CSWARM_) || defined(_SWARM_) || defined(_PTSWARM_) + sb k1,0(k0) +#else + nop +#endif + sync /* flush the write buffer */ + sd t2,0(t1) +1: b 1b + + /* + * And he never returned, no he never returned... and his fate + * is still unknown, he will ride forever 'neath the cycles of + * the SB1, he's the core that never returned! + */ +#endif + + + +END(vapi_run) + + +LEAF(vapi_flushtest) + + move s1,ra + + /* + * Run uncached + */ + + bal vapi_kseg1_switch # now running in KSEG1 + + /* + * Flush the caches + */ + + move s0,a0 # L2 flush trashes A0 + CALLKSEG1(sb1250_l1cache_flush_d) + CALLKSEG1(sb1250_l1cache_inval_i) + CALLKSEG1(sb1250_l2cache_flush) + move a0,s0 + + /* + * Back to cached + */ + + bal vapi_kseg0_switch # now running in KSEG1 + + move ra,s1 + j ra + +END(vapi_flushtest) + + +#endif /* CFG_VAPI */ + +/* ********************************************************************* + * End + ********************************************************************* */ + + diff --git a/cfe/cfe/verif/vapi.h b/cfe/cfe/verif/vapi.h new file mode 100644 index 0000000..1deb8a5 --- /dev/null +++ b/cfe/cfe/verif/vapi.h @@ -0,0 +1,242 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Verification Test APIs File: vapi.h + * + * This module contains special low-level routines for use + * by verification programs. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#define VAPI_EPTSEAL 0x56415049 +#define VAPI_CFESEAL 0xCFE10000 +#define VAPI_SEAL_MASK 0xFFFF0000 +#define VAPI_FMT_MASK 0x000000FF +#define VAPI_PRID_MASK 0x0000FF00 + +#define VAPI_DIAG_ENTRY 0x80020000 +#define VAPI_DIAG_ENTRY_UNC 0xA0020000 +#define VAPI_DIAG_ENTRY_MC 0xBFD00000 +#define VAPI_MAGIC_NUMBER 0x1CFE2CFE3CFE4CFE +#define VAPI_MAGIC_NUMBER_UNC 0x0CFE1CFE2CFE3CFE +#define VAPI_MAGIC_NUMBER_MC 0xACFEBCFECCFEDCFE + +#define VAPI_FMT_GPRS 0 +#define VAPI_FMT_SOC 1 +#define VAPI_FMT_DATA 2 +#define VAPI_FMT_BUFFER 3 +#define VAPI_FMT_TRACE 4 +#define VAPI_FMT_EXIT 5 +#define VAPI_FMT_FPRS 6 + +#define VAPI_PRNUM_SHIFT 8 + +#define VAPI_REC_SIGNATURE 0 +#define VAPI_REC_SIZE 8 +#define VAPI_REC_RA 16 +#define VAPI_REC_DATA 24 + +#define VAPI_IDX_SIGNATURE 0 +#define VAPI_IDX_SIZE 1 +#define VAPI_IDX_RA 2 +#define VAPI_IDX_DATA 3 + + +#define VAPI_FUNC_EXIT 0x9fc00510 +#define VAPI_FUNC_DUMPGPRS 0x9fc00520 +#define VAPI_FUNC_SETLOG 0x9fc00530 +#define VAPI_FUNC_LOGVALUE 0x9fc00540 +#define VAPI_FUNC_LOGDATA 0x9fc00550 +#define VAPI_FUNC_LOGTRACE 0x9fc00560 +#define VAPI_FUNC_LOGSOC 0x9fc00570 +#define VAPI_FUNC_LOGGPRS 0x9fc00580 +#define VAPI_FUNC_DUMPSTRING 0x9fc00590 +#define VAPI_FUNC_SETLEDS 0x9fc005a0 +#define VAPI_FUNC_LOGFPRS 0x9fc005b0 + + +#define VAPI_LOG_SETBUF(start,end) \ + .set push ; \ + .set reorder ; \ + la a0, start ; \ + la a1, end ; \ + li k0, VAPI_FUNC_SETLOG ; \ + jalr k0 ; \ + .set pop + +#define VAPI_EXIT_CONST(val) \ + .set push ; \ + .set reorder ; \ + li a0, val ; \ + li k0, VAPI_FUNC_EXIT ; \ + jr k0 ; \ + .set pop + +#define VAPI_EXIT_REG(val) \ + .set push ; \ + .set reorder ; \ + move a0, val ; \ + li k0, VAPI_FUNC_EXIT ; \ + jr k0 ; \ + .set pop + +#define VAPI_LOG_CONST(id,value) \ + .set push ; \ + .set reorder ; \ + li a0, id ; \ + li a1, value ; \ + li k0, VAPI_FUNC_LOGVALUE ; \ + jalr k0 ; \ + .set pop + +#define VAPI_LOG_REG(id,value) \ + .set push ; \ + .set reorder ; \ + li a0, id ; \ + move a1, value ; \ + li k0, VAPI_FUNC_LOGVALUE ; \ + jalr k0 ; \ + .set pop + +#define VAPI_LOG_BUFFER(id,addr,nwords) \ + .set push ; \ + .set reorder ; \ + li a0,id ; \ + la a1,addr ; \ + li a2,nwords ; \ + li k0, VAPI_FUNC_LOGDATA ; \ + jalr k0 ; \ + .set pop + +#define VAPI_PUTS(text) \ + .set push ; \ + .set reorder ; \ + b 1f ; \ +2: .asciz text ; \ + .align 4 ; \ +1: la a0, 2b ; \ + li k0, VAPI_FUNC_DUMPSTRING ; \ + jalr k0 ; \ + .set pop + +#define VAPI_PRINTGPRS() \ + .set push ; \ + .set reorder ; \ + li k0, VAPI_FUNC_DUMPGPRS ; \ + jalr k0 ; \ + .set pop + +#define VAPI_LOG_GPRS(id) \ + .set push ; \ + .set reorder ; \ + li a0, id ; \ + li k0, VAPI_FUNC_LOGGPRS ; \ + jalr k0 ; \ + .set pop + +#define VAPI_LOG_FPRS(id) \ + .set push ; \ + .set reorder ; \ + li a0, id ; \ + li k0, VAPI_FUNC_LOGFPRS ; \ + jalr k0 ; \ + .set pop + +#define VAPI_LOG_TRACE(id) \ + .set push ; \ + .set reorder ; \ + li a0, id ; \ + li k0, VAPI_FUNC_LOGTRACE ; \ + jalr k0 ; \ + .set pop + +#define VAPI_LOG_SOCSTATE(id,bits) \ + .set push ; \ + .set reorder ; \ + li a0, id ; \ + li a1, bits ; \ + li k0, VAPI_FUNC_LOGSOC ; \ + jalr k0 ; \ + .set pop + +#define VAPI_SETLEDS(a,b,c,d) \ + .set push ; \ + .set reorder ; \ + li a0, ((a) << 24) | ((b) << 16) | ((c) << 8) | (d) ; \ + li k0, VAPI_FUNC_SETLEDS ; \ + jalr k0 ; \ + .set pop + +#ifndef SOC_AGENT_MC0 +#define SOC_AGENT_MC0 0x00000001 +#define SOC_AGENT_MC1 0x00000002 +#define SOC_AGENT_MC 0x00000003 +#define SOC_AGENT_L2 0x00000004 +#define SOC_AGENT_MACDMA0 0x00000008 +#define SOC_AGENT_MACDMA1 0x00000010 +#define SOC_AGENT_MACDMA2 0x00000020 +#define SOC_AGENT_MACDMA 0x00000038 +#define SOC_AGENT_MACRMON0 0x00000040 +#define SOC_AGENT_MACRMON1 0x00000080 +#define SOC_AGENT_MACRMON2 0x00000100 +#define SOC_AGENT_MACRMON 0x000001C0 +#define SOC_AGENT_MAC0 0x00000200 +#define SOC_AGENT_MAC1 0x00000400 +#define SOC_AGENT_MAC2 0x00000800 +#define SOC_AGENT_MAC 0x00000E00 +#define SOC_AGENT_DUART 0x00001000 +#define SOC_AGENT_GENCS 0x00002000 +#define SOC_AGENT_GEN 0x00004000 +#define SOC_AGENT_GPIO 0x00008000 +#define SOC_AGENT_SMBUS0 0x00010000 +#define SOC_AGENT_SMBUS1 0x00020000 +#define SOC_AGENT_SMBUS 0x00030000 +#define SOC_AGENT_TIMER 0x00040000 +#define SOC_AGENT_SCD 0x00080000 +#define SOC_AGENT_BUSERR 0x00100000 +#define SOC_AGENT_DM 0x00200000 +#define SOC_AGENT_IMR0 0x00400000 +#define SOC_AGENT_IMR1 0x00800000 +#define SOC_AGENT_IMR 0x00C00000 +#endif + + + diff --git a/cfe/cfe/verif/vapisubr.c b/cfe/cfe/verif/vapisubr.c new file mode 100644 index 0000000..1ec130a --- /dev/null +++ b/cfe/cfe/verif/vapisubr.c @@ -0,0 +1,122 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Verification Test APIs File: vapisubr.c + * + * This module contains special low-level routines for use + * by verification programs. The routines here are the "C" + * routines for higher-level functions. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "bsp_config.h" +#include "lib_types.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_console.h" + +#if CFG_VAPI + +void vapi_doputs(char *str); +void vapi_dodumpregs(uint64_t *gprs); + +const static char * const gpregnames[] = { + "$0/zero","$1/AT","$2/v0","$3/v1","$4/a0","$5/a1","$6/a2","$7/a3", + "$8/t0","$9/t1","$10/t2","$11/t3","$12/t4","$13/t5","$14/t6","$15/t7", + "$16/s0","$17/s1","$18/s2","$19/s3","$20/s4","$21/s5","$22/s6","$23/s7", + "$24/t8","$25/t9","$26/k0","$27/k1","$28/gp","$29/sp","$30/fp","$31/ra", + "INX", + "RAND", + "TLBLO0", + "TLBLO1", + "CTEXT", + "PGMASK", + "WIRED", + "BADVADDR", + "COUNT", + "TLBHI", + "COMPARE", + "SR", + "CAUSE", + "EPC", + "PRID", + "CONFIG", + "LLADDR", + "WATCHLO", + "WATCHHI", + "XCTEXT", + "ECC", + "CACHEERR", + "TAGLO", + "TAGHI", + "ERREPC"}; + + + + +void vapi_doputs(char *str) +{ + xprintf("# %s\n",str); +} + +void vapi_dodumpregs(uint64_t *gprs) +{ + int cnt = sizeof(gpregnames)/sizeof(char *); + int idx; + + xprintf("# GPRS:\n"); + for (idx = 0; idx < cnt; idx++) { + if ((idx & 1) == 0) xprintf("# "); + xprintf(" %8s=%016llX ",gpregnames[idx],gprs[idx]); + if ((idx & 1) == 1) xprintf("\n"); + } + xprintf("\n"); + +} + +#endif /* CFG_VAPI */ + +/* ********************************************************************* + * End + ********************************************************************* */ + + diff --git a/cfe/cfe/verif/vapitest.S b/cfe/cfe/verif/vapitest.S new file mode 100644 index 0000000..4199f4e --- /dev/null +++ b/cfe/cfe/verif/vapitest.S @@ -0,0 +1,108 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Verification Test APIs File: vapitest.S + * + * This module contains special low-level routines for use + * by verification programs. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "bsp_config.h" + +#if CFG_VAPI + +#if (CFG_EMBEDDED_PIC) +#error "CFG_VAPI is not compatible with relocatable code" +#endif + + +#include "vapi.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + .text + +testbuf: .dword 0x123456789ABCDEF0 + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xAABBCCDD + .dword 0xFEDCBA9876543210 + +LEAF(vapitest) + + sub sp,8 + sd ra,0(sp) + + VAPI_LOG_SETBUF(0x80200000,0x80300000) + + + VAPI_LOG_CONST(0x100,0xABCDEF) + VAPI_LOG_REG(0x101,sp) + VAPI_LOG_BUFFER(0x102,testbuf,10) + VAPI_PUTS("Hello world.\n") + VAPI_LOG_SOCSTATE(0x103,SOC_AGENT_DUART) + VAPI_PRINTGPRS(); + VAPI_LOG_CONST(0x1EE,0xEEEEEEEE) + VAPI_LOG_GPRS(0x199) + VAPI_SETLEDS('V','A','P','I') + + ld ra,0(sp) + add sp,8 + j ra + +END(vapitest) + + +#endif /* CFG_VAPI */ + +/* ********************************************************************* + * End + ********************************************************************* */ + + diff --git a/cfe/cfe/x86emu/LICENSE b/cfe/cfe/x86emu/LICENSE new file mode 100644 index 0000000..a3ede4a --- /dev/null +++ b/cfe/cfe/x86emu/LICENSE @@ -0,0 +1,17 @@ + License information + ------------------- + +The x86emu library is under a BSD style license, comaptible +with the XFree86 and X licenses used by XFree86. The +original x86emu libraries were under the GNU General Public +License. Due to license incompatibilities between the GPL +and the XFree86 license, the original authors of the code +decided to allow a license change. If you have submitted +code to the original x86emu project, and you don't agree +with the license change, please contact us and let you +know. Your code will be removed to comply with your wishes. + +If you have any questions about this, please send email to +x86emu@linuxlabs.com or KendallB@scitechsoft.com for +clarification. + diff --git a/cfe/cfe/x86emu/Makefile b/cfe/cfe/x86emu/Makefile new file mode 100644 index 0000000..6b02c1a --- /dev/null +++ b/cfe/cfe/x86emu/Makefile @@ -0,0 +1,2 @@ + +ALLOBJS += debug.o decode.o fpu.o ops.o ops2.o prim_ops.o sys.o diff --git a/cfe/cfe/x86emu/README b/cfe/cfe/x86emu/README new file mode 100644 index 0000000..c7351ba --- /dev/null +++ b/cfe/cfe/x86emu/README @@ -0,0 +1,12 @@ + +This is a simple X86 emulator. The original source for this +was taken from the XFree86 project. This code is used to +interpret the X86 instructions in the ROM on the VGA +adapter to initialize the card to text mode. Once initialized, +this emulator is no longer needed. + +** Read the 'LICENSE' file before using this in production code ** + +The XFree86 license is similar to the BSD license. + + diff --git a/cfe/cfe/x86emu/debug.c b/cfe/cfe/x86emu/debug.c new file mode 100644 index 0000000..3e26a50 --- /dev/null +++ b/cfe/cfe/x86emu/debug.c @@ -0,0 +1,462 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: This file contains the code to handle debugging of the +* emulator. +* +****************************************************************************/ +/* $XFree86: xc/extras/x86emu/src/x86emu/debug.c,v 1.4 2000/04/17 16:29:45 eich Exp $ */ + +#include "x86emu/x86emui.h" +#ifdef IN_MODULE +#include "xf86_ansic.h" +#else +#include +#ifndef _CFE_ +#include +#endif +#endif + +#ifdef _CFE_ +#include "cfe_console.h" +#endif + + +/*----------------------------- Implementation ----------------------------*/ + +#ifdef DEBUG + +static void print_encoded_bytes (u16 s, u16 o); +static void print_decoded_instruction (void); +static int parse_line (char *s, int *ps, int *n); + +/* should look something like debug's output. */ +void X86EMU_trace_regs (void) +{ + if (DEBUG_TRACE()) { + x86emu_dump_regs(); + } + if (DEBUG_DECODE() && ! DEBUG_DECODE_NOPRINT()) { + printk("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip); + print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip); + print_decoded_instruction(); + } +} + +void X86EMU_trace_xregs (void) +{ + if (DEBUG_TRACE()) { + x86emu_dump_xregs(); + } +} + +void x86emu_just_disassemble (void) +{ + /* + * This routine called if the flag DEBUG_DISASSEMBLE is set kind + * of a hack! + */ + printk("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip); + print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip); + print_decoded_instruction(); +} + +static u16 disassemble_forward (u16 seg, u16 off, int n) +{ + X86EMU_sysEnv tregs; + int i; + u8 op1; + u16 finaloffset; + /* + * hack, hack, hack. What we do is use the exact machinery set up + * for execution, except that now there is an additional state + * flag associated with the "execution", and we are using a copy + * of the register struct. All the major opcodes, once fully + * decoded, have the following two steps: TRACE_REGS(r,m); + * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to + * the preprocessor. The TRACE_REGS macro expands to: + * + * if (debug&DEBUG_DISASSEMBLE) + * {just_disassemble(); goto EndOfInstruction;} + * if (debug&DEBUG_TRACE) trace_regs(r,m); + * + * ...... and at the last line of the routine. + * + * EndOfInstruction: end_instr(); + * + * Up to the point where TRACE_REG is expanded, NO modifications + * are done to any register EXCEPT the IP register, for fetch and + * decoding purposes. + * + * This was done for an entirely different reason, but makes a + * nice way to get the system to help debug codes. + */ + tregs = M; + M.x86.R_IP = off; + M.x86.R_CS = seg; + M.x86.saved_ip = off; + M.x86.saved_cs = seg; + + /* reset the decoding buffers */ + M.x86.enc_str_pos = 0; + M.x86.enc_pos = 0; + + /* turn on the "disassemble only, no execute" flag */ + M.x86.debug |= DEBUG_DISASSEMBLE_F; + + /* DUMP NEXT n instructions to screen in straight_line fashion */ + /* + * This looks like the regular instruction fetch stream, except + * that when this occurs, each fetched opcode, upon seeing the + * DEBUG_DISASSEMBLE flag set, exits immediately after decoding + * the instruction. XXX --- CHECK THAT MEM IS NOT AFFECTED!!! + * Note the use of a copy of the register structure... + */ + for (i=0; i 256) return; + seg = fetch_data_word_abs(0,iv*4); + off = fetch_data_word_abs(0,iv*4+2); + printk("%04x:%04x ", seg, off); +} + +void X86EMU_dump_memory (u16 seg, u16 off, u32 amt) +{ + u32 start = off & 0xfffffff0; + u32 end = (off+16) & 0xfffffff0; + u32 i; + u32 current; + + current = start; + while (end <= off + amt) { + printk("%04x:%04x ", seg, start); + for (i=start; i< off; i++) + printk(" "); + for ( ; i< end; i++) + printk("%02x ", fetch_data_byte_abs(seg,i)); + printk("\n"); + start = end; + end = start + 16; + } +} + +void x86emu_single_step (void) +{ + char s[1024]; + int ps[10]; + int ntok; + int cmd; + int done; + int segment; + int offset; + static int breakpoint; + static int noDecode = 1; + + char *p; + + if (DEBUG_BREAK()) { + if (M.x86.saved_ip != breakpoint) { + return; + } + else { + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + M.x86.debug |= DEBUG_TRACE_F; + M.x86.debug &= ~DEBUG_BREAK_F; + print_decoded_instruction (); + X86EMU_trace_regs(); + } + } + done=0; + offset = M.x86.saved_ip; + while (!done) { +#ifdef _CFE_ + cmd = console_readline("-",s,1023); + if (cmd) { s[cmd] = '\n'; s[cmd+1] = 0;} + p = s; +#else + printk("-"); + p = fgets(s, 1023, stdin); +#endif + cmd = parse_line(s, ps, &ntok); + switch(cmd) { + case 'u': + if (ntok == 2) { offset = ps[1]; } + offset = disassemble_forward(M.x86.saved_cs,(u16)offset,10); + break; + case 'd': + if (ntok == 2) { + segment = M.x86.saved_cs; + offset = ps[1]; + X86EMU_dump_memory(segment,(u16)offset,16); + offset += 16; + } else if (ntok == 3) { + segment = ps[1]; + offset = ps[2]; + X86EMU_dump_memory(segment,(u16)offset,16); + offset += 16; + } else { + segment = M.x86.saved_cs; + X86EMU_dump_memory(segment,(u16)offset,16); + offset += 16; + } + break; + case 'c': + M.x86.debug ^= DEBUG_TRACECALL_F; + break; + case 's': + M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F; + break; + case 'r': + X86EMU_trace_regs(); + break; + case 'x': + X86EMU_trace_xregs(); + break; + case 'g': + if (ntok == 2) { + breakpoint = ps[1]; + if (noDecode) { + M.x86.debug |= DEBUG_DECODE_NOPRINT_F; + } else { + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + } + M.x86.debug &= ~DEBUG_TRACE_F; + M.x86.debug |= DEBUG_BREAK_F; + done = 1; + } + break; + case 'q': + M.x86.debug &= ~DEBUG_TRACE_F; + M.x86.debug &= ~DEBUG_BREAK_F; + M.x86.debug &= ~DEBUG_STEP_F; + M.x86.debug &= ~DEBUG_DECODE_F; + done = 1; + break; + case 'P': + noDecode = (noDecode)?0:1; + printk("Toggled decoding to %s\n",(noDecode)?"FALSE":"TRUE"); + break; + case 't': + case 0: + done = 1; + break; + } + } +} + +int X86EMU_trace_on(void) +{ + return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; +} + +int X86EMU_trace_off(void) +{ + return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F); +} + +static int parse_line (char *s, int *ps, int *n) +{ + int cmd; + + *n = 0; + while(*s == ' ' || *s == '\t') s++; + ps[*n] = *s; + switch (*s) { + case '\n': + *n += 1; + return 0; + default: + cmd = *s; + *n += 1; + } + + while (1) { + while (*s != ' ' && *s != '\t' && *s != '\n') s++; + + if (*s == '\n') + return cmd; + + while(*s == ' ' || *s == '\t') s++; +#ifdef _CFE_ + ps[*n] = xtoi(s); +#else + sscanf(s,"%x",&ps[*n]); +#endif + *n += 1; + } +} + +#endif /* DEBUG */ + +void x86emu_dump_regs (void) +{ + printk("\tAX=%04x ", M.x86.R_AX ); + printk("BX=%04x ", M.x86.R_BX ); + printk("CX=%04x ", M.x86.R_CX ); + printk("DX=%04x ", M.x86.R_DX ); + printk("SP=%04x ", M.x86.R_SP ); + printk("BP=%04x ", M.x86.R_BP ); + printk("SI=%04x ", M.x86.R_SI ); + printk("DI=%04x\n", M.x86.R_DI ); + printk("\tDS=%04x ", M.x86.R_DS ); + printk("ES=%04x ", M.x86.R_ES ); + printk("SS=%04x ", M.x86.R_SS ); + printk("CS=%04x ", M.x86.R_CS ); + printk("IP=%04x ", M.x86.R_IP ); + if (ACCESS_FLAG(F_OF)) printk("OV "); /* CHECKED... */ + else printk("NV "); + if (ACCESS_FLAG(F_DF)) printk("DN "); + else printk("UP "); + if (ACCESS_FLAG(F_IF)) printk("EI "); + else printk("DI "); + if (ACCESS_FLAG(F_SF)) printk("NG "); + else printk("PL "); + if (ACCESS_FLAG(F_ZF)) printk("ZR "); + else printk("NZ "); + if (ACCESS_FLAG(F_AF)) printk("AC "); + else printk("NA "); + if (ACCESS_FLAG(F_PF)) printk("PE "); + else printk("PO "); + if (ACCESS_FLAG(F_CF)) printk("CY "); + else printk("NC "); + printk("\n"); +} + +void x86emu_dump_xregs (void) +{ + printk("\tEAX=%08x ", M.x86.R_EAX ); + printk("EBX=%08x ", M.x86.R_EBX ); + printk("ECX=%08x ", M.x86.R_ECX ); + printk("EDX=%08x \n", M.x86.R_EDX ); + printk("\tESP=%08x ", M.x86.R_ESP ); + printk("EBP=%08x ", M.x86.R_EBP ); + printk("ESI=%08x ", M.x86.R_ESI ); + printk("EDI=%08x\n", M.x86.R_EDI ); + printk("\tDS=%04x ", M.x86.R_DS ); + printk("ES=%04x ", M.x86.R_ES ); + printk("SS=%04x ", M.x86.R_SS ); + printk("CS=%04x ", M.x86.R_CS ); + printk("EIP=%08x\n\t", M.x86.R_EIP ); + if (ACCESS_FLAG(F_OF)) printk("OV "); /* CHECKED... */ + else printk("NV "); + if (ACCESS_FLAG(F_DF)) printk("DN "); + else printk("UP "); + if (ACCESS_FLAG(F_IF)) printk("EI "); + else printk("DI "); + if (ACCESS_FLAG(F_SF)) printk("NG "); + else printk("PL "); + if (ACCESS_FLAG(F_ZF)) printk("ZR "); + else printk("NZ "); + if (ACCESS_FLAG(F_AF)) printk("AC "); + else printk("NA "); + if (ACCESS_FLAG(F_PF)) printk("PE "); + else printk("PO "); + if (ACCESS_FLAG(F_CF)) printk("CY "); + else printk("NC "); + printk("\n"); +} diff --git a/cfe/cfe/x86emu/decode.c b/cfe/cfe/x86emu/decode.c new file mode 100644 index 0000000..10082eb --- /dev/null +++ b/cfe/cfe/x86emu/decode.c @@ -0,0 +1,1000 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: This file includes subroutines which are related to +* instruction decoding and accessess of immediate data via IP. etc. +* +****************************************************************************/ + +/* $XFree86: xc/extras/x86emu/src/x86emu/decode.c,v 1.8 2000/12/13 03:19:34 tsi Exp $ */ + +#include "x86emu/x86emui.h" +#include "cfe_console.h" + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +REMARKS: +Handles any pending asychronous interrupts. +****************************************************************************/ +static void x86emu_intr_handle(void) +{ + u8 intno; + + if (M.x86.intr & INTR_SYNCH) { + intno = M.x86.intno; + if (_X86EMU_intrTab[intno]) { + (*_X86EMU_intrTab[intno])(intno); + } else { + push_word((u16)M.x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + push_word(M.x86.R_CS); + M.x86.R_CS = mem_access_word(intno * 4 + 2); + push_word(M.x86.R_IP); + M.x86.R_IP = mem_access_word(intno * 4); + M.x86.intr = 0; + } + } +} + +/**************************************************************************** +PARAMETERS: +intrnum - Interrupt number to raise + +REMARKS: +Raise the specified interrupt to be handled before the execution of the +next instruction. +****************************************************************************/ +void x86emu_intr_raise( + u8 intrnum) +{ + M.x86.intno = intrnum; + M.x86.intr |= INTR_SYNCH; +} + +#ifdef DEBUG +extern u8 inb(u32); +#endif + +/**************************************************************************** +REMARKS: +Main execution loop for the emulator. We return from here when the system +halts, which is normally caused by a stack fault when we return from the +original real mode call. +****************************************************************************/ +void X86EMU_exec(void) +{ + u8 op1; + + M.x86.intr = 0; + DB(x86emu_end_instr();) + + for (;;) { +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + /* If debugging, save the IP and CS values. */ + SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP); + INC_DECODED_INST_LEN(1); + if (M.x86.intr) { + if (M.x86.intr & INTR_HALTED) { +DB( printk("halted\n"); + X86EMU_trace_regs();) + return; + } + if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) || + !ACCESS_FLAG(F_IF)) { + x86emu_intr_handle(); + } + } +#ifdef DEBUG + if (inb(0x3f8 + 5) & 1) { + M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; + } +#endif + op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); + (*x86emu_optab[op1])(op1); + } +} + +/**************************************************************************** +REMARKS: +Halts the system by setting the halted system flag. +****************************************************************************/ +void X86EMU_halt_sys(void) +{ + M.x86.intr |= INTR_HALTED; +} + +/**************************************************************************** +PARAMETERS: +mod - Mod value from decoded byte +regh - Reg h value from decoded byte +regl - Reg l value from decoded byte + +REMARKS: +Raise the specified interrupt to be handled before the execution of the +next instruction. + +NOTE: Do not inline this function, as (*sys_rdb) is already inline! +****************************************************************************/ +void fetch_decode_modrm( + int *mod, + int *regh, + int *regl) +{ + int fetched; + +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); + INC_DECODED_INST_LEN(1); + *mod = (fetched >> 6) & 0x03; + *regh = (fetched >> 3) & 0x07; + *regl = (fetched >> 0) & 0x07; +} + +/**************************************************************************** +RETURNS: +Immediate byte value read from instruction queue + +REMARKS: +This function returns the immediate byte from the instruction queue, and +moves the instruction pointer to the next value. + +NOTE: Do not inline this function, as (*sys_rdb) is already inline! +****************************************************************************/ +u8 fetch_byte_imm(void) +{ + u8 fetched; + +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); + INC_DECODED_INST_LEN(1); + return fetched; +} + +/**************************************************************************** +RETURNS: +Immediate word value read from instruction queue + +REMARKS: +This function returns the immediate byte from the instruction queue, and +moves the instruction pointer to the next value. + +NOTE: Do not inline this function, as (*sys_rdw) is already inline! +****************************************************************************/ +u16 fetch_word_imm(void) +{ + u16 fetched; + +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); + M.x86.R_IP += 2; + INC_DECODED_INST_LEN(2); + return fetched; +} + +/**************************************************************************** +RETURNS: +Immediate lone value read from instruction queue + +REMARKS: +This function returns the immediate byte from the instruction queue, and +moves the instruction pointer to the next value. + +NOTE: Do not inline this function, as (*sys_rdw) is already inline! +****************************************************************************/ +u32 fetch_long_imm(void) +{ + u32 fetched; + +DB( if (CHECK_IP_FETCH()) + x86emu_check_ip_access();) + fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); + M.x86.R_IP += 4; + INC_DECODED_INST_LEN(4); + return fetched; +} + +/**************************************************************************** +RETURNS: +Value of the default data segment + +REMARKS: +Inline function that returns the default data segment for the current +instruction. + +On the x86 processor, the default segment is not always DS if there is +no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to +addresses relative to SS (ie: on the stack). So, at the minimum, all +decodings of addressing modes would have to set/clear a bit describing +whether the access is relative to DS or SS. That is the function of the +cpu-state-varible M.x86.mode. There are several potential states: + + repe prefix seen (handled elsewhere) + repne prefix seen (ditto) + + cs segment override + ds segment override + es segment override + fs segment override + gs segment override + ss segment override + + ds/ss select (in absense of override) + +Each of the above 7 items are handled with a bit in the mode field. +****************************************************************************/ +_INLINE u32 get_data_segment(void) +{ +#define GET_SEGMENT(segment) + switch (M.x86.mode & SYSMODE_SEGMASK) { + case 0: /* default case: use ds register */ + case SYSMODE_SEGOVR_DS: + case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS: + return M.x86.R_DS; + case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */ + return M.x86.R_SS; + case SYSMODE_SEGOVR_CS: + case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS: + return M.x86.R_CS; + case SYSMODE_SEGOVR_ES: + case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS: + return M.x86.R_ES; + case SYSMODE_SEGOVR_FS: + case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS: + return M.x86.R_FS; + case SYSMODE_SEGOVR_GS: + case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS: + return M.x86.R_GS; + case SYSMODE_SEGOVR_SS: + case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS: + return M.x86.R_SS; + default: +#ifdef DEBUG + printk("error: should not happen: multiple overrides.\n"); +#endif + HALT_SYS(); + return 0; + } +} + +/**************************************************************************** +PARAMETERS: +offset - Offset to load data from + +RETURNS: +Byte value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u8 fetch_data_byte( + uint offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((u16)get_data_segment(), offset); +#endif + return (*sys_rdb)((get_data_segment() << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +offset - Offset to load data from + +RETURNS: +Word value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u16 fetch_data_word( + uint offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((u16)get_data_segment(), offset); +#endif + return (*sys_rdw)((get_data_segment() << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +offset - Offset to load data from + +RETURNS: +Long value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u32 fetch_data_long( + uint offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((u16)get_data_segment(), offset); +#endif + return (*sys_rdl)((get_data_segment() << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to load data from +offset - Offset to load data from + +RETURNS: +Byte value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u8 fetch_data_byte_abs( + uint segment, + uint offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + return (*sys_rdb)(((u32)segment << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to load data from +offset - Offset to load data from + +RETURNS: +Word value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u16 fetch_data_word_abs( + uint segment, + uint offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + return (*sys_rdw)(((u32)segment << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to load data from +offset - Offset to load data from + +RETURNS: +Long value read from the absolute memory location. + +NOTE: Do not inline this function as (*sys_rdX) is already inline! +****************************************************************************/ +u32 fetch_data_long_abs( + uint segment, + uint offset) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + return (*sys_rdl)(((u32)segment << 4) + offset); +} + +/**************************************************************************** +PARAMETERS: +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a word value to an segmented memory location. The segment used is +the current 'default' segment, which may have been overridden. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_byte( + uint offset, + u8 val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((u16)get_data_segment(), offset); +#endif + (*sys_wrb)((get_data_segment() << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a word value to an segmented memory location. The segment used is +the current 'default' segment, which may have been overridden. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_word( + uint offset, + u16 val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((u16)get_data_segment(), offset); +#endif + (*sys_wrw)((get_data_segment() << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a long value to an segmented memory location. The segment used is +the current 'default' segment, which may have been overridden. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_long( + uint offset, + u32 val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access((u16)get_data_segment(), offset); +#endif + (*sys_wrl)((get_data_segment() << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to store data at +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a byte value to an absolute memory location. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_byte_abs( + uint segment, + uint offset, + u8 val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + (*sys_wrb)(((u32)segment << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to store data at +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a word value to an absolute memory location. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_word_abs( + uint segment, + uint offset, + u16 val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + (*sys_wrw)(((u32)segment << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +segment - Segment to store data at +offset - Offset to store data at +val - Value to store + +REMARKS: +Writes a long value to an absolute memory location. + +NOTE: Do not inline this function as (*sys_wrX) is already inline! +****************************************************************************/ +void store_data_long_abs( + uint segment, + uint offset, + u32 val) +{ +#ifdef DEBUG + if (CHECK_DATA_ACCESS()) + x86emu_check_data_access(segment, offset); +#endif + (*sys_wrl)(((u32)segment << 4) + offset, val); +} + +/**************************************************************************** +PARAMETERS: +reg - Register to decode + +RETURNS: +Pointer to the appropriate register + +REMARKS: +Return a pointer to the register given by the R/RM field of the +modrm byte, for byte operands. Also enables the decoding of instructions. +****************************************************************************/ +u8* decode_rm_byte_register( + int reg) +{ + switch (reg) { + case 0: + DECODE_PRINTF("AL"); + return &M.x86.R_AL; + case 1: + DECODE_PRINTF("CL"); + return &M.x86.R_CL; + case 2: + DECODE_PRINTF("DL"); + return &M.x86.R_DL; + case 3: + DECODE_PRINTF("BL"); + return &M.x86.R_BL; + case 4: + DECODE_PRINTF("AH"); + return &M.x86.R_AH; + case 5: + DECODE_PRINTF("CH"); + return &M.x86.R_CH; + case 6: + DECODE_PRINTF("DH"); + return &M.x86.R_DH; + case 7: + DECODE_PRINTF("BH"); + return &M.x86.R_BH; + } + HALT_SYS(); + return NULL; /* NOT REACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +PARAMETERS: +reg - Register to decode + +RETURNS: +Pointer to the appropriate register + +REMARKS: +Return a pointer to the register given by the R/RM field of the +modrm byte, for word operands. Also enables the decoding of instructions. +****************************************************************************/ +u16* decode_rm_word_register( + int reg) +{ + switch (reg) { + case 0: + DECODE_PRINTF("AX"); + return &M.x86.R_AX; + case 1: + DECODE_PRINTF("CX"); + return &M.x86.R_CX; + case 2: + DECODE_PRINTF("DX"); + return &M.x86.R_DX; + case 3: + DECODE_PRINTF("BX"); + return &M.x86.R_BX; + case 4: + DECODE_PRINTF("SP"); + return &M.x86.R_SP; + case 5: + DECODE_PRINTF("BP"); + return &M.x86.R_BP; + case 6: + DECODE_PRINTF("SI"); + return &M.x86.R_SI; + case 7: + DECODE_PRINTF("DI"); + return &M.x86.R_DI; + } + HALT_SYS(); + return NULL; /* NOTREACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +PARAMETERS: +reg - Register to decode + +RETURNS: +Pointer to the appropriate register + +REMARKS: +Return a pointer to the register given by the R/RM field of the +modrm byte, for dword operands. Also enables the decoding of instructions. +****************************************************************************/ +u32* decode_rm_long_register( + int reg) +{ + switch (reg) { + case 0: + DECODE_PRINTF("EAX"); + return &M.x86.R_EAX; + case 1: + DECODE_PRINTF("ECX"); + return &M.x86.R_ECX; + case 2: + DECODE_PRINTF("EDX"); + return &M.x86.R_EDX; + case 3: + DECODE_PRINTF("EBX"); + return &M.x86.R_EBX; + case 4: + DECODE_PRINTF("ESP"); + return &M.x86.R_ESP; + case 5: + DECODE_PRINTF("EBP"); + return &M.x86.R_EBP; + case 6: + DECODE_PRINTF("ESI"); + return &M.x86.R_ESI; + case 7: + DECODE_PRINTF("EDI"); + return &M.x86.R_EDI; + } + HALT_SYS(); + return NULL; /* NOTREACHED OR REACHED ON ERROR */ +} + +/**************************************************************************** +PARAMETERS: +reg - Register to decode + +RETURNS: +Pointer to the appropriate register + +REMARKS: +Return a pointer to the register given by the R/RM field of the +modrm byte, for word operands, modified from above for the weirdo +special case of segreg operands. Also enables the decoding of instructions. +****************************************************************************/ +u16* decode_rm_seg_register( + int reg) +{ + switch (reg) { + case 0: + DECODE_PRINTF("ES"); + return &M.x86.R_ES; + case 1: + DECODE_PRINTF("CS"); + return &M.x86.R_CS; + case 2: + DECODE_PRINTF("SS"); + return &M.x86.R_SS; + case 3: + DECODE_PRINTF("DS"); + return &M.x86.R_DS; + case 4: + case 5: + case 6: + case 7: + DECODE_PRINTF("ILLEGAL SEGREG"); + break; + } + HALT_SYS(); + return NULL; /* NOT REACHED OR REACHED ON ERROR */ +} + + +/**************************************************************************** +PARAMETERS: +sib - SIB value to decode + +RETURNS: +Offset in memory for the address decoding + +REMARKS: +Return the offset given by the specified SIB byte. + +NOTE: The code which specifies the corresponding segment (ds vs ss) + below in the case of [BP+..]. The assumption here is that at the + point that this subroutine is called, the bit corresponding to + SYSMODE_SEG_DS_SS will be zero. After every instruction + except the segment override instructions, this bit (as well + as any bits indicating segment overrides) will be clear. So + if a SS access is needed, set this bit. Otherwise, DS access + occurs (unless any of the segment override bits are set). +****************************************************************************/ +static unsigned decode_sib_address( + int sib) +{ + unsigned ss,index,base; + unsigned addr = 0; + + ss = (sib >> 6) & 3; + index = (sib >> 3) & 7; + base = (sib & 7); + + switch (base) { + case 0: + DECODE_PRINTF("[EAX"); + addr = M.x86.R_EAX; + break; + case 1: + DECODE_PRINTF("[ECX"); + addr = M.x86.R_ECX; + break; + case 2: + DECODE_PRINTF("[EDX"); + addr = M.x86.R_EDX; + break; + case 3: + DECODE_PRINTF("[EBX"); + addr = M.x86.R_EBX; + break; + case 4: + DECODE_PRINTF("[ESP"); + addr = M.x86.R_ESP; + break; + case 5: + DECODE_PRINTF("[invalid"); + addr = M.x86.R_ESP;/* incorrect */ + break; + case 6: + DECODE_PRINTF("[invalid"); + addr = M.x86.R_ESP;/* incorrect */ + break; + case 7: + DECODE_PRINTF("[invalid"); + addr = M.x86.R_ESP; /* incorrect */ + break; + } + + switch (index) { + case 0: + DECODE_PRINTF("+EAX"); + addr += M.x86.R_EAX*(1< 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + s32 imm; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_long(srcoffset); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + s16 imm; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_word(srcoffset); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + res = (s16)srcval * (s16)imm; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + s32 imm; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_long(srcoffset); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + s16 imm; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_word(srcoffset); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + res = (s16)srcval * (s16)imm; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*srcreg; + u32 res_lo,res_hi; + s32 imm; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg,*srcreg; + u32 res; + s16 imm; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + res = (s16)*srcreg * (s16)imm; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6a +****************************************************************************/ +void x86emuOp_push_byte_IMM(u8 X86EMU_UNUSED(op1)) +{ + s16 imm; + + START_OF_INSTR(); + imm = (s8)fetch_byte_imm(); + DECODE_PRINTF2("PUSH\t%d\n", imm); + TRACE_AND_STEP(); + push_word(imm); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6b +****************************************************************************/ +void x86emuOp_imul_byte_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint srcoffset; + s8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("IMUL\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_long(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_word(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + res = (s16)srcval * (s16)imm; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_long(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_word(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + res = (s16)srcval * (s16)imm; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_long(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_word(srcoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + res = (s16)srcval * (s16)imm; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*srcreg; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg,*srcreg; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%d\n", (s32)imm); + res = (s16)*srcreg * (s16)imm; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6c +****************************************************************************/ +void x86emuOp_ins_byte(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("INSB\n"); + ins(1); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6d +****************************************************************************/ +void x86emuOp_ins_word(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("INSD\n"); + ins(4); + } else { + DECODE_PRINTF("INSW\n"); + ins(2); + } + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6e +****************************************************************************/ +void x86emuOp_outs_byte(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("OUTSB\n"); + outs(1); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6f +****************************************************************************/ +void x86emuOp_outs_word(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("OUTSD\n"); + outs(4); + } else { + DECODE_PRINTF("OUTSW\n"); + outs(2); + } + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x70 +****************************************************************************/ +void x86emuOp_jump_near_O(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if overflow flag is set */ + START_OF_INSTR(); + DECODE_PRINTF("JO\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_OF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x71 +****************************************************************************/ +void x86emuOp_jump_near_NO(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if overflow is not set */ + START_OF_INSTR(); + DECODE_PRINTF("JNO\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (!ACCESS_FLAG(F_OF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x72 +****************************************************************************/ +void x86emuOp_jump_near_B(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if carry flag is set. */ + START_OF_INSTR(); + DECODE_PRINTF("JB\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_CF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x73 +****************************************************************************/ +void x86emuOp_jump_near_NB(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if carry flag is clear. */ + START_OF_INSTR(); + DECODE_PRINTF("JNB\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (!ACCESS_FLAG(F_CF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x74 +****************************************************************************/ +void x86emuOp_jump_near_Z(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if zero flag is set. */ + START_OF_INSTR(); + DECODE_PRINTF("JZ\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_ZF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x75 +****************************************************************************/ +void x86emuOp_jump_near_NZ(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if zero flag is clear. */ + START_OF_INSTR(); + DECODE_PRINTF("JNZ\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (!ACCESS_FLAG(F_ZF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x76 +****************************************************************************/ +void x86emuOp_jump_near_BE(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if carry flag is set or if the zero + flag is set. */ + START_OF_INSTR(); + DECODE_PRINTF("JBE\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x77 +****************************************************************************/ +void x86emuOp_jump_near_NBE(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if carry flag is clear and if the zero + flag is clear */ + START_OF_INSTR(); + DECODE_PRINTF("JNBE\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x78 +****************************************************************************/ +void x86emuOp_jump_near_S(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if sign flag is set */ + START_OF_INSTR(); + DECODE_PRINTF("JS\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_SF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x79 +****************************************************************************/ +void x86emuOp_jump_near_NS(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if sign flag is clear */ + START_OF_INSTR(); + DECODE_PRINTF("JNS\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (!ACCESS_FLAG(F_SF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x7a +****************************************************************************/ +void x86emuOp_jump_near_P(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if parity flag is set (even parity) */ + START_OF_INSTR(); + DECODE_PRINTF("JP\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_PF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x7b +****************************************************************************/ +void x86emuOp_jump_near_NP(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + + /* jump to byte offset if parity flag is clear (odd parity) */ + START_OF_INSTR(); + DECODE_PRINTF("JNP\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (!ACCESS_FLAG(F_PF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x7c +****************************************************************************/ +void x86emuOp_jump_near_L(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + int sf, of; + + /* jump to byte offset if sign flag not equal to overflow flag. */ + START_OF_INSTR(); + DECODE_PRINTF("JL\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + if (sf ^ of) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x7d +****************************************************************************/ +void x86emuOp_jump_near_NL(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + int sf, of; + + /* jump to byte offset if sign flag not equal to overflow flag. */ + START_OF_INSTR(); + DECODE_PRINTF("JNL\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + /* note: inverse of above, but using == instead of xor. */ + if (sf == of) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x7e +****************************************************************************/ +void x86emuOp_jump_near_LE(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + int sf, of; + + /* jump to byte offset if sign flag not equal to overflow flag + or the zero flag is set */ + START_OF_INSTR(); + DECODE_PRINTF("JLE\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + if ((sf ^ of) || ACCESS_FLAG(F_ZF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x7f +****************************************************************************/ +void x86emuOp_jump_near_NLE(u8 X86EMU_UNUSED(op1)) +{ + s8 offset; + u16 target; + int sf, of; + + /* jump to byte offset if sign flag equal to overflow flag. + and the zero flag is clear */ + START_OF_INSTR(); + DECODE_PRINTF("JNLE\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + sf = ACCESS_FLAG(F_SF) != 0; + of = ACCESS_FLAG(F_OF) != 0; + if ((sf == of) && !ACCESS_FLAG(F_ZF)) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +static u8 (*opc80_byte_operation[])(u8 d, u8 s) = +{ + add_byte, /* 00 */ + or_byte, /* 01 */ + adc_byte, /* 02 */ + sbb_byte, /* 03 */ + and_byte, /* 04 */ + sub_byte, /* 05 */ + xor_byte, /* 06 */ + cmp_byte, /* 07 */ +}; + +/**************************************************************************** +REMARKS: +Handles opcode 0x80 +****************************************************************************/ +void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg; + uint destoffset; + u8 imm; + u8 destval; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + + switch (rh) { + case 0: + DECODE_PRINTF("ADD\t"); + break; + case 1: + DECODE_PRINTF("OR\t"); + break; + case 2: + DECODE_PRINTF("ADC\t"); + break; + case 3: + DECODE_PRINTF("SBB\t"); + break; + case 4: + DECODE_PRINTF("AND\t"); + break; + case 5: + DECODE_PRINTF("SUB\t"); + break; + case 6: + DECODE_PRINTF("XOR\t"); + break; + case 7: + DECODE_PRINTF("CMP\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) { + case 0: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc80_byte_operation[rh]) (destval, imm); + if (rh != 7) + store_data_byte(destoffset, destval); + break; + case 1: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc80_byte_operation[rh]) (destval, imm); + if (rh != 7) + store_data_byte(destoffset, destval); + break; + case 2: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc80_byte_operation[rh]) (destval, imm); + if (rh != 7) + store_data_byte(destoffset, destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(","); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc80_byte_operation[rh]) (*destreg, imm); + if (rh != 7) + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +static u16 (*opc81_word_operation[])(u16 d, u16 s) = +{ + add_word, /*00 */ + or_word, /*01 */ + adc_word, /*02 */ + sbb_word, /*03 */ + and_word, /*04 */ + sub_word, /*05 */ + xor_word, /*06 */ + cmp_word, /*07 */ +}; + +static u32 (*opc81_long_operation[])(u32 d, u32 s) = +{ + add_long, /*00 */ + or_long, /*01 */ + adc_long, /*02 */ + sbb_long, /*03 */ + and_long, /*04 */ + sub_long, /*05 */ + xor_long, /*06 */ + cmp_long, /*07 */ +}; + +/**************************************************************************** +REMARKS: +Handles opcode 0x81 +****************************************************************************/ +void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + + switch (rh) { + case 0: + DECODE_PRINTF("ADD\t"); + break; + case 1: + DECODE_PRINTF("OR\t"); + break; + case 2: + DECODE_PRINTF("ADC\t"); + break; + case 3: + DECODE_PRINTF("SBB\t"); + break; + case 4: + DECODE_PRINTF("AND\t"); + break; + case 5: + DECODE_PRINTF("SUB\t"); + break; + case 6: + DECODE_PRINTF("XOR\t"); + break; + case 7: + DECODE_PRINTF("CMP\t"); + break; + } + } +#endif + /* + * Know operation, decode the mod byte to find the addressing + * mode. + */ + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + imm = fetch_long_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + u16 destval,imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_word_operation[rh]) (destval, imm); + if (rh != 7) + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + imm = fetch_long_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + u16 destval,imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_word_operation[rh]) (destval, imm); + if (rh != 7) + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + imm = fetch_long_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + u16 destval,imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_word_operation[rh]) (destval, imm); + if (rh != 7) + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 destval,imm; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + imm = fetch_long_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_long_operation[rh]) (*destreg, imm); + if (rh != 7) + *destreg = destval; + } else { + u16 *destreg; + u16 destval,imm; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc81_word_operation[rh]) (*destreg, imm); + if (rh != 7) + *destreg = destval; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +static u8 (*opc82_byte_operation[])(u8 s, u8 d) = +{ + add_byte, /*00 */ + or_byte, /*01 *//*YYY UNUSED ???? */ + adc_byte, /*02 */ + sbb_byte, /*03 */ + and_byte, /*04 *//*YYY UNUSED ???? */ + sub_byte, /*05 */ + xor_byte, /*06 *//*YYY UNUSED ???? */ + cmp_byte, /*07 */ +}; + +/**************************************************************************** +REMARKS: +Handles opcode 0x82 +****************************************************************************/ +void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg; + uint destoffset; + u8 imm; + u8 destval; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction Similar to opcode 81, except that + * the immediate byte is sign extended to a word length. + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + switch (rh) { + case 0: + DECODE_PRINTF("ADD\t"); + break; + case 1: + DECODE_PRINTF("OR\t"); + break; + case 2: + DECODE_PRINTF("ADC\t"); + break; + case 3: + DECODE_PRINTF("SBB\t"); + break; + case 4: + DECODE_PRINTF("AND\t"); + break; + case 5: + DECODE_PRINTF("SUB\t"); + break; + case 6: + DECODE_PRINTF("XOR\t"); + break; + case 7: + DECODE_PRINTF("CMP\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) { + case 0: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm00_address(rl); + destval = fetch_data_byte(destoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc82_byte_operation[rh]) (destval, imm); + if (rh != 7) + store_data_byte(destoffset, destval); + break; + case 1: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm01_address(rl); + destval = fetch_data_byte(destoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc82_byte_operation[rh]) (destval, imm); + if (rh != 7) + store_data_byte(destoffset, destval); + break; + case 2: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + destval = fetch_data_byte(destoffset); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc82_byte_operation[rh]) (destval, imm); + if (rh != 7) + store_data_byte(destoffset, destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc82_byte_operation[rh]) (*destreg, imm); + if (rh != 7) + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +static u16 (*opc83_word_operation[])(u16 s, u16 d) = +{ + add_word, /*00 */ + or_word, /*01 *//*YYY UNUSED ???? */ + adc_word, /*02 */ + sbb_word, /*03 */ + and_word, /*04 *//*YYY UNUSED ???? */ + sub_word, /*05 */ + xor_word, /*06 *//*YYY UNUSED ???? */ + cmp_word, /*07 */ +}; + +static u32 (*opc83_long_operation[])(u32 s, u32 d) = +{ + add_long, /*00 */ + or_long, /*01 *//*YYY UNUSED ???? */ + adc_long, /*02 */ + sbb_long, /*03 */ + and_long, /*04 *//*YYY UNUSED ???? */ + sub_long, /*05 */ + xor_long, /*06 *//*YYY UNUSED ???? */ + cmp_long, /*07 */ +}; + +/**************************************************************************** +REMARKS: +Handles opcode 0x83 +****************************************************************************/ +void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + /* + * Weirdo special case instruction format. Part of the opcode + * held below in "RH". Doubly nested case would result, except + * that the decoded instruction Similar to opcode 81, except that + * the immediate byte is sign extended to a word length. + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + switch (rh) { + case 0: + DECODE_PRINTF("ADD\t"); + break; + case 1: + DECODE_PRINTF("OR\t"); + break; + case 2: + DECODE_PRINTF("ADC\t"); + break; + case 3: + DECODE_PRINTF("SBB\t"); + break; + case 4: + DECODE_PRINTF("AND\t"); + break; + case 5: + DECODE_PRINTF("SUB\t"); + break; + case 6: + DECODE_PRINTF("XOR\t"); + break; + case 7: + DECODE_PRINTF("CMP\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm00_address(rl); + destval = fetch_data_long(destoffset); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + u16 destval,imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm00_address(rl); + destval = fetch_data_word(destoffset); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_word_operation[rh]) (destval, imm); + if (rh != 7) + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm01_address(rl); + destval = fetch_data_long(destoffset); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + u16 destval,imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm01_address(rl); + destval = fetch_data_word(destoffset); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_word_operation[rh]) (destval, imm); + if (rh != 7) + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm10_address(rl); + destval = fetch_data_long(destoffset); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_long_operation[rh]) (destval, imm); + if (rh != 7) + store_data_long(destoffset, destval); + } else { + u16 destval,imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm10_address(rl); + destval = fetch_data_word(destoffset); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_word_operation[rh]) (destval, imm); + if (rh != 7) + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 destval,imm; + + destreg = DECODE_RM_LONG_REGISTER(rl); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_long_operation[rh]) (*destreg, imm); + if (rh != 7) + *destreg = destval; + } else { + u16 *destreg; + u16 destval,imm; + + destreg = DECODE_RM_WORD_REGISTER(rl); + imm = (s8) fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + destval = (*opc83_word_operation[rh]) (*destreg, imm); + if (rh != 7) + *destreg = destval; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x84 +****************************************************************************/ +void x86emuOp_test_byte_RM_R(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg, *srcreg; + uint destoffset; + u8 destval; + + START_OF_INSTR(); + DECODE_PRINTF("TEST\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_byte(destval, *srcreg); + break; + case 1: + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_byte(destval, *srcreg); + break; + case 2: + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_byte(destval, *srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_byte(*destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x85 +****************************************************************************/ +void x86emuOp_test_word_RM_R(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("TEST\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *srcreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_long(destval, *srcreg); + } else { + u16 destval; + u16 *srcreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_word(destval, *srcreg); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *srcreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_long(destval, *srcreg); + } else { + u16 destval; + u16 *srcreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_word(destval, *srcreg); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *srcreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_long(destval, *srcreg); + } else { + u16 destval; + u16 *srcreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_word(destval, *srcreg); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_long(*destreg, *srcreg); + } else { + u16 *destreg,*srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + test_word(*destreg, *srcreg); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x86 +****************************************************************************/ +void x86emuOp_xchg_byte_RM_R(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg, *srcreg; + uint destoffset; + u8 destval; + u8 tmp; + + START_OF_INSTR(); + DECODE_PRINTF("XCHG\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_byte(destoffset, destval); + break; + case 1: + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_byte(destoffset, destval); + break; + case 2: + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_byte(destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_byte(destoffset, destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = *destreg; + *destreg = tmp; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x87 +****************************************************************************/ +void x86emuOp_xchg_word_RM_R(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("XCHG\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg; + u32 destval,tmp; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_long(destoffset, destval); + } else { + u16 *srcreg; + u16 destval,tmp; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg; + u32 destval,tmp; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_long(destoffset, destval); + } else { + u16 *srcreg; + u16 destval,tmp; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg; + u32 destval,tmp; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_long(destoffset); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_long(destoffset, destval); + } else { + u16 *srcreg; + u16 destval,tmp; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + destval = fetch_data_word(destoffset); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*srcreg; + u32 tmp; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = *destreg; + *destreg = tmp; + } else { + u16 *destreg,*srcreg; + u16 tmp; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + tmp = *srcreg; + *srcreg = *destreg; + *destreg = tmp; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x88 +****************************************************************************/ +void x86emuOp_mov_byte_RM_R(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg, *srcreg; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_byte(destoffset, *srcreg); + break; + case 1: + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_byte(destoffset, *srcreg); + break; + case 2: + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_byte(destoffset, *srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x89 +****************************************************************************/ +void x86emuOp_mov_word_RM_R(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_long(destoffset, *srcreg); + } else { + u16 *srcreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_word(destoffset, *srcreg); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_long(destoffset, *srcreg); + } else { + u16 *srcreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_word(destoffset, *srcreg); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_long(destoffset, *srcreg); + } else { + u16 *srcreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + store_data_word(destoffset, *srcreg); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } else { + u16 *destreg,*srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8a +****************************************************************************/ +void x86emuOp_mov_byte_R_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg, *srcreg; + uint srcoffset; + u8 srcval; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8b +****************************************************************************/ +void x86emuOp_mov_word_R_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_long(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_long(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_long(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg, *srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } else { + u16 *destreg, *srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8c +****************************************************************************/ +void x86emuOp_mov_word_RM_SR(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u16 *destreg, *srcreg; + uint destoffset; + u16 destval; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + srcreg = decode_rm_seg_register(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = *srcreg; + store_data_word(destoffset, destval); + break; + case 1: + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + srcreg = decode_rm_seg_register(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = *srcreg; + store_data_word(destoffset, destval); + break; + case 2: + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + srcreg = decode_rm_seg_register(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = *srcreg; + store_data_word(destoffset, destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcreg = decode_rm_seg_register(rh); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8d +****************************************************************************/ +void x86emuOp_lea_word_R_M(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u16 *srcreg; + uint destoffset; + +/* + * TODO: Need to handle address size prefix! + * + * lea eax,[eax+ebx*2] ?? + */ + + START_OF_INSTR(); + DECODE_PRINTF("LEA\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *srcreg = (u16)destoffset; + break; + case 1: + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *srcreg = (u16)destoffset; + break; + case 2: + srcreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *srcreg = (u16)destoffset; + break; + case 3: /* register to register */ + /* undefined. Do nothing. */ + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8e +****************************************************************************/ +void x86emuOp_mov_word_SR_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u16 *destreg, *srcreg; + uint srcoffset; + u16 srcval; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destreg = decode_rm_seg_register(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 1: + destreg = decode_rm_seg_register(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 2: + destreg = decode_rm_seg_register(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 3: /* register to register */ + destreg = decode_rm_seg_register(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + break; + } + /* + * Clean up, and reset all the R_xSP pointers to the correct + * locations. This is about 3x too much overhead (doing all the + * segreg ptrs when only one is needed, but this instruction + * *cannot* be that common, and this isn't too much work anyway. + */ + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8f +****************************************************************************/ +void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("POP\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (rh != 0) { + DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); + HALT_SYS(); + } + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = pop_long(); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = pop_word(); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = pop_long(); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = pop_word(); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = pop_long(); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + destval = pop_word(); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = pop_long(); + } else { + u16 *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = pop_word(); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x90 +****************************************************************************/ +void x86emuOp_nop(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("NOP\n"); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x91 +****************************************************************************/ +void x86emuOp_xchg_word_AX_CX(u8 X86EMU_UNUSED(op1)) +{ + u32 tmp; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("XCHG\tEAX,ECX\n"); + } else { + DECODE_PRINTF("XCHG\tAX,CX\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + tmp = M.x86.R_EAX; + M.x86.R_EAX = M.x86.R_ECX; + M.x86.R_ECX = tmp; + } else { + tmp = M.x86.R_AX; + M.x86.R_AX = M.x86.R_CX; + M.x86.R_CX = (u16)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x92 +****************************************************************************/ +void x86emuOp_xchg_word_AX_DX(u8 X86EMU_UNUSED(op1)) +{ + u32 tmp; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("XCHG\tEAX,EDX\n"); + } else { + DECODE_PRINTF("XCHG\tAX,DX\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + tmp = M.x86.R_EAX; + M.x86.R_EAX = M.x86.R_EDX; + M.x86.R_EDX = tmp; + } else { + tmp = M.x86.R_AX; + M.x86.R_AX = M.x86.R_DX; + M.x86.R_DX = (u16)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x93 +****************************************************************************/ +void x86emuOp_xchg_word_AX_BX(u8 X86EMU_UNUSED(op1)) +{ + u32 tmp; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("XCHG\tEAX,EBX\n"); + } else { + DECODE_PRINTF("XCHG\tAX,BX\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + tmp = M.x86.R_EAX; + M.x86.R_EAX = M.x86.R_EBX; + M.x86.R_EBX = tmp; + } else { + tmp = M.x86.R_AX; + M.x86.R_AX = M.x86.R_BX; + M.x86.R_BX = (u16)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x94 +****************************************************************************/ +void x86emuOp_xchg_word_AX_SP(u8 X86EMU_UNUSED(op1)) +{ + u32 tmp; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("XCHG\tEAX,ESP\n"); + } else { + DECODE_PRINTF("XCHG\tAX,SP\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + tmp = M.x86.R_EAX; + M.x86.R_EAX = M.x86.R_ESP; + M.x86.R_ESP = tmp; + } else { + tmp = M.x86.R_AX; + M.x86.R_AX = M.x86.R_SP; + M.x86.R_SP = (u16)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x95 +****************************************************************************/ +void x86emuOp_xchg_word_AX_BP(u8 X86EMU_UNUSED(op1)) +{ + u32 tmp; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("XCHG\tEAX,EBP\n"); + } else { + DECODE_PRINTF("XCHG\tAX,BP\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + tmp = M.x86.R_EAX; + M.x86.R_EAX = M.x86.R_EBP; + M.x86.R_EBP = tmp; + } else { + tmp = M.x86.R_AX; + M.x86.R_AX = M.x86.R_BP; + M.x86.R_BP = (u16)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x96 +****************************************************************************/ +void x86emuOp_xchg_word_AX_SI(u8 X86EMU_UNUSED(op1)) +{ + u32 tmp; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("XCHG\tEAX,ESI\n"); + } else { + DECODE_PRINTF("XCHG\tAX,SI\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + tmp = M.x86.R_EAX; + M.x86.R_EAX = M.x86.R_ESI; + M.x86.R_ESI = tmp; + } else { + tmp = M.x86.R_AX; + M.x86.R_AX = M.x86.R_SI; + M.x86.R_SI = (u16)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x97 +****************************************************************************/ +void x86emuOp_xchg_word_AX_DI(u8 X86EMU_UNUSED(op1)) +{ + u32 tmp; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("XCHG\tEAX,EDI\n"); + } else { + DECODE_PRINTF("XCHG\tAX,DI\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + tmp = M.x86.R_EAX; + M.x86.R_EAX = M.x86.R_EDI; + M.x86.R_EDI = tmp; + } else { + tmp = M.x86.R_AX; + M.x86.R_AX = M.x86.R_DI; + M.x86.R_DI = (u16)tmp; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x98 +****************************************************************************/ +void x86emuOp_cbw(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("CWDE\n"); + } else { + DECODE_PRINTF("CBW\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + if (M.x86.R_AX & 0x8000) { + M.x86.R_EAX |= 0xffff0000; + } else { + M.x86.R_EAX &= 0x0000ffff; + } + } else { + if (M.x86.R_AL & 0x80) { + M.x86.R_AH = 0xff; + } else { + M.x86.R_AH = 0x0; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x99 +****************************************************************************/ +void x86emuOp_cwd(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("CDQ\n"); + } else { + DECODE_PRINTF("CWD\n"); + } + DECODE_PRINTF("CWD\n"); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + if (M.x86.R_EAX & 0x80000000) { + M.x86.R_EDX = 0xffffffff; + } else { + M.x86.R_EDX = 0x0; + } + } else { + if (M.x86.R_AX & 0x8000) { + M.x86.R_DX = 0xffff; + } else { + M.x86.R_DX = 0x0; + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9a +****************************************************************************/ +void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 farseg, faroff; + + START_OF_INSTR(); + DECODE_PRINTF("CALL\t"); + faroff = fetch_word_imm(); + farseg = fetch_word_imm(); + DECODE_PRINTF2("%04x:", farseg); + DECODE_PRINTF2("%04x\n", faroff); + CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR "); + + /* XXX + * + * Hooked interrupt vectors calling into our "BIOS" will cause + * problems unless all intersegment stuff is checked for BIOS + * access. Check needed here. For moment, let it alone. + */ + TRACE_AND_STEP(); + push_word(M.x86.R_CS); + M.x86.R_CS = farseg; + push_word(M.x86.R_IP); + M.x86.R_IP = faroff; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9b +****************************************************************************/ +void x86emuOp_wait(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("WAIT"); + TRACE_AND_STEP(); + /* NADA. */ + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9c +****************************************************************************/ +void x86emuOp_pushf_word(u8 X86EMU_UNUSED(op1)) +{ + u32 flags; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("PUSHFD\n"); + } else { + DECODE_PRINTF("PUSHF\n"); + } + TRACE_AND_STEP(); + + /* clear out *all* bits not representing flags, and turn on real bits */ + flags = (M.x86.R_EFLG & F_MSK) | F_ALWAYS_ON; + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + push_long(flags); + } else { + push_word((u16)flags); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9d +****************************************************************************/ +void x86emuOp_popf_word(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("POPFD\n"); + } else { + DECODE_PRINTF("POPF\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EFLG = pop_long(); + } else { + M.x86.R_FLG = pop_word(); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9e +****************************************************************************/ +void x86emuOp_sahf(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("SAHF\n"); + TRACE_AND_STEP(); + /* clear the lower bits of the flag register */ + M.x86.R_FLG &= 0xffffff00; + /* or in the AH register into the flags register */ + M.x86.R_FLG |= M.x86.R_AH; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9f +****************************************************************************/ +void x86emuOp_lahf(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("LAHF\n"); + TRACE_AND_STEP(); + M.x86.R_AH = (u8)(M.x86.R_FLG & 0xff); + /*undocumented TC++ behavior??? Nope. It's documented, but + you have too look real hard to notice it. */ + M.x86.R_AH |= 0x2; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa0 +****************************************************************************/ +void x86emuOp_mov_AL_M_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 offset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tAL,"); + offset = fetch_word_imm(); + DECODE_PRINTF2("[%04x]\n", offset); + TRACE_AND_STEP(); + M.x86.R_AL = fetch_data_byte(offset); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa1 +****************************************************************************/ +void x86emuOp_mov_AX_M_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 offset; + + START_OF_INSTR(); + offset = fetch_word_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("MOV\tEAX,[%04x]\n", offset); + } else { + DECODE_PRINTF2("MOV\tAX,[%04x]\n", offset); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EAX = fetch_data_long(offset); + } else { + M.x86.R_AX = fetch_data_word(offset); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa2 +****************************************************************************/ +void x86emuOp_mov_M_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 offset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + offset = fetch_word_imm(); + DECODE_PRINTF2("[%04x],AL\n", offset); + TRACE_AND_STEP(); + store_data_byte(offset, M.x86.R_AL); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa3 +****************************************************************************/ +void x86emuOp_mov_M_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 offset; + + START_OF_INSTR(); + offset = fetch_word_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("MOV\t[%04x],EAX\n", offset); + } else { + DECODE_PRINTF2("MOV\t[%04x],AX\n", offset); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + store_data_long(offset, M.x86.R_EAX); + } else { + store_data_word(offset, M.x86.R_AX); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa4 +****************************************************************************/ +void x86emuOp_movs_byte(u8 X86EMU_UNUSED(op1)) +{ + u8 val; + u32 count; + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("MOVS\tBYTE\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + TRACE_AND_STEP(); + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = M.x86.R_CX; + M.x86.R_CX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + val = fetch_data_byte(M.x86.R_SI); + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val); + M.x86.R_SI += inc; + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa5 +****************************************************************************/ +void x86emuOp_movs_word(u8 X86EMU_UNUSED(op1)) +{ + u32 val; + int inc; + u32 count; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOVS\tDWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("MOVS\tWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -2; + else + inc = 2; + } + TRACE_AND_STEP(); + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = M.x86.R_CX; + M.x86.R_CX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long(M.x86.R_SI); + store_data_long_abs(M.x86.R_ES, M.x86.R_DI, val); + } else { + val = fetch_data_word(M.x86.R_SI); + store_data_word_abs(M.x86.R_ES, M.x86.R_DI, (u16)val); + } + M.x86.R_SI += inc; + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa6 +****************************************************************************/ +void x86emuOp_cmps_byte(u8 X86EMU_UNUSED(op1)) +{ + s8 val1, val2; + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("CMPS\tBYTE\n"); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + val1 = fetch_data_byte(M.x86.R_SI); + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(val1, val2); + M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + val1 = fetch_data_byte(M.x86.R_SI); + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(val1, val2); + M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + val1 = fetch_data_byte(M.x86.R_SI); + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(val1, val2); + M.x86.R_SI += inc; + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa7 +****************************************************************************/ +void x86emuOp_cmps_word(u8 X86EMU_UNUSED(op1)) +{ + u32 val1,val2; + int inc; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("CMPS\tDWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("CMPS\tWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -2; + else + inc = 2; + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(M.x86.R_SI); + val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(val1, val2); + } else { + val1 = fetch_data_word(M.x86.R_SI); + val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word((u16)val1, (u16)val2); + } + M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(M.x86.R_SI); + val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(val1, val2); + } else { + val1 = fetch_data_word(M.x86.R_SI); + val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word((u16)val1, (u16)val2); + } + M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(M.x86.R_SI); + val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(val1, val2); + } else { + val1 = fetch_data_word(M.x86.R_SI); + val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word((u16)val1, (u16)val2); + } + M.x86.R_SI += inc; + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa8 +****************************************************************************/ +void x86emuOp_test_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ + int imm; + + START_OF_INSTR(); + DECODE_PRINTF("TEST\tAL,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%04x\n", imm); + TRACE_AND_STEP(); + test_byte(M.x86.R_AL, (u8)imm); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa9 +****************************************************************************/ +void x86emuOp_test_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("TEST\tEAX,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("TEST\tAX,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + test_long(M.x86.R_EAX, srcval); + } else { + test_word(M.x86.R_AX, (u16)srcval); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xaa +****************************************************************************/ +void x86emuOp_stos_byte(u8 X86EMU_UNUSED(op1)) +{ + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("STOS\tBYTE\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + TRACE_AND_STEP(); + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL); + M.x86.R_CX -= 1; + M.x86.R_DI += inc; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL); + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xab +****************************************************************************/ +void x86emuOp_stos_word(u8 X86EMU_UNUSED(op1)) +{ + int inc; + u32 count; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("STOS\tDWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("STOS\tWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -2; + else + inc = 2; + } + TRACE_AND_STEP(); + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = M.x86.R_CX; + M.x86.R_CX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + store_data_long_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_EAX); + } else { + store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX); + } + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xac +****************************************************************************/ +void x86emuOp_lods_byte(u8 X86EMU_UNUSED(op1)) +{ + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("LODS\tBYTE\n"); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + M.x86.R_AL = fetch_data_byte(M.x86.R_SI); + M.x86.R_CX -= 1; + M.x86.R_SI += inc; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + M.x86.R_AL = fetch_data_byte(M.x86.R_SI); + M.x86.R_SI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xad +****************************************************************************/ +void x86emuOp_lods_word(u8 X86EMU_UNUSED(op1)) +{ + int inc; + u32 count; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("LODS\tDWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("LODS\tWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -2; + else + inc = 2; + } + TRACE_AND_STEP(); + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + count = M.x86.R_CX; + M.x86.R_CX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EAX = fetch_data_long(M.x86.R_SI); + } else { + M.x86.R_AX = fetch_data_word(M.x86.R_SI); + } + M.x86.R_SI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xae +****************************************************************************/ +void x86emuOp_scas_byte(u8 X86EMU_UNUSED(op1)) +{ + s8 val2; + int inc; + + START_OF_INSTR(); + DECODE_PRINTF("SCAS\tBYTE\n"); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(M.x86.R_AL, val2); + M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(M.x86.R_AL, val2); + M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(M.x86.R_AL, val2); + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xaf +****************************************************************************/ +void x86emuOp_scas_word(u8 X86EMU_UNUSED(op1)) +{ + int inc; + u32 val; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("SCAS\tDWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -4; + else + inc = 4; + } else { + DECODE_PRINTF("SCAS\tWORD\n"); + if (ACCESS_FLAG(F_DF)) /* down */ + inc = -2; + else + inc = 2; + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(M.x86.R_EAX, val); + } else { + val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word(M.x86.R_AX, (u16)val); + } + M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ + /* move them until CX is ZERO. */ + while (M.x86.R_CX != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(M.x86.R_EAX, val); + } else { + val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word(M.x86.R_AX, (u16)val); + } + M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(M.x86.R_EAX, val); + } else { + val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word(M.x86.R_AX, (u16)val); + } + M.x86.R_DI += inc; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb0 +****************************************************************************/ +void x86emuOp_mov_byte_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tAL,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_AL = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb1 +****************************************************************************/ +void x86emuOp_mov_byte_CL_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tCL,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_CL = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb2 +****************************************************************************/ +void x86emuOp_mov_byte_DL_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tDL,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_DL = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb3 +****************************************************************************/ +void x86emuOp_mov_byte_BL_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tBL,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_BL = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb4 +****************************************************************************/ +void x86emuOp_mov_byte_AH_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tAH,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_AH = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb5 +****************************************************************************/ +void x86emuOp_mov_byte_CH_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tCH,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_CH = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb6 +****************************************************************************/ +void x86emuOp_mov_byte_DH_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tDH,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_DH = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb7 +****************************************************************************/ +void x86emuOp_mov_byte_BH_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\tBH,"); + imm = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", imm); + TRACE_AND_STEP(); + M.x86.R_BH = imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb8 +****************************************************************************/ +void x86emuOp_mov_word_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tEAX,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tAX,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EAX = srcval; + } else { + M.x86.R_AX = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb9 +****************************************************************************/ +void x86emuOp_mov_word_CX_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tECX,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tCX,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_ECX = srcval; + } else { + M.x86.R_CX = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xba +****************************************************************************/ +void x86emuOp_mov_word_DX_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tEDX,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tDX,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EDX = srcval; + } else { + M.x86.R_DX = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xbb +****************************************************************************/ +void x86emuOp_mov_word_BX_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tEBX,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tBX,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EBX = srcval; + } else { + M.x86.R_BX = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xbc +****************************************************************************/ +void x86emuOp_mov_word_SP_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tESP,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tSP,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_ESP = srcval; + } else { + M.x86.R_SP = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xbd +****************************************************************************/ +void x86emuOp_mov_word_BP_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tEBP,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tBP,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EBP = srcval; + } else { + M.x86.R_BP = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xbe +****************************************************************************/ +void x86emuOp_mov_word_SI_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tESI,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tSI,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_ESI = srcval; + } else { + M.x86.R_SI = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xbf +****************************************************************************/ +void x86emuOp_mov_word_DI_IMM(u8 X86EMU_UNUSED(op1)) +{ + u32 srcval; + + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("MOV\tEDI,"); + srcval = fetch_long_imm(); + } else { + DECODE_PRINTF("MOV\tDI,"); + srcval = fetch_word_imm(); + } + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EDI = srcval; + } else { + M.x86.R_DI = (u16)srcval; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/* used by opcodes c0, d0, and d2. */ +static u8(*opcD0_byte_operation[])(u8 d, u8 s) = +{ + rol_byte, + ror_byte, + rcl_byte, + rcr_byte, + shl_byte, + shr_byte, + shl_byte, /* sal_byte === shl_byte by definition */ + sar_byte, +}; + +/**************************************************************************** +REMARKS: +Handles opcode 0xc0 +****************************************************************************/ +void x86emuOp_opcC0_byte_RM_MEM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg; + uint destoffset; + u8 destval; + u8 amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + + switch (rh) { + case 0: + DECODE_PRINTF("ROL\t"); + break; + case 1: + DECODE_PRINTF("ROR\t"); + break; + case 2: + DECODE_PRINTF("RCL\t"); + break; + case 3: + DECODE_PRINTF("RCR\t"); + break; + case 4: + DECODE_PRINTF("SHL\t"); + break; + case 5: + DECODE_PRINTF("SHR\t"); + break; + case 6: + DECODE_PRINTF("SAL\t"); + break; + case 7: + DECODE_PRINTF("SAR\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) { + case 0: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm00_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, amt); + store_data_byte(destoffset, destval); + break; + case 1: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm01_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, amt); + store_data_byte(destoffset, destval); + break; + case 2: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, amt); + store_data_byte(destoffset, destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (*destreg, amt); + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/* used by opcodes c1, d1, and d3. */ +static u16(*opcD1_word_operation[])(u16 s, u8 d) = +{ + rol_word, + ror_word, + rcl_word, + rcr_word, + shl_word, + shr_word, + shl_word, /* sal_byte === shl_byte by definition */ + sar_word, +}; + +/* used by opcodes c1, d1, and d3. */ +static u32 (*opcD1_long_operation[])(u32 s, u8 d) = +{ + rol_long, + ror_long, + rcl_long, + rcr_long, + shl_long, + shr_long, + shl_long, /* sal_byte === shl_byte by definition */ + sar_long, +}; + +/**************************************************************************** +REMARKS: +Handles opcode 0xc1 +****************************************************************************/ +void x86emuOp_opcC1_word_RM_MEM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + u8 amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + + switch (rh) { + case 0: + DECODE_PRINTF("ROL\t"); + break; + case 1: + DECODE_PRINTF("ROR\t"); + break; + case 2: + DECODE_PRINTF("RCL\t"); + break; + case 3: + DECODE_PRINTF("RCR\t"); + break; + case 4: + DECODE_PRINTF("SHL\t"); + break; + case 5: + DECODE_PRINTF("SHR\t"); + break; + case 6: + DECODE_PRINTF("SAL\t"); + break; + case 7: + DECODE_PRINTF("SAR\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm00_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm00_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, amt); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm01_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm01_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, amt); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm10_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm10_address(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, amt); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + TRACE_AND_STEP(); + *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); + } else { + u16 *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + amt = fetch_byte_imm(); + DECODE_PRINTF2(",%x\n", amt); + TRACE_AND_STEP(); + *destreg = (*opcD1_word_operation[rh]) (*destreg, amt); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc2 +****************************************************************************/ +void x86emuOp_ret_near_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 imm; + + START_OF_INSTR(); + DECODE_PRINTF("RET\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); + RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + M.x86.R_SP += imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc3 +****************************************************************************/ +void x86emuOp_ret_near(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("RET\n"); + RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc4 +****************************************************************************/ +void x86emuOp_les_R_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + u16 *dstreg; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("LES\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_ES = fetch_data_word(srcoffset + 2); + break; + case 1: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_ES = fetch_data_word(srcoffset + 2); + break; + case 2: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_ES = fetch_data_word(srcoffset + 2); + break; + case 3: /* register to register */ + /* UNDEFINED! */ + TRACE_AND_STEP(); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc5 +****************************************************************************/ +void x86emuOp_lds_R_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + u16 *dstreg; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("LDS\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_DS = fetch_data_word(srcoffset + 2); + break; + case 1: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_DS = fetch_data_word(srcoffset + 2); + break; + case 2: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_DS = fetch_data_word(srcoffset + 2); + break; + case 3: /* register to register */ + /* UNDEFINED! */ + TRACE_AND_STEP(); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc6 +****************************************************************************/ +void x86emuOp_mov_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg; + uint destoffset; + u8 imm; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (rh != 0) { + DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\n"); + HALT_SYS(); + } + switch (mod) { + case 0: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm00_address(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%2x\n", imm); + TRACE_AND_STEP(); + store_data_byte(destoffset, imm); + break; + case 1: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm01_address(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%2x\n", imm); + TRACE_AND_STEP(); + store_data_byte(destoffset, imm); + break; + case 2: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%2x\n", imm); + TRACE_AND_STEP(); + store_data_byte(destoffset, imm); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + imm = fetch_byte_imm(); + DECODE_PRINTF2(",%2x\n", imm); + TRACE_AND_STEP(); + *destreg = imm; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc7 +****************************************************************************/ +void x86emuOp_mov_word_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOV\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + if (rh != 0) { + DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); + HALT_SYS(); + } + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm00_address(rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + store_data_long(destoffset, imm); + } else { + u16 imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm00_address(rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + store_data_word(destoffset, imm); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm01_address(rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + store_data_long(destoffset, imm); + } else { + u16 imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm01_address(rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + store_data_word(destoffset, imm); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 imm; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm10_address(rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + store_data_long(destoffset, imm); + } else { + u16 imm; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm10_address(rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + store_data_word(destoffset, imm); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 imm; + + destreg = DECODE_RM_LONG_REGISTER(rl); + imm = fetch_long_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + *destreg = imm; + } else { + u16 *destreg; + u16 imm; + + destreg = DECODE_RM_WORD_REGISTER(rl); + imm = fetch_word_imm(); + DECODE_PRINTF2(",%x\n", imm); + TRACE_AND_STEP(); + *destreg = imm; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc8 +****************************************************************************/ +void x86emuOp_enter(u8 X86EMU_UNUSED(op1)) +{ + u16 local,frame_pointer; + u8 nesting; + int i; + + START_OF_INSTR(); + local = fetch_word_imm(); + nesting = fetch_byte_imm(); + DECODE_PRINTF2("ENTER %x\n", local); + DECODE_PRINTF2(",%x\n", nesting); + TRACE_AND_STEP(); + push_word(M.x86.R_BP); + frame_pointer = M.x86.R_SP; + if (nesting > 0) { + for (i = 1; i < nesting; i++) { + M.x86.R_BP -= 2; + push_word(fetch_data_word_abs(M.x86.R_SS, M.x86.R_BP)); + } + push_word(frame_pointer); + } + M.x86.R_BP = frame_pointer; + M.x86.R_SP = (u16)(M.x86.R_SP - local); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc9 +****************************************************************************/ +void x86emuOp_leave(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("LEAVE\n"); + TRACE_AND_STEP(); + M.x86.R_SP = M.x86.R_BP; + M.x86.R_BP = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xca +****************************************************************************/ +void x86emuOp_ret_far_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 imm; + + START_OF_INSTR(); + DECODE_PRINTF("RETF\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); + RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + M.x86.R_CS = pop_word(); + M.x86.R_SP += imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcb +****************************************************************************/ +void x86emuOp_ret_far(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("RETF\n"); + RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + M.x86.R_CS = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcc +****************************************************************************/ +void x86emuOp_int3(u8 X86EMU_UNUSED(op1)) +{ + u16 tmp; + + START_OF_INSTR(); + DECODE_PRINTF("INT 3\n"); + tmp = (u16) mem_access_word(3 * 4 + 2); + /* access the segment register */ + TRACE_AND_STEP(); + if (_X86EMU_intrTab[3]) { + (*_X86EMU_intrTab[3])(3); + } else { + push_word((u16)M.x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + push_word(M.x86.R_CS); + M.x86.R_CS = mem_access_word(3 * 4 + 2); + push_word(M.x86.R_IP); + M.x86.R_IP = mem_access_word(3 * 4); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcd +****************************************************************************/ +void x86emuOp_int_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 tmp; + u8 intnum; + + START_OF_INSTR(); + DECODE_PRINTF("INT\t"); + intnum = fetch_byte_imm(); + DECODE_PRINTF2("%x\n", intnum); + tmp = mem_access_word(intnum * 4 + 2); + TRACE_AND_STEP(); + if (_X86EMU_intrTab[intnum]) { + (*_X86EMU_intrTab[intnum])(intnum); + } else { + push_word((u16)M.x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + push_word(M.x86.R_CS); + M.x86.R_CS = mem_access_word(intnum * 4 + 2); + push_word(M.x86.R_IP); + M.x86.R_IP = mem_access_word(intnum * 4); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xce +****************************************************************************/ +void x86emuOp_into(u8 X86EMU_UNUSED(op1)) +{ + u16 tmp; + + START_OF_INSTR(); + DECODE_PRINTF("INTO\n"); + TRACE_AND_STEP(); + if (ACCESS_FLAG(F_OF)) { + tmp = mem_access_word(4 * 4 + 2); + if (_X86EMU_intrTab[4]) { + (*_X86EMU_intrTab[4])(4); + } else { + push_word((u16)M.x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + push_word(M.x86.R_CS); + M.x86.R_CS = mem_access_word(4 * 4 + 2); + push_word(M.x86.R_IP); + M.x86.R_IP = mem_access_word(4 * 4); + } + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcf +****************************************************************************/ +void x86emuOp_iret(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("IRET\n"); + + TRACE_AND_STEP(); + + M.x86.R_IP = pop_word(); + M.x86.R_CS = pop_word(); + M.x86.R_FLG = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd0 +****************************************************************************/ +void x86emuOp_opcD0_byte_RM_1(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg; + uint destoffset; + u8 destval; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + switch (rh) { + case 0: + DECODE_PRINTF("ROL\t"); + break; + case 1: + DECODE_PRINTF("ROR\t"); + break; + case 2: + DECODE_PRINTF("RCL\t"); + break; + case 3: + DECODE_PRINTF("RCR\t"); + break; + case 4: + DECODE_PRINTF("SHL\t"); + break; + case 5: + DECODE_PRINTF("SHR\t"); + break; + case 6: + DECODE_PRINTF("SAL\t"); + break; + case 7: + DECODE_PRINTF("SAR\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) { + case 0: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, 1); + store_data_byte(destoffset, destval); + break; + case 1: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, 1); + store_data_byte(destoffset, destval); + break; + case 2: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, 1); + store_data_byte(destoffset, destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(",1\n"); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (*destreg, 1); + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd1 +****************************************************************************/ +void x86emuOp_opcD1_word_RM_1(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + switch (rh) { + case 0: + DECODE_PRINTF("ROL\t"); + break; + case 1: + DECODE_PRINTF("ROR\t"); + break; + case 2: + DECODE_PRINTF("RCL\t"); + break; + case 3: + DECODE_PRINTF("RCR\t"); + break; + case 4: + DECODE_PRINTF("SHL\t"); + break; + case 5: + DECODE_PRINTF("SHR\t"); + break; + case 6: + DECODE_PRINTF("SAL\t"); + break; + case 7: + DECODE_PRINTF("SAR\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, 1); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, 1); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, 1); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, 1); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, 1); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(",1\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, 1); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(",1\n"); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (*destreg, 1); + *destreg = destval; + } else { + u16 destval; + u16 *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(",1\n"); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (*destreg, 1); + *destreg = destval; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd2 +****************************************************************************/ +void x86emuOp_opcD2_byte_RM_CL(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg; + uint destoffset; + u8 destval; + u8 amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + switch (rh) { + case 0: + DECODE_PRINTF("ROL\t"); + break; + case 1: + DECODE_PRINTF("ROR\t"); + break; + case 2: + DECODE_PRINTF("RCL\t"); + break; + case 3: + DECODE_PRINTF("RCR\t"); + break; + case 4: + DECODE_PRINTF("SHL\t"); + break; + case 5: + DECODE_PRINTF("SHR\t"); + break; + case 6: + DECODE_PRINTF("SAL\t"); + break; + case 7: + DECODE_PRINTF("SAR\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + amt = M.x86.R_CL; + switch (mod) { + case 0: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, amt); + store_data_byte(destoffset, destval); + break; + case 1: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, amt); + store_data_byte(destoffset, destval); + break; + case 2: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (destval, amt); + store_data_byte(destoffset, destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = (*opcD0_byte_operation[rh]) (*destreg, amt); + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd3 +****************************************************************************/ +void x86emuOp_opcD3_word_RM_CL(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + u8 amt; + + /* + * Yet another weirdo special case instruction format. Part of + * the opcode held below in "RH". Doubly nested case would + * result, except that the decoded instruction + */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + switch (rh) { + case 0: + DECODE_PRINTF("ROL\t"); + break; + case 1: + DECODE_PRINTF("ROR\t"); + break; + case 2: + DECODE_PRINTF("RCL\t"); + break; + case 3: + DECODE_PRINTF("RCR\t"); + break; + case 4: + DECODE_PRINTF("SHL\t"); + break; + case 5: + DECODE_PRINTF("SHR\t"); + break; + case 6: + DECODE_PRINTF("SAL\t"); + break; + case 7: + DECODE_PRINTF("SAR\t"); + break; + } + } +#endif + /* know operation, decode the mod byte to find the addressing + mode. */ + amt = M.x86.R_CL; + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, amt); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, amt); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_long_operation[rh]) (destval, amt); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("WORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(",CL\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = (*opcD1_word_operation[rh]) (destval, amt); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); + } else { + u16 *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + *destreg = (*opcD1_word_operation[rh]) (*destreg, amt); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd4 +****************************************************************************/ +void x86emuOp_aam(u8 X86EMU_UNUSED(op1)) +{ + u8 a; + + START_OF_INSTR(); + DECODE_PRINTF("AAM\n"); + a = fetch_byte_imm(); /* this is a stupid encoding. */ + if (a != 10) { + DECODE_PRINTF("ERROR DECODING AAM\n"); + TRACE_REGS(); + HALT_SYS(); + } + TRACE_AND_STEP(); + /* note the type change here --- returning AL and AH in AX. */ + M.x86.R_AX = aam_word(M.x86.R_AL); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd5 +****************************************************************************/ +void x86emuOp_aad(u8 X86EMU_UNUSED(op1)) +{ + u8 a; + + START_OF_INSTR(); + DECODE_PRINTF("AAD\n"); + a = fetch_byte_imm(); + TRACE_AND_STEP(); + M.x86.R_AX = aad_word(M.x86.R_AX); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/* opcode 0xd6 ILLEGAL OPCODE */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xd7 +****************************************************************************/ +void x86emuOp_xlat(u8 X86EMU_UNUSED(op1)) +{ + u16 addr; + + START_OF_INSTR(); + DECODE_PRINTF("XLAT\n"); + TRACE_AND_STEP(); + addr = (u16)(M.x86.R_BX + (u8)M.x86.R_AL); + M.x86.R_AL = fetch_data_byte(addr); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/* instuctions D8 .. DF are in i87_ops.c */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xe0 +****************************************************************************/ +void x86emuOp_loopne(u8 X86EMU_UNUSED(op1)) +{ + s16 ip; + + START_OF_INSTR(); + DECODE_PRINTF("LOOPNE\t"); + ip = (s8) fetch_byte_imm(); + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); + M.x86.R_CX -= 1; + if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF)) /* CX != 0 and !ZF */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe1 +****************************************************************************/ +void x86emuOp_loope(u8 X86EMU_UNUSED(op1)) +{ + s16 ip; + + START_OF_INSTR(); + DECODE_PRINTF("LOOPE\t"); + ip = (s8) fetch_byte_imm(); + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); + M.x86.R_CX -= 1; + if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF)) /* CX != 0 and ZF */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe2 +****************************************************************************/ +void x86emuOp_loop(u8 X86EMU_UNUSED(op1)) +{ + s16 ip; + + START_OF_INSTR(); + DECODE_PRINTF("LOOP\t"); + ip = (s8) fetch_byte_imm(); + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); + M.x86.R_CX -= 1; + if (M.x86.R_CX != 0) + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe3 +****************************************************************************/ +void x86emuOp_jcxz(u8 X86EMU_UNUSED(op1)) +{ + u16 target; + s8 offset; + + /* jump to byte offset if overflow flag is set */ + START_OF_INSTR(); + DECODE_PRINTF("JCXZ\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + if (M.x86.R_CX == 0) + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe4 +****************************************************************************/ +void x86emuOp_in_byte_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 port; + + START_OF_INSTR(); + DECODE_PRINTF("IN\t"); + port = (u8) fetch_byte_imm(); + DECODE_PRINTF2("%x,AL\n", port); + TRACE_AND_STEP(); + M.x86.R_AL = (*sys_inb)(port); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe5 +****************************************************************************/ +void x86emuOp_in_word_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ + u8 port; + + START_OF_INSTR(); + DECODE_PRINTF("IN\t"); + port = (u8) fetch_byte_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("EAX,%x\n", port); + } else { + DECODE_PRINTF2("AX,%x\n", port); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EAX = (*sys_inl)(port); + } else { + M.x86.R_AX = (*sys_inw)(port); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe6 +****************************************************************************/ +void x86emuOp_out_byte_IMM_AL(u8 X86EMU_UNUSED(op1)) +{ + u8 port; + + START_OF_INSTR(); + DECODE_PRINTF("OUT\t"); + port = (u8) fetch_byte_imm(); + DECODE_PRINTF2("%x,AL\n", port); + TRACE_AND_STEP(); + (*sys_outb)(port, M.x86.R_AL); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe7 +****************************************************************************/ +void x86emuOp_out_word_IMM_AX(u8 X86EMU_UNUSED(op1)) +{ + u8 port; + + START_OF_INSTR(); + DECODE_PRINTF("OUT\t"); + port = (u8) fetch_byte_imm(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF2("%x,EAX\n", port); + } else { + DECODE_PRINTF2("%x,AX\n", port); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + (*sys_outl)(port, M.x86.R_EAX); + } else { + (*sys_outw)(port, M.x86.R_AX); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe8 +****************************************************************************/ +void x86emuOp_call_near_IMM(u8 X86EMU_UNUSED(op1)) +{ + s16 ip; + + START_OF_INSTR(); + DECODE_PRINTF("CALL\t"); + ip = (s16) fetch_word_imm(); + ip += (s16) M.x86.R_IP; /* CHECK SIGN */ + DECODE_PRINTF2("%04x\n", ip); + CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, ""); + TRACE_AND_STEP(); + push_word(M.x86.R_IP); + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe9 +****************************************************************************/ +void x86emuOp_jump_near_IMM(u8 X86EMU_UNUSED(op1)) +{ + int ip; + + START_OF_INSTR(); + DECODE_PRINTF("JMP\t"); + ip = (s16)fetch_word_imm(); + ip += (s16)M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); + M.x86.R_IP = (u16)ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xea +****************************************************************************/ +void x86emuOp_jump_far_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 cs, ip; + + START_OF_INSTR(); + DECODE_PRINTF("JMP\tFAR "); + ip = fetch_word_imm(); + cs = fetch_word_imm(); + DECODE_PRINTF2("%04x:", cs); + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); + M.x86.R_IP = ip; + M.x86.R_CS = cs; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xeb +****************************************************************************/ +void x86emuOp_jump_byte_IMM(u8 X86EMU_UNUSED(op1)) +{ + u16 target; + s8 offset; + + START_OF_INSTR(); + DECODE_PRINTF("JMP\t"); + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xec +****************************************************************************/ +void x86emuOp_in_byte_AL_DX(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("IN\tAL,DX\n"); + TRACE_AND_STEP(); + M.x86.R_AL = (*sys_inb)(M.x86.R_DX); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xed +****************************************************************************/ +void x86emuOp_in_word_AX_DX(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("IN\tEAX,DX\n"); + } else { + DECODE_PRINTF("IN\tAX,DX\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_EAX = (*sys_inl)(M.x86.R_DX); + } else { + M.x86.R_AX = (*sys_inw)(M.x86.R_DX); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xee +****************************************************************************/ +void x86emuOp_out_byte_DX_AL(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("OUT\tDX,AL\n"); + TRACE_AND_STEP(); + (*sys_outb)(M.x86.R_DX, M.x86.R_AL); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xef +****************************************************************************/ +void x86emuOp_out_word_DX_AX(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("OUT\tDX,EAX\n"); + } else { + DECODE_PRINTF("OUT\tDX,AX\n"); + } + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + (*sys_outl)(M.x86.R_DX, M.x86.R_EAX); + } else { + (*sys_outw)(M.x86.R_DX, M.x86.R_AX); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf0 +****************************************************************************/ +void x86emuOp_lock(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("LOCK:\n"); + TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/*opcode 0xf1 ILLEGAL OPERATION */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xf2 +****************************************************************************/ +void x86emuOp_repne(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("REPNE\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPNE; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf3 +****************************************************************************/ +void x86emuOp_repe(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("REPE\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPE; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf4 +****************************************************************************/ +void x86emuOp_halt(u8 X86EMU_UNUSED(op1)) +{ + START_OF_INSTR(); + DECODE_PRINTF("HALT\n"); + TRACE_AND_STEP(); + HALT_SYS(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf5 +****************************************************************************/ +void x86emuOp_cmc(u8 X86EMU_UNUSED(op1)) +{ + /* complement the carry flag. */ + START_OF_INSTR(); + DECODE_PRINTF("CMC\n"); + TRACE_AND_STEP(); + TOGGLE_FLAG(F_CF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf6 +****************************************************************************/ +void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + u8 *destreg; + uint destoffset; + u8 destval, srcval; + + /* long, drawn out code follows. Double switch for a total + of 32 cases. */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: /* mod=00 */ + switch (rh) { + case 0: /* test byte imm */ + DECODE_PRINTF("TEST\tBYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + srcval = fetch_byte_imm(); + DECODE_PRINTF2("%02x\n", srcval); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + test_byte(destval, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("NOT\tBYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = not_byte(destval); + store_data_byte(destoffset, destval); + break; + case 3: + DECODE_PRINTF("NEG\tBYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = neg_byte(destval); + store_data_byte(destoffset, destval); + break; + case 4: + DECODE_PRINTF("MUL\tBYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + mul_byte(destval); + break; + case 5: + DECODE_PRINTF("IMUL\tBYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + imul_byte(destval); + break; + case 6: + DECODE_PRINTF("DIV\tBYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + div_byte(destval); + break; + case 7: + DECODE_PRINTF("IDIV\tBYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + idiv_byte(destval); + break; + } + break; /* end mod==00 */ + case 1: /* mod=01 */ + switch (rh) { + case 0: /* test byte imm */ + DECODE_PRINTF("TEST\tBYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + srcval = fetch_byte_imm(); + DECODE_PRINTF2("%02x\n", srcval); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + test_byte(destval, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=01 RH=01 OP=F6\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("NOT\tBYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = not_byte(destval); + store_data_byte(destoffset, destval); + break; + case 3: + DECODE_PRINTF("NEG\tBYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = neg_byte(destval); + store_data_byte(destoffset, destval); + break; + case 4: + DECODE_PRINTF("MUL\tBYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + mul_byte(destval); + break; + case 5: + DECODE_PRINTF("IMUL\tBYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + imul_byte(destval); + break; + case 6: + DECODE_PRINTF("DIV\tBYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + div_byte(destval); + break; + case 7: + DECODE_PRINTF("IDIV\tBYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + idiv_byte(destval); + break; + } + break; /* end mod==01 */ + case 2: /* mod=10 */ + switch (rh) { + case 0: /* test byte imm */ + DECODE_PRINTF("TEST\tBYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + srcval = fetch_byte_imm(); + DECODE_PRINTF2("%02x\n", srcval); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + test_byte(destval, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=10 RH=01 OP=F6\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("NOT\tBYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = not_byte(destval); + store_data_byte(destoffset, destval); + break; + case 3: + DECODE_PRINTF("NEG\tBYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = neg_byte(destval); + store_data_byte(destoffset, destval); + break; + case 4: + DECODE_PRINTF("MUL\tBYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + mul_byte(destval); + break; + case 5: + DECODE_PRINTF("IMUL\tBYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + imul_byte(destval); + break; + case 6: + DECODE_PRINTF("DIV\tBYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + div_byte(destval); + break; + case 7: + DECODE_PRINTF("IDIV\tBYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + idiv_byte(destval); + break; + } + break; /* end mod==10 */ + case 3: /* mod=11 */ + switch (rh) { + case 0: /* test byte imm */ + DECODE_PRINTF("TEST\t"); + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF(","); + srcval = fetch_byte_imm(); + DECODE_PRINTF2("%02x\n", srcval); + TRACE_AND_STEP(); + test_byte(*destreg, srcval); + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); + HALT_SYS(); + break; + case 2: + DECODE_PRINTF("NOT\t"); + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = not_byte(*destreg); + break; + case 3: + DECODE_PRINTF("NEG\t"); + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = neg_byte(*destreg); + break; + case 4: + DECODE_PRINTF("MUL\t"); + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + mul_byte(*destreg); /*!!! */ + break; + case 5: + DECODE_PRINTF("IMUL\t"); + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + imul_byte(*destreg); + break; + case 6: + DECODE_PRINTF("DIV\t"); + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + div_byte(*destreg); + break; + case 7: + DECODE_PRINTF("IDIV\t"); + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + idiv_byte(*destreg); + break; + } + break; /* end mod==11 */ + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf7 +****************************************************************************/ +void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rl, rh; + uint destoffset; + + /* long, drawn out code follows. Double switch for a total + of 32 cases. */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: /* mod=00 */ + switch (rh) { + case 0: /* test word imm */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,srcval; + + DECODE_PRINTF("TEST\tDWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + srcval = fetch_long_imm(); + DECODE_PRINTF2("%x\n", srcval); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + test_long(destval, srcval); + } else { + u16 destval,srcval; + + DECODE_PRINTF("TEST\tWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + srcval = fetch_word_imm(); + DECODE_PRINTF2("%x\n", srcval); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + test_word(destval, srcval); + } + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); + HALT_SYS(); + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("NOT\tDWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = not_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("NOT\tWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = not_word(destval); + store_data_word(destoffset, destval); + } + break; + case 3: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("NEG\tDWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = neg_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("NEG\tWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = neg_word(destval); + store_data_word(destoffset, destval); + } + break; + case 4: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("MUL\tDWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + mul_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("MUL\tWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + mul_word(destval); + } + break; + case 5: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("IMUL\tDWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + imul_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("IMUL\tWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + imul_word(destval); + } + break; + case 6: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DIV\tDWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + div_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("DIV\tWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + div_word(destval); + } + break; + case 7: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("IDIV\tDWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + idiv_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("IDIV\tWORD PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + idiv_word(destval); + } + break; + } + break; /* end mod==00 */ + case 1: /* mod=01 */ + switch (rh) { + case 0: /* test word imm */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,srcval; + + DECODE_PRINTF("TEST\tDWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + srcval = fetch_long_imm(); + DECODE_PRINTF2("%x\n", srcval); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + test_long(destval, srcval); + } else { + u16 destval,srcval; + + DECODE_PRINTF("TEST\tWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + srcval = fetch_word_imm(); + DECODE_PRINTF2("%x\n", srcval); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + test_word(destval, srcval); + } + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=01 RH=01 OP=F6\n"); + HALT_SYS(); + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("NOT\tDWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = not_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("NOT\tWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = not_word(destval); + store_data_word(destoffset, destval); + } + break; + case 3: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("NEG\tDWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = neg_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("NEG\tWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = neg_word(destval); + store_data_word(destoffset, destval); + } + break; + case 4: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("MUL\tDWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + mul_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("MUL\tWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + mul_word(destval); + } + break; + case 5: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("IMUL\tDWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + imul_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("IMUL\tWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + imul_word(destval); + } + break; + case 6: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DIV\tDWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + div_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("DIV\tWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + div_word(destval); + } + break; + case 7: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("IDIV\tDWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + idiv_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("IDIV\tWORD PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + idiv_word(destval); + } + break; + } + break; /* end mod==01 */ + case 2: /* mod=10 */ + switch (rh) { + case 0: /* test word imm */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval,srcval; + + DECODE_PRINTF("TEST\tDWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + srcval = fetch_long_imm(); + DECODE_PRINTF2("%x\n", srcval); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + test_long(destval, srcval); + } else { + u16 destval,srcval; + + DECODE_PRINTF("TEST\tWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + srcval = fetch_word_imm(); + DECODE_PRINTF2("%x\n", srcval); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + test_word(destval, srcval); + } + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=10 RH=01 OP=F6\n"); + HALT_SYS(); + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("NOT\tDWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = not_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("NOT\tWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = not_word(destval); + store_data_word(destoffset, destval); + } + break; + case 3: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("NEG\tDWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = neg_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + DECODE_PRINTF("NEG\tWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = neg_word(destval); + store_data_word(destoffset, destval); + } + break; + case 4: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("MUL\tDWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + mul_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("MUL\tWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + mul_word(destval); + } + break; + case 5: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("IMUL\tDWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + imul_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("IMUL\tWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + imul_word(destval); + } + break; + case 6: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("DIV\tDWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + div_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("DIV\tWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + div_word(destval); + } + break; + case 7: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + DECODE_PRINTF("IDIV\tDWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + idiv_long(destval); + } else { + u16 destval; + + DECODE_PRINTF("IDIV\tWORD PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + idiv_word(destval); + } + break; + } + break; /* end mod==10 */ + case 3: /* mod=11 */ + switch (rh) { + case 0: /* test word imm */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + DECODE_PRINTF("TEST\t"); + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + srcval = fetch_long_imm(); + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + test_long(*destreg, srcval); + } else { + u16 *destreg; + u16 srcval; + + DECODE_PRINTF("TEST\t"); + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + srcval = fetch_word_imm(); + DECODE_PRINTF2("%x\n", srcval); + TRACE_AND_STEP(); + test_word(*destreg, srcval); + } + break; + case 1: + DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); + HALT_SYS(); + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + DECODE_PRINTF("NOT\t"); + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = not_long(*destreg); + } else { + u16 *destreg; + + DECODE_PRINTF("NOT\t"); + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = not_word(*destreg); + } + break; + case 3: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + DECODE_PRINTF("NEG\t"); + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = neg_long(*destreg); + } else { + u16 *destreg; + + DECODE_PRINTF("NEG\t"); + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = neg_word(*destreg); + } + break; + case 4: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + DECODE_PRINTF("MUL\t"); + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + mul_long(*destreg); /*!!! */ + } else { + u16 *destreg; + + DECODE_PRINTF("MUL\t"); + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + mul_word(*destreg); /*!!! */ + } + break; + case 5: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + DECODE_PRINTF("IMUL\t"); + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + imul_long(*destreg); + } else { + u16 *destreg; + + DECODE_PRINTF("IMUL\t"); + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + imul_word(*destreg); + } + break; + case 6: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + DECODE_PRINTF("DIV\t"); + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + div_long(*destreg); + } else { + u16 *destreg; + + DECODE_PRINTF("DIV\t"); + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + div_word(*destreg); + } + break; + case 7: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + DECODE_PRINTF("IDIV\t"); + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + idiv_long(*destreg); + } else { + u16 *destreg; + + DECODE_PRINTF("IDIV\t"); + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + idiv_word(*destreg); + } + break; + } + break; /* end mod==11 */ + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf8 +****************************************************************************/ +void x86emuOp_clc(u8 X86EMU_UNUSED(op1)) +{ + /* clear the carry flag. */ + START_OF_INSTR(); + DECODE_PRINTF("CLC\n"); + TRACE_AND_STEP(); + CLEAR_FLAG(F_CF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf9 +****************************************************************************/ +void x86emuOp_stc(u8 X86EMU_UNUSED(op1)) +{ + /* set the carry flag. */ + START_OF_INSTR(); + DECODE_PRINTF("STC\n"); + TRACE_AND_STEP(); + SET_FLAG(F_CF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfa +****************************************************************************/ +void x86emuOp_cli(u8 X86EMU_UNUSED(op1)) +{ + /* clear interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("CLI\n"); + TRACE_AND_STEP(); + CLEAR_FLAG(F_IF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfb +****************************************************************************/ +void x86emuOp_sti(u8 X86EMU_UNUSED(op1)) +{ + /* enable interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("STI\n"); + TRACE_AND_STEP(); + SET_FLAG(F_IF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfc +****************************************************************************/ +void x86emuOp_cld(u8 X86EMU_UNUSED(op1)) +{ + /* clear interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("CLD\n"); + TRACE_AND_STEP(); + CLEAR_FLAG(F_DF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfd +****************************************************************************/ +void x86emuOp_std(u8 X86EMU_UNUSED(op1)) +{ + /* clear interrupts. */ + START_OF_INSTR(); + DECODE_PRINTF("STD\n"); + TRACE_AND_STEP(); + SET_FLAG(F_DF); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfe +****************************************************************************/ +void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + u8 destval; + uint destoffset; + u8 *destreg; + + /* Yet another special case instruction. */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + + switch (rh) { + case 0: + DECODE_PRINTF("INC\t"); + break; + case 1: + DECODE_PRINTF("DEC\t"); + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + DECODE_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x \n", mod); + HALT_SYS(); + break; + } + } +#endif + switch (mod) { + case 0: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + switch (rh) { + case 0: /* inc word ptr ... */ + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = inc_byte(destval); + store_data_byte(destoffset, destval); + break; + case 1: /* dec word ptr ... */ + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = dec_byte(destval); + store_data_byte(destoffset, destval); + break; + } + break; + case 1: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + switch (rh) { + case 0: + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = inc_byte(destval); + store_data_byte(destoffset, destval); + break; + case 1: + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = dec_byte(destval); + store_data_byte(destoffset, destval); + break; + } + break; + case 2: + DECODE_PRINTF("BYTE PTR "); + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + switch (rh) { + case 0: + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = inc_byte(destval); + store_data_byte(destoffset, destval); + break; + case 1: + destval = fetch_data_byte(destoffset); + TRACE_AND_STEP(); + destval = dec_byte(destval); + store_data_byte(destoffset, destval); + break; + } + break; + case 3: + destreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + switch (rh) { + case 0: + TRACE_AND_STEP(); + *destreg = inc_byte(*destreg); + break; + case 1: + TRACE_AND_STEP(); + *destreg = dec_byte(*destreg); + break; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xff +****************************************************************************/ +void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1)) +{ + int mod, rh, rl; + uint destoffset = 0; + u16 *destreg; + u16 destval,destval2; + + /* Yet another special case instruction. */ + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG + if (DEBUG_DECODE()) { + /* XXX DECODE_PRINTF may be changed to something more + general, so that it is important to leave the strings + in the same format, even though the result is that the + above test is done twice. */ + + switch (rh) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("INC\tDWORD PTR "); + } else { + DECODE_PRINTF("INC\tWORD PTR "); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + DECODE_PRINTF("DEC\tDWORD PTR "); + } else { + DECODE_PRINTF("DEC\tWORD PTR "); + } + break; + case 2: + DECODE_PRINTF("CALL\t "); + break; + case 3: + DECODE_PRINTF("CALL\tFAR "); + break; + case 4: + DECODE_PRINTF("JMP\t"); + break; + case 5: + DECODE_PRINTF("JMP\tFAR "); + break; + case 6: + DECODE_PRINTF("PUSH\t"); + break; + case 7: + DECODE_PRINTF("ILLEGAL DECODING OF OPCODE FF\t"); + HALT_SYS(); + break; + } + } +#endif + switch (mod) { + case 0: + destoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + switch (rh) { + case 0: /* inc word ptr ... */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = inc_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = inc_word(destval); + store_data_word(destoffset, destval); + } + break; + case 1: /* dec word ptr ... */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = dec_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = dec_word(destval); + store_data_word(destoffset, destval); + } + break; + case 2: /* call word ptr ... */ + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + push_word(M.x86.R_IP); + M.x86.R_IP = destval; + break; + case 3: /* call far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); + TRACE_AND_STEP(); + push_word(M.x86.R_CS); + M.x86.R_CS = destval2; + push_word(M.x86.R_IP); + M.x86.R_IP = destval; + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + M.x86.R_CS = destval2; + break; + case 6: /* push word ptr ... */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + push_long(destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + push_word(destval); + } + break; + } + break; + case 1: + destoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + switch (rh) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = inc_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = inc_word(destval); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = dec_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = dec_word(destval); + store_data_word(destoffset, destval); + } + break; + case 2: /* call word ptr ... */ + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + push_word(M.x86.R_IP); + M.x86.R_IP = destval; + break; + case 3: /* call far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); + TRACE_AND_STEP(); + push_word(M.x86.R_CS); + M.x86.R_CS = destval2; + push_word(M.x86.R_IP); + M.x86.R_IP = destval; + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + M.x86.R_CS = destval2; + break; + case 6: /* push word ptr ... */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + push_long(destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + push_word(destval); + } + break; + } + break; + case 2: + destoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + switch (rh) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = inc_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = inc_word(destval); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + destval = dec_long(destval); + store_data_long(destoffset, destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + destval = dec_word(destval); + store_data_word(destoffset, destval); + } + break; + case 2: /* call word ptr ... */ + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + push_word(M.x86.R_IP); + M.x86.R_IP = destval; + break; + case 3: /* call far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); + TRACE_AND_STEP(); + push_word(M.x86.R_CS); + M.x86.R_CS = destval2; + push_word(M.x86.R_IP); + M.x86.R_IP = destval; + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + M.x86.R_CS = destval2; + break; + case 6: /* push word ptr ... */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + + destval = fetch_data_long(destoffset); + TRACE_AND_STEP(); + push_long(destval); + } else { + u16 destval; + + destval = fetch_data_word(destoffset); + TRACE_AND_STEP(); + push_word(destval); + } + break; + } + break; + case 3: + switch (rh) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = inc_long(*destreg); + } else { + u16 *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = inc_word(*destreg); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = dec_long(*destreg); + } else { + u16 *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = dec_word(*destreg); + } + break; + case 2: /* call word ptr ... */ + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + push_word(M.x86.R_IP); + M.x86.R_IP = *destreg; + break; + case 3: /* jmp far ptr ... */ + DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); + TRACE_AND_STEP(); + HALT_SYS(); + break; + + case 4: /* jmp ... */ + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + M.x86.R_IP = (u16) (*destreg); + break; + case 5: /* jmp far ptr ... */ + DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); + TRACE_AND_STEP(); + HALT_SYS(); + break; + case 6: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + push_long(*destreg); + } else { + u16 *destreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + push_word(*destreg); + } + break; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/*************************************************************************** + * Single byte operation code table: + **************************************************************************/ +void (*x86emu_optab[256])(u8) = +{ +/* 0x00 */ x86emuOp_add_byte_RM_R, +/* 0x01 */ x86emuOp_add_word_RM_R, +/* 0x02 */ x86emuOp_add_byte_R_RM, +/* 0x03 */ x86emuOp_add_word_R_RM, +/* 0x04 */ x86emuOp_add_byte_AL_IMM, +/* 0x05 */ x86emuOp_add_word_AX_IMM, +/* 0x06 */ x86emuOp_push_ES, +/* 0x07 */ x86emuOp_pop_ES, + +/* 0x08 */ x86emuOp_or_byte_RM_R, +/* 0x09 */ x86emuOp_or_word_RM_R, +/* 0x0a */ x86emuOp_or_byte_R_RM, +/* 0x0b */ x86emuOp_or_word_R_RM, +/* 0x0c */ x86emuOp_or_byte_AL_IMM, +/* 0x0d */ x86emuOp_or_word_AX_IMM, +/* 0x0e */ x86emuOp_push_CS, +/* 0x0f */ x86emuOp_two_byte, + +/* 0x10 */ x86emuOp_adc_byte_RM_R, +/* 0x11 */ x86emuOp_adc_word_RM_R, +/* 0x12 */ x86emuOp_adc_byte_R_RM, +/* 0x13 */ x86emuOp_adc_word_R_RM, +/* 0x14 */ x86emuOp_adc_byte_AL_IMM, +/* 0x15 */ x86emuOp_adc_word_AX_IMM, +/* 0x16 */ x86emuOp_push_SS, +/* 0x17 */ x86emuOp_pop_SS, + +/* 0x18 */ x86emuOp_sbb_byte_RM_R, +/* 0x19 */ x86emuOp_sbb_word_RM_R, +/* 0x1a */ x86emuOp_sbb_byte_R_RM, +/* 0x1b */ x86emuOp_sbb_word_R_RM, +/* 0x1c */ x86emuOp_sbb_byte_AL_IMM, +/* 0x1d */ x86emuOp_sbb_word_AX_IMM, +/* 0x1e */ x86emuOp_push_DS, +/* 0x1f */ x86emuOp_pop_DS, + +/* 0x20 */ x86emuOp_and_byte_RM_R, +/* 0x21 */ x86emuOp_and_word_RM_R, +/* 0x22 */ x86emuOp_and_byte_R_RM, +/* 0x23 */ x86emuOp_and_word_R_RM, +/* 0x24 */ x86emuOp_and_byte_AL_IMM, +/* 0x25 */ x86emuOp_and_word_AX_IMM, +/* 0x26 */ x86emuOp_segovr_ES, +/* 0x27 */ x86emuOp_daa, + +/* 0x28 */ x86emuOp_sub_byte_RM_R, +/* 0x29 */ x86emuOp_sub_word_RM_R, +/* 0x2a */ x86emuOp_sub_byte_R_RM, +/* 0x2b */ x86emuOp_sub_word_R_RM, +/* 0x2c */ x86emuOp_sub_byte_AL_IMM, +/* 0x2d */ x86emuOp_sub_word_AX_IMM, +/* 0x2e */ x86emuOp_segovr_CS, +/* 0x2f */ x86emuOp_das, + +/* 0x30 */ x86emuOp_xor_byte_RM_R, +/* 0x31 */ x86emuOp_xor_word_RM_R, +/* 0x32 */ x86emuOp_xor_byte_R_RM, +/* 0x33 */ x86emuOp_xor_word_R_RM, +/* 0x34 */ x86emuOp_xor_byte_AL_IMM, +/* 0x35 */ x86emuOp_xor_word_AX_IMM, +/* 0x36 */ x86emuOp_segovr_SS, +/* 0x37 */ x86emuOp_aaa, + +/* 0x38 */ x86emuOp_cmp_byte_RM_R, +/* 0x39 */ x86emuOp_cmp_word_RM_R, +/* 0x3a */ x86emuOp_cmp_byte_R_RM, +/* 0x3b */ x86emuOp_cmp_word_R_RM, +/* 0x3c */ x86emuOp_cmp_byte_AL_IMM, +/* 0x3d */ x86emuOp_cmp_word_AX_IMM, +/* 0x3e */ x86emuOp_segovr_DS, +/* 0x3f */ x86emuOp_aas, + +/* 0x40 */ x86emuOp_inc_AX, +/* 0x41 */ x86emuOp_inc_CX, +/* 0x42 */ x86emuOp_inc_DX, +/* 0x43 */ x86emuOp_inc_BX, +/* 0x44 */ x86emuOp_inc_SP, +/* 0x45 */ x86emuOp_inc_BP, +/* 0x46 */ x86emuOp_inc_SI, +/* 0x47 */ x86emuOp_inc_DI, + +/* 0x48 */ x86emuOp_dec_AX, +/* 0x49 */ x86emuOp_dec_CX, +/* 0x4a */ x86emuOp_dec_DX, +/* 0x4b */ x86emuOp_dec_BX, +/* 0x4c */ x86emuOp_dec_SP, +/* 0x4d */ x86emuOp_dec_BP, +/* 0x4e */ x86emuOp_dec_SI, +/* 0x4f */ x86emuOp_dec_DI, + +/* 0x50 */ x86emuOp_push_AX, +/* 0x51 */ x86emuOp_push_CX, +/* 0x52 */ x86emuOp_push_DX, +/* 0x53 */ x86emuOp_push_BX, +/* 0x54 */ x86emuOp_push_SP, +/* 0x55 */ x86emuOp_push_BP, +/* 0x56 */ x86emuOp_push_SI, +/* 0x57 */ x86emuOp_push_DI, + +/* 0x58 */ x86emuOp_pop_AX, +/* 0x59 */ x86emuOp_pop_CX, +/* 0x5a */ x86emuOp_pop_DX, +/* 0x5b */ x86emuOp_pop_BX, +/* 0x5c */ x86emuOp_pop_SP, +/* 0x5d */ x86emuOp_pop_BP, +/* 0x5e */ x86emuOp_pop_SI, +/* 0x5f */ x86emuOp_pop_DI, + +/* 0x60 */ x86emuOp_push_all, +/* 0x61 */ x86emuOp_pop_all, +/* 0x62 */ x86emuOp_illegal_op, /* bound */ +/* 0x63 */ x86emuOp_illegal_op, /* arpl */ +/* 0x64 */ x86emuOp_segovr_FS, +/* 0x65 */ x86emuOp_segovr_GS, +/* 0x66 */ x86emuOp_prefix_data, +/* 0x67 */ x86emuOp_prefix_addr, + +/* 0x68 */ x86emuOp_push_word_IMM, +/* 0x69 */ x86emuOp_imul_word_IMM, +/* 0x6a */ x86emuOp_push_byte_IMM, +/* 0x6b */ x86emuOp_imul_byte_IMM, +/* 0x6c */ x86emuOp_ins_byte, +/* 0x6d */ x86emuOp_ins_word, +/* 0x6e */ x86emuOp_outs_byte, +/* 0x6f */ x86emuOp_outs_word, + +/* 0x70 */ x86emuOp_jump_near_O, +/* 0x71 */ x86emuOp_jump_near_NO, +/* 0x72 */ x86emuOp_jump_near_B, +/* 0x73 */ x86emuOp_jump_near_NB, +/* 0x74 */ x86emuOp_jump_near_Z, +/* 0x75 */ x86emuOp_jump_near_NZ, +/* 0x76 */ x86emuOp_jump_near_BE, +/* 0x77 */ x86emuOp_jump_near_NBE, + +/* 0x78 */ x86emuOp_jump_near_S, +/* 0x79 */ x86emuOp_jump_near_NS, +/* 0x7a */ x86emuOp_jump_near_P, +/* 0x7b */ x86emuOp_jump_near_NP, +/* 0x7c */ x86emuOp_jump_near_L, +/* 0x7d */ x86emuOp_jump_near_NL, +/* 0x7e */ x86emuOp_jump_near_LE, +/* 0x7f */ x86emuOp_jump_near_NLE, + +/* 0x80 */ x86emuOp_opc80_byte_RM_IMM, +/* 0x81 */ x86emuOp_opc81_word_RM_IMM, +/* 0x82 */ x86emuOp_opc82_byte_RM_IMM, +/* 0x83 */ x86emuOp_opc83_word_RM_IMM, +/* 0x84 */ x86emuOp_test_byte_RM_R, +/* 0x85 */ x86emuOp_test_word_RM_R, +/* 0x86 */ x86emuOp_xchg_byte_RM_R, +/* 0x87 */ x86emuOp_xchg_word_RM_R, + +/* 0x88 */ x86emuOp_mov_byte_RM_R, +/* 0x89 */ x86emuOp_mov_word_RM_R, +/* 0x8a */ x86emuOp_mov_byte_R_RM, +/* 0x8b */ x86emuOp_mov_word_R_RM, +/* 0x8c */ x86emuOp_mov_word_RM_SR, +/* 0x8d */ x86emuOp_lea_word_R_M, +/* 0x8e */ x86emuOp_mov_word_SR_RM, +/* 0x8f */ x86emuOp_pop_RM, + +/* 0x90 */ x86emuOp_nop, +/* 0x91 */ x86emuOp_xchg_word_AX_CX, +/* 0x92 */ x86emuOp_xchg_word_AX_DX, +/* 0x93 */ x86emuOp_xchg_word_AX_BX, +/* 0x94 */ x86emuOp_xchg_word_AX_SP, +/* 0x95 */ x86emuOp_xchg_word_AX_BP, +/* 0x96 */ x86emuOp_xchg_word_AX_SI, +/* 0x97 */ x86emuOp_xchg_word_AX_DI, + +/* 0x98 */ x86emuOp_cbw, +/* 0x99 */ x86emuOp_cwd, +/* 0x9a */ x86emuOp_call_far_IMM, +/* 0x9b */ x86emuOp_wait, +/* 0x9c */ x86emuOp_pushf_word, +/* 0x9d */ x86emuOp_popf_word, +/* 0x9e */ x86emuOp_sahf, +/* 0x9f */ x86emuOp_lahf, + +/* 0xa0 */ x86emuOp_mov_AL_M_IMM, +/* 0xa1 */ x86emuOp_mov_AX_M_IMM, +/* 0xa2 */ x86emuOp_mov_M_AL_IMM, +/* 0xa3 */ x86emuOp_mov_M_AX_IMM, +/* 0xa4 */ x86emuOp_movs_byte, +/* 0xa5 */ x86emuOp_movs_word, +/* 0xa6 */ x86emuOp_cmps_byte, +/* 0xa7 */ x86emuOp_cmps_word, +/* 0xa8 */ x86emuOp_test_AL_IMM, +/* 0xa9 */ x86emuOp_test_AX_IMM, +/* 0xaa */ x86emuOp_stos_byte, +/* 0xab */ x86emuOp_stos_word, +/* 0xac */ x86emuOp_lods_byte, +/* 0xad */ x86emuOp_lods_word, +/* 0xac */ x86emuOp_scas_byte, +/* 0xad */ x86emuOp_scas_word, + + +/* 0xb0 */ x86emuOp_mov_byte_AL_IMM, +/* 0xb1 */ x86emuOp_mov_byte_CL_IMM, +/* 0xb2 */ x86emuOp_mov_byte_DL_IMM, +/* 0xb3 */ x86emuOp_mov_byte_BL_IMM, +/* 0xb4 */ x86emuOp_mov_byte_AH_IMM, +/* 0xb5 */ x86emuOp_mov_byte_CH_IMM, +/* 0xb6 */ x86emuOp_mov_byte_DH_IMM, +/* 0xb7 */ x86emuOp_mov_byte_BH_IMM, + +/* 0xb8 */ x86emuOp_mov_word_AX_IMM, +/* 0xb9 */ x86emuOp_mov_word_CX_IMM, +/* 0xba */ x86emuOp_mov_word_DX_IMM, +/* 0xbb */ x86emuOp_mov_word_BX_IMM, +/* 0xbc */ x86emuOp_mov_word_SP_IMM, +/* 0xbd */ x86emuOp_mov_word_BP_IMM, +/* 0xbe */ x86emuOp_mov_word_SI_IMM, +/* 0xbf */ x86emuOp_mov_word_DI_IMM, + +/* 0xc0 */ x86emuOp_opcC0_byte_RM_MEM, +/* 0xc1 */ x86emuOp_opcC1_word_RM_MEM, +/* 0xc2 */ x86emuOp_ret_near_IMM, +/* 0xc3 */ x86emuOp_ret_near, +/* 0xc4 */ x86emuOp_les_R_IMM, +/* 0xc5 */ x86emuOp_lds_R_IMM, +/* 0xc6 */ x86emuOp_mov_byte_RM_IMM, +/* 0xc7 */ x86emuOp_mov_word_RM_IMM, +/* 0xc8 */ x86emuOp_enter, +/* 0xc9 */ x86emuOp_leave, +/* 0xca */ x86emuOp_ret_far_IMM, +/* 0xcb */ x86emuOp_ret_far, +/* 0xcc */ x86emuOp_int3, +/* 0xcd */ x86emuOp_int_IMM, +/* 0xce */ x86emuOp_into, +/* 0xcf */ x86emuOp_iret, + +/* 0xd0 */ x86emuOp_opcD0_byte_RM_1, +/* 0xd1 */ x86emuOp_opcD1_word_RM_1, +/* 0xd2 */ x86emuOp_opcD2_byte_RM_CL, +/* 0xd3 */ x86emuOp_opcD3_word_RM_CL, +/* 0xd4 */ x86emuOp_aam, +/* 0xd5 */ x86emuOp_aad, +/* 0xd6 */ x86emuOp_illegal_op, /* Undocumented SETALC instruction */ +/* 0xd7 */ x86emuOp_xlat, +/* 0xd8 */ x86emuOp_esc_coprocess_d8, +/* 0xd9 */ x86emuOp_esc_coprocess_d9, +/* 0xda */ x86emuOp_esc_coprocess_da, +/* 0xdb */ x86emuOp_esc_coprocess_db, +/* 0xdc */ x86emuOp_esc_coprocess_dc, +/* 0xdd */ x86emuOp_esc_coprocess_dd, +/* 0xde */ x86emuOp_esc_coprocess_de, +/* 0xdf */ x86emuOp_esc_coprocess_df, + +/* 0xe0 */ x86emuOp_loopne, +/* 0xe1 */ x86emuOp_loope, +/* 0xe2 */ x86emuOp_loop, +/* 0xe3 */ x86emuOp_jcxz, +/* 0xe4 */ x86emuOp_in_byte_AL_IMM, +/* 0xe5 */ x86emuOp_in_word_AX_IMM, +/* 0xe6 */ x86emuOp_out_byte_IMM_AL, +/* 0xe7 */ x86emuOp_out_word_IMM_AX, + +/* 0xe8 */ x86emuOp_call_near_IMM, +/* 0xe9 */ x86emuOp_jump_near_IMM, +/* 0xea */ x86emuOp_jump_far_IMM, +/* 0xeb */ x86emuOp_jump_byte_IMM, +/* 0xec */ x86emuOp_in_byte_AL_DX, +/* 0xed */ x86emuOp_in_word_AX_DX, +/* 0xee */ x86emuOp_out_byte_DX_AL, +/* 0xef */ x86emuOp_out_word_DX_AX, + +/* 0xf0 */ x86emuOp_lock, +/* 0xf1 */ x86emuOp_illegal_op, +/* 0xf2 */ x86emuOp_repne, +/* 0xf3 */ x86emuOp_repe, +/* 0xf4 */ x86emuOp_halt, +/* 0xf5 */ x86emuOp_cmc, +/* 0xf6 */ x86emuOp_opcF6_byte_RM, +/* 0xf7 */ x86emuOp_opcF7_word_RM, + +/* 0xf8 */ x86emuOp_clc, +/* 0xf9 */ x86emuOp_stc, +/* 0xfa */ x86emuOp_cli, +/* 0xfb */ x86emuOp_sti, +/* 0xfc */ x86emuOp_cld, +/* 0xfd */ x86emuOp_std, +/* 0xfe */ x86emuOp_opcFE_byte_RM, +/* 0xff */ x86emuOp_opcFF_word_RM, +}; diff --git a/cfe/cfe/x86emu/ops2.c b/cfe/cfe/x86emu/ops2.c new file mode 100644 index 0000000..c59c813 --- /dev/null +++ b/cfe/cfe/x86emu/ops2.c @@ -0,0 +1,2802 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: This file includes subroutines to implement the decoding +* and emulation of all the x86 extended two-byte processor +* instructions. +* +****************************************************************************/ +/* $XFree86: xc/extras/x86emu/src/x86emu/ops2.c,v 1.4 2000/11/16 19:44:50 eich Exp $ */ + +#include "x86emu/x86emui.h" +#include "x86emu/ops_protos.h" + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +op1 - Instruction op code + +REMARKS: +Handles illegal opcodes. +****************************************************************************/ +void x86emuOp2_illegal_op( + u8 op2) +{ + START_OF_INSTR(); + DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); + TRACE_REGS(); + printk("%04x:%04x: %02X ILLEGAL EXTENDED X86 OPCODE!\n", + M.x86.R_CS, M.x86.R_IP-2,op2); + HALT_SYS(); + END_OF_INSTR(); +} + +#define xorl(a,b) ((a) && !(b)) || (!(a) && (b)) + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x80-0x8F +****************************************************************************/ +void x86emuOp2_long_jump(u8 op2) +{ + s32 target; + char *name = 0; + int cond = 0; + + /* conditional jump to word offset. */ + START_OF_INSTR(); + switch (op2) { + case 0x80: + name = "JO\t"; + cond = ACCESS_FLAG(F_OF); + break; + case 0x81: + name = "JNO\t"; + cond = !ACCESS_FLAG(F_OF); + break; + case 0x82: + name = "JB\t"; + cond = ACCESS_FLAG(F_CF); + break; + case 0x83: + name = "JNB\t"; + cond = !ACCESS_FLAG(F_CF); + break; + case 0x84: + name = "JZ\t"; + cond = ACCESS_FLAG(F_ZF); + break; + case 0x85: + name = "JNZ\t"; + cond = !ACCESS_FLAG(F_ZF); + break; + case 0x86: + name = "JBE\t"; + cond = ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF); + break; + case 0x87: + name = "JNBE\t"; + cond = !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); + break; + case 0x88: + name = "JS\t"; + cond = ACCESS_FLAG(F_SF); + break; + case 0x89: + name = "JNS\t"; + cond = !ACCESS_FLAG(F_SF); + break; + case 0x8a: + name = "JP\t"; + cond = ACCESS_FLAG(F_PF); + break; + case 0x8b: + name = "JNP\t"; + cond = !ACCESS_FLAG(F_PF); + break; + case 0x8c: + name = "JL\t"; + cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); + break; + case 0x8d: + name = "JNL\t"; + cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); + break; + case 0x8e: + name = "JLE\t"; + cond = (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || + ACCESS_FLAG(F_ZF)); + break; + case 0x8f: + name = "JNLE\t"; + cond = !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || + ACCESS_FLAG(F_ZF)); + break; + } + DECODE_PRINTF(name); + target = (s16) fetch_word_imm(); + target += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", target); + TRACE_AND_STEP(); + if (cond) + M.x86.R_IP = (u16)target; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x90-0x9F +****************************************************************************/ +void x86emuOp2_set_byte(u8 op2) +{ + int mod, rl, rh; + uint destoffset; + u8 *destreg; + char *name = 0; + int cond = 0; + + START_OF_INSTR(); + switch (op2) { + case 0x90: + name = "SETO\t"; + cond = ACCESS_FLAG(F_OF); + break; + case 0x91: + name = "SETNO\t"; + cond = !ACCESS_FLAG(F_OF); + break; + case 0x92: + name = "SETB\t"; + cond = ACCESS_FLAG(F_CF); + break; + case 0x93: + name = "SETNB\t"; + cond = !ACCESS_FLAG(F_CF); + break; + case 0x94: + name = "SETZ\t"; + cond = ACCESS_FLAG(F_ZF); + break; + case 0x95: + name = "SETNZ\t"; + cond = !ACCESS_FLAG(F_ZF); + break; + case 0x96: + name = "SETBE\t"; + cond = ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF); + break; + case 0x97: + name = "SETNBE\t"; + cond = !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); + break; + case 0x98: + name = "SETS\t"; + cond = ACCESS_FLAG(F_SF); + break; + case 0x99: + name = "SETNS\t"; + cond = !ACCESS_FLAG(F_SF); + break; + case 0x9a: + name = "SETP\t"; + cond = ACCESS_FLAG(F_PF); + break; + case 0x9b: + name = "SETNP\t"; + cond = !ACCESS_FLAG(F_PF); + break; + case 0x9c: + name = "SETL\t"; + cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); + break; + case 0x9d: + name = "SETNL\t"; + cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); + break; + case 0x9e: + name = "SETLE\t"; + cond = (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || + ACCESS_FLAG(F_ZF)); + break; + case 0x9f: + name = "SETNLE\t"; + cond = !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || + ACCESS_FLAG(F_ZF)); + break; + } + DECODE_PRINTF(name); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destoffset = decode_rm00_address(rl); + TRACE_AND_STEP(); + store_data_byte(destoffset, cond ? 0x01 : 0x00); + break; + case 1: + destoffset = decode_rm01_address(rl); + TRACE_AND_STEP(); + store_data_byte(destoffset, cond ? 0x01 : 0x00); + break; + case 2: + destoffset = decode_rm10_address(rl); + TRACE_AND_STEP(); + store_data_byte(destoffset, cond ? 0x01 : 0x00); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(rl); + TRACE_AND_STEP(); + *destreg = cond ? 0x01 : 0x00; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa0 +****************************************************************************/ +void x86emuOp2_push_FS(u8 X86EMU_UNUSED(op2)) +{ + START_OF_INSTR(); + DECODE_PRINTF("PUSH\tFS\n"); + TRACE_AND_STEP(); + push_word(M.x86.R_FS); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa1 +****************************************************************************/ +void x86emuOp2_pop_FS(u8 X86EMU_UNUSED(op2)) +{ + START_OF_INSTR(); + DECODE_PRINTF("POP\tFS\n"); + TRACE_AND_STEP(); + M.x86.R_FS = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa3 +****************************************************************************/ +void x86emuOp2_bt_R(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + int bit,disp; + + START_OF_INSTR(); + DECODE_PRINTF("BT\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval; + u32 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); + } else { + u16 srcval; + u16 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval; + u32 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); + } else { + u16 srcval; + u16 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval; + u32 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); + } else { + u16 srcval; + u16 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg,*shiftreg; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF); + } else { + u16 *srcreg,*shiftreg; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa4 +****************************************************************************/ +void x86emuOp2_shld_IMM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint destoffset; + u8 shift; + + START_OF_INSTR(); + DECODE_PRINTF("SHLD\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shld_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shld_word(destval,*shiftreg,shift); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shld_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shld_word(destval,*shiftreg,shift); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shld_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shld_word(destval,*shiftreg,shift); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*shiftreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + *destreg = shld_long(*destreg,*shiftreg,shift); + } else { + u16 *destreg,*shiftreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + *destreg = shld_word(*destreg,*shiftreg,shift); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa5 +****************************************************************************/ +void x86emuOp2_shld_CL(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("SHLD\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shld_long(destval,*shiftreg,M.x86.R_CL); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shld_word(destval,*shiftreg,M.x86.R_CL); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shld_long(destval,*shiftreg,M.x86.R_CL); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shld_word(destval,*shiftreg,M.x86.R_CL); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shld_long(destval,*shiftreg,M.x86.R_CL); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shld_word(destval,*shiftreg,M.x86.R_CL); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*shiftreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + *destreg = shld_long(*destreg,*shiftreg,M.x86.R_CL); + } else { + u16 *destreg,*shiftreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + *destreg = shld_word(*destreg,*shiftreg,M.x86.R_CL); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa8 +****************************************************************************/ +void x86emuOp2_push_GS(u8 X86EMU_UNUSED(op2)) +{ + START_OF_INSTR(); + DECODE_PRINTF("PUSH\tGS\n"); + TRACE_AND_STEP(); + push_word(M.x86.R_GS); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa9 +****************************************************************************/ +void x86emuOp2_pop_GS(u8 X86EMU_UNUSED(op2)) +{ + START_OF_INSTR(); + DECODE_PRINTF("POP\tGS\n"); + TRACE_AND_STEP(); + M.x86.R_GS = pop_word(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xaa +****************************************************************************/ +void x86emuOp2_bts_R(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + int bit,disp; + + START_OF_INSTR(); + DECODE_PRINTF("BTS\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval | mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, srcval | mask); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval | mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, srcval | mask); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval | mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, srcval | mask); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg,*shiftreg; + u32 mask; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + *srcreg |= mask; + } else { + u16 *srcreg,*shiftreg; + u16 mask; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + *srcreg |= mask; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xac +****************************************************************************/ +void x86emuOp2_shrd_IMM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint destoffset; + u8 shift; + + START_OF_INSTR(); + DECODE_PRINTF("SHLD\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shrd_word(destval,*shiftreg,shift); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shrd_word(destval,*shiftreg,shift); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,shift); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shrd_word(destval,*shiftreg,shift); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*shiftreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + *destreg = shrd_long(*destreg,*shiftreg,shift); + } else { + u16 *destreg,*shiftreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + DECODE_PRINTF2("%d\n", shift); + TRACE_AND_STEP(); + *destreg = shrd_word(*destreg,*shiftreg,shift); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xad +****************************************************************************/ +void x86emuOp2_shrd_CL(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint destoffset; + + START_OF_INSTR(); + DECODE_PRINTF("SHLD\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,M.x86.R_CL); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shrd_word(destval,*shiftreg,M.x86.R_CL); + store_data_word(destoffset, destval); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,M.x86.R_CL); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shrd_word(destval,*shiftreg,M.x86.R_CL); + store_data_word(destoffset, destval); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 destval; + u32 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_long(destoffset); + destval = shrd_long(destval,*shiftreg,M.x86.R_CL); + store_data_long(destoffset, destval); + } else { + u16 destval; + u16 *shiftreg; + + destoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + destval = fetch_data_word(destoffset); + destval = shrd_word(destval,*shiftreg,M.x86.R_CL); + store_data_word(destoffset, destval); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*shiftreg; + + destreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + *destreg = shrd_long(*destreg,*shiftreg,M.x86.R_CL); + } else { + u16 *destreg,*shiftreg; + + destreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(",CL\n"); + TRACE_AND_STEP(); + *destreg = shrd_word(*destreg,*shiftreg,M.x86.R_CL); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xaf +****************************************************************************/ +void x86emuOp2_imul_R_RM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("IMUL\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_long(srcoffset); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_word(srcoffset); + TRACE_AND_STEP(); + res = (s16)*destreg * (s16)srcval; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_long(srcoffset); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_word(srcoffset); + TRACE_AND_STEP(); + res = (s16)*destreg * (s16)srcval; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_long(srcoffset); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg; + u16 srcval; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_word(srcoffset); + TRACE_AND_STEP(); + res = (s16)*destreg * (s16)srcval; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg,*srcreg; + u32 res_lo,res_hi; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_LONG_REGISTER(rl); + TRACE_AND_STEP(); + imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)*srcreg); + if (res_hi != 0) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u32)res_lo; + } else { + u16 *destreg,*srcreg; + u32 res; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + res = (s16)*destreg * (s16)*srcreg; + if (res > 0xFFFF) { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } + *destreg = (u16)res; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb2 +****************************************************************************/ +void x86emuOp2_lss_R_IMM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rh, rl; + u16 *dstreg; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("LSS\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_SS = fetch_data_word(srcoffset + 2); + break; + case 1: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_SS = fetch_data_word(srcoffset + 2); + break; + case 2: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_SS = fetch_data_word(srcoffset + 2); + break; + case 3: /* register to register */ + /* UNDEFINED! */ + TRACE_AND_STEP(); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb3 +****************************************************************************/ +void x86emuOp2_btr_R(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + int bit,disp; + + START_OF_INSTR(); + DECODE_PRINTF("BTR\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval & ~mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (u16)(srcval & ~mask)); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval & ~mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (u16)(srcval & ~mask)); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval & ~mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (u16)(srcval & ~mask)); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg,*shiftreg; + u32 mask; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + *srcreg &= ~mask; + } else { + u16 *srcreg,*shiftreg; + u16 mask; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + *srcreg &= ~mask; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb4 +****************************************************************************/ +void x86emuOp2_lfs_R_IMM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rh, rl; + u16 *dstreg; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("LFS\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_FS = fetch_data_word(srcoffset + 2); + break; + case 1: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_FS = fetch_data_word(srcoffset + 2); + break; + case 2: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_FS = fetch_data_word(srcoffset + 2); + break; + case 3: /* register to register */ + /* UNDEFINED! */ + TRACE_AND_STEP(); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb5 +****************************************************************************/ +void x86emuOp2_lgs_R_IMM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rh, rl; + u16 *dstreg; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("LGS\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_GS = fetch_data_word(srcoffset + 2); + break; + case 1: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_GS = fetch_data_word(srcoffset + 2); + break; + case 2: + dstreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *dstreg = fetch_data_word(srcoffset); + M.x86.R_GS = fetch_data_word(srcoffset + 2); + break; + case 3: /* register to register */ + /* UNDEFINED! */ + TRACE_AND_STEP(); + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb6 +****************************************************************************/ +void x86emuOp2_movzx_byte_R_RM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOVZX\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_byte(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u8 *srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } else { + u16 *destreg; + u8 *srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb7 +****************************************************************************/ +void x86emuOp2_movzx_word_R_RM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + u32 *destreg; + u32 srcval; + u16 *srcreg; + + START_OF_INSTR(); + DECODE_PRINTF("MOVZX\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 1: + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 2: + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = fetch_data_word(srcoffset); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 3: /* register to register */ + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xba +****************************************************************************/ +void x86emuOp2_btX_I(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + int bit; + + START_OF_INSTR(); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (rh) { + case 3: + DECODE_PRINTF("BT\t"); + break; + case 4: + DECODE_PRINTF("BTS\t"); + break; + case 5: + DECODE_PRINTF("BTR\t"); + break; + case 6: + DECODE_PRINTF("BTC\t"); + break; + default: + DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); + TRACE_REGS(); + printk("%04x:%04x: %02X%02X ILLEGAL EXTENDED X86 OPCODE EXTENSION!\n", + M.x86.R_CS, M.x86.R_IP-3,op2, (mod<<6)|(rh<<3)|rl); + HALT_SYS(); + } + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, mask; + u8 shift; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0x1F; + srcval = fetch_data_long(srcoffset); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + switch (rh) { + case 4: + store_data_long(srcoffset, srcval | mask); + break; + case 5: + store_data_long(srcoffset, srcval & ~mask); + break; + case 6: + store_data_long(srcoffset, srcval ^ mask); + break; + default: + break; + } + } else { + u16 srcval, mask; + u8 shift; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0xF; + srcval = fetch_data_word(srcoffset); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + switch (rh) { + case 4: + store_data_word(srcoffset, srcval | mask); + break; + case 5: + store_data_word(srcoffset, srcval & ~mask); + break; + case 6: + store_data_word(srcoffset, srcval ^ mask); + break; + default: + break; + } + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, mask; + u8 shift; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0x1F; + srcval = fetch_data_long(srcoffset); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + switch (rh) { + case 4: + store_data_long(srcoffset, srcval | mask); + break; + case 5: + store_data_long(srcoffset, srcval & ~mask); + break; + case 6: + store_data_long(srcoffset, srcval ^ mask); + break; + default: + break; + } + } else { + u16 srcval, mask; + u8 shift; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0xF; + srcval = fetch_data_word(srcoffset); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + switch (rh) { + case 4: + store_data_word(srcoffset, srcval | mask); + break; + case 5: + store_data_word(srcoffset, srcval & ~mask); + break; + case 6: + store_data_word(srcoffset, srcval ^ mask); + break; + default: + break; + } + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, mask; + u8 shift; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0x1F; + srcval = fetch_data_long(srcoffset); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + switch (rh) { + case 4: + store_data_long(srcoffset, srcval | mask); + break; + case 5: + store_data_long(srcoffset, srcval & ~mask); + break; + case 6: + store_data_long(srcoffset, srcval ^ mask); + break; + default: + break; + } + } else { + u16 srcval, mask; + u8 shift; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0xF; + srcval = fetch_data_word(srcoffset); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + switch (rh) { + case 4: + store_data_word(srcoffset, srcval | mask); + break; + case 5: + store_data_word(srcoffset, srcval & ~mask); + break; + case 6: + store_data_word(srcoffset, srcval ^ mask); + break; + default: + break; + } + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg; + u32 mask; + u8 shift; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0x1F; + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + switch (rh) { + case 4: + *srcreg |= mask; + break; + case 5: + *srcreg &= ~mask; + break; + case 6: + *srcreg ^= mask; + break; + default: + break; + } + } else { + u16 *srcreg; + u16 mask; + u8 shift; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shift = fetch_byte_imm(); + TRACE_AND_STEP(); + bit = shift & 0xF; + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + switch (rh) { + case 4: + *srcreg |= mask; + break; + case 5: + *srcreg &= ~mask; + break; + case 6: + *srcreg ^= mask; + break; + default: + break; + } + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbb +****************************************************************************/ +void x86emuOp2_btc_R(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + int bit,disp; + + START_OF_INSTR(); + DECODE_PRINTF("BTC\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval ^ mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (u16)(srcval ^ mask)); + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval ^ mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (u16)(srcval ^ mask)); + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval,mask; + u32 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + disp = (s16)*shiftreg >> 5; + srcval = fetch_data_long(srcoffset+disp); + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_long(srcoffset+disp, srcval ^ mask); + } else { + u16 srcval,mask; + u16 *shiftreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + disp = (s16)*shiftreg >> 4; + srcval = fetch_data_word(srcoffset+disp); + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(srcval & mask,F_CF); + store_data_word(srcoffset+disp, (u16)(srcval ^ mask)); + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg,*shiftreg; + u32 mask; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0x1F; + mask = (0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + *srcreg ^= mask; + } else { + u16 *srcreg,*shiftreg; + u16 mask; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + shiftreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + bit = *shiftreg & 0xF; + mask = (u16)(0x1 << bit); + CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); + *srcreg ^= mask; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbc +****************************************************************************/ +void x86emuOp2_bsf(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("BSF\n"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch(mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, *dstreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_long(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 0; *dstreg < 32; (*dstreg)++) + if ((srcval >> *dstreg) & 1) break; + } else { + u16 srcval, *dstreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_word(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 0; *dstreg < 16; (*dstreg)++) + if ((srcval >> *dstreg) & 1) break; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, *dstreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_long(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 0; *dstreg < 32; (*dstreg)++) + if ((srcval >> *dstreg) & 1) break; + } else { + u16 srcval, *dstreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_word(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 0; *dstreg < 16; (*dstreg)++) + if ((srcval >> *dstreg) & 1) break; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, *dstreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_long(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 0; *dstreg < 32; (*dstreg)++) + if ((srcval >> *dstreg) & 1) break; + } else { + u16 srcval, *dstreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_word(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 0; *dstreg < 16; (*dstreg)++) + if ((srcval >> *dstreg) & 1) break; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg, *dstreg; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); + for(*dstreg = 0; *dstreg < 32; (*dstreg)++) + if ((*srcreg >> *dstreg) & 1) break; + } else { + u16 *srcreg, *dstreg; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); + for(*dstreg = 0; *dstreg < 16; (*dstreg)++) + if ((*srcreg >> *dstreg) & 1) break; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbd +****************************************************************************/ +void x86emuOp2_bsr(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("BSF\n"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch(mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, *dstreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_long(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 31; *dstreg > 0; (*dstreg)--) + if ((srcval >> *dstreg) & 1) break; + } else { + u16 srcval, *dstreg; + + srcoffset = decode_rm00_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_word(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 15; *dstreg > 0; (*dstreg)--) + if ((srcval >> *dstreg) & 1) break; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, *dstreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_long(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 31; *dstreg > 0; (*dstreg)--) + if ((srcval >> *dstreg) & 1) break; + } else { + u16 srcval, *dstreg; + + srcoffset = decode_rm01_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_word(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 15; *dstreg > 0; (*dstreg)--) + if ((srcval >> *dstreg) & 1) break; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 srcval, *dstreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_long(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 31; *dstreg > 0; (*dstreg)--) + if ((srcval >> *dstreg) & 1) break; + } else { + u16 srcval, *dstreg; + + srcoffset = decode_rm10_address(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + srcval = fetch_data_word(srcoffset); + CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); + for(*dstreg = 15; *dstreg > 0; (*dstreg)--) + if ((srcval >> *dstreg) & 1) break; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *srcreg, *dstreg; + + srcreg = DECODE_RM_LONG_REGISTER(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_LONG_REGISTER(rh); + TRACE_AND_STEP(); + CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); + for(*dstreg = 31; *dstreg > 0; (*dstreg)--) + if ((*srcreg >> *dstreg) & 1) break; + } else { + u16 *srcreg, *dstreg; + + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF(","); + dstreg = DECODE_RM_WORD_REGISTER(rh); + TRACE_AND_STEP(); + CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); + for(*dstreg = 15; *dstreg > 0; (*dstreg)--) + if ((*srcreg >> *dstreg) & 1) break; + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbe +****************************************************************************/ +void x86emuOp2_movsx_byte_R_RM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + + START_OF_INSTR(); + DECODE_PRINTF("MOVSX\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = (s32)((s8)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = (s16)((s8)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 1: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = (s32)((s8)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = (s16)((s8)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 2: + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u32 srcval; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = (s32)((s8)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } else { + u16 *destreg; + u16 srcval; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = (s16)((s8)fetch_data_byte(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + } + break; + case 3: /* register to register */ + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + u32 *destreg; + u8 *srcreg; + + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = (s32)((s8)*srcreg); + } else { + u16 *destreg; + u8 *srcreg; + + destreg = DECODE_RM_WORD_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_BYTE_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = (s16)((s8)*srcreg); + } + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbf +****************************************************************************/ +void x86emuOp2_movsx_word_R_RM(u8 X86EMU_UNUSED(op2)) +{ + int mod, rl, rh; + uint srcoffset; + u32 *destreg; + u32 srcval; + u16 *srcreg; + + START_OF_INSTR(); + DECODE_PRINTF("MOVSX\t"); + FETCH_DECODE_MODRM(mod, rh, rl); + switch (mod) { + case 0: + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm00_address(rl); + srcval = (s32)((s16)fetch_data_word(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 1: + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm01_address(rl); + srcval = (s32)((s16)fetch_data_word(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 2: + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcoffset = decode_rm10_address(rl); + srcval = (s32)((s16)fetch_data_word(srcoffset)); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = srcval; + break; + case 3: /* register to register */ + destreg = DECODE_RM_LONG_REGISTER(rh); + DECODE_PRINTF(","); + srcreg = DECODE_RM_WORD_REGISTER(rl); + DECODE_PRINTF("\n"); + TRACE_AND_STEP(); + *destreg = (s32)((s16)*srcreg); + break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +} + +/*************************************************************************** + * Double byte operation code table: + **************************************************************************/ +void (*x86emu_optab2[256])(u8) = +{ +/* 0x00 */ x86emuOp2_illegal_op, /* Group F (ring 0 PM) */ +/* 0x01 */ x86emuOp2_illegal_op, /* Group G (ring 0 PM) */ +/* 0x02 */ x86emuOp2_illegal_op, /* lar (ring 0 PM) */ +/* 0x03 */ x86emuOp2_illegal_op, /* lsl (ring 0 PM) */ +/* 0x04 */ x86emuOp2_illegal_op, +/* 0x05 */ x86emuOp2_illegal_op, /* loadall (undocumented) */ +/* 0x06 */ x86emuOp2_illegal_op, /* clts (ring 0 PM) */ +/* 0x07 */ x86emuOp2_illegal_op, /* loadall (undocumented) */ +/* 0x08 */ x86emuOp2_illegal_op, /* invd (ring 0 PM) */ +/* 0x09 */ x86emuOp2_illegal_op, /* wbinvd (ring 0 PM) */ +/* 0x0a */ x86emuOp2_illegal_op, +/* 0x0b */ x86emuOp2_illegal_op, +/* 0x0c */ x86emuOp2_illegal_op, +/* 0x0d */ x86emuOp2_illegal_op, +/* 0x0e */ x86emuOp2_illegal_op, +/* 0x0f */ x86emuOp2_illegal_op, + +/* 0x10 */ x86emuOp2_illegal_op, +/* 0x11 */ x86emuOp2_illegal_op, +/* 0x12 */ x86emuOp2_illegal_op, +/* 0x13 */ x86emuOp2_illegal_op, +/* 0x14 */ x86emuOp2_illegal_op, +/* 0x15 */ x86emuOp2_illegal_op, +/* 0x16 */ x86emuOp2_illegal_op, +/* 0x17 */ x86emuOp2_illegal_op, +/* 0x18 */ x86emuOp2_illegal_op, +/* 0x19 */ x86emuOp2_illegal_op, +/* 0x1a */ x86emuOp2_illegal_op, +/* 0x1b */ x86emuOp2_illegal_op, +/* 0x1c */ x86emuOp2_illegal_op, +/* 0x1d */ x86emuOp2_illegal_op, +/* 0x1e */ x86emuOp2_illegal_op, +/* 0x1f */ x86emuOp2_illegal_op, + +/* 0x20 */ x86emuOp2_illegal_op, /* mov reg32,creg (ring 0 PM) */ +/* 0x21 */ x86emuOp2_illegal_op, /* mov reg32,dreg (ring 0 PM) */ +/* 0x22 */ x86emuOp2_illegal_op, /* mov creg,reg32 (ring 0 PM) */ +/* 0x23 */ x86emuOp2_illegal_op, /* mov dreg,reg32 (ring 0 PM) */ +/* 0x24 */ x86emuOp2_illegal_op, /* mov reg32,treg (ring 0 PM) */ +/* 0x25 */ x86emuOp2_illegal_op, +/* 0x26 */ x86emuOp2_illegal_op, /* mov treg,reg32 (ring 0 PM) */ +/* 0x27 */ x86emuOp2_illegal_op, +/* 0x28 */ x86emuOp2_illegal_op, +/* 0x29 */ x86emuOp2_illegal_op, +/* 0x2a */ x86emuOp2_illegal_op, +/* 0x2b */ x86emuOp2_illegal_op, +/* 0x2c */ x86emuOp2_illegal_op, +/* 0x2d */ x86emuOp2_illegal_op, +/* 0x2e */ x86emuOp2_illegal_op, +/* 0x2f */ x86emuOp2_illegal_op, + +/* 0x30 */ x86emuOp2_illegal_op, +/* 0x31 */ x86emuOp2_illegal_op, +/* 0x32 */ x86emuOp2_illegal_op, +/* 0x33 */ x86emuOp2_illegal_op, +/* 0x34 */ x86emuOp2_illegal_op, +/* 0x35 */ x86emuOp2_illegal_op, +/* 0x36 */ x86emuOp2_illegal_op, +/* 0x37 */ x86emuOp2_illegal_op, +/* 0x38 */ x86emuOp2_illegal_op, +/* 0x39 */ x86emuOp2_illegal_op, +/* 0x3a */ x86emuOp2_illegal_op, +/* 0x3b */ x86emuOp2_illegal_op, +/* 0x3c */ x86emuOp2_illegal_op, +/* 0x3d */ x86emuOp2_illegal_op, +/* 0x3e */ x86emuOp2_illegal_op, +/* 0x3f */ x86emuOp2_illegal_op, + +/* 0x40 */ x86emuOp2_illegal_op, +/* 0x41 */ x86emuOp2_illegal_op, +/* 0x42 */ x86emuOp2_illegal_op, +/* 0x43 */ x86emuOp2_illegal_op, +/* 0x44 */ x86emuOp2_illegal_op, +/* 0x45 */ x86emuOp2_illegal_op, +/* 0x46 */ x86emuOp2_illegal_op, +/* 0x47 */ x86emuOp2_illegal_op, +/* 0x48 */ x86emuOp2_illegal_op, +/* 0x49 */ x86emuOp2_illegal_op, +/* 0x4a */ x86emuOp2_illegal_op, +/* 0x4b */ x86emuOp2_illegal_op, +/* 0x4c */ x86emuOp2_illegal_op, +/* 0x4d */ x86emuOp2_illegal_op, +/* 0x4e */ x86emuOp2_illegal_op, +/* 0x4f */ x86emuOp2_illegal_op, + +/* 0x50 */ x86emuOp2_illegal_op, +/* 0x51 */ x86emuOp2_illegal_op, +/* 0x52 */ x86emuOp2_illegal_op, +/* 0x53 */ x86emuOp2_illegal_op, +/* 0x54 */ x86emuOp2_illegal_op, +/* 0x55 */ x86emuOp2_illegal_op, +/* 0x56 */ x86emuOp2_illegal_op, +/* 0x57 */ x86emuOp2_illegal_op, +/* 0x58 */ x86emuOp2_illegal_op, +/* 0x59 */ x86emuOp2_illegal_op, +/* 0x5a */ x86emuOp2_illegal_op, +/* 0x5b */ x86emuOp2_illegal_op, +/* 0x5c */ x86emuOp2_illegal_op, +/* 0x5d */ x86emuOp2_illegal_op, +/* 0x5e */ x86emuOp2_illegal_op, +/* 0x5f */ x86emuOp2_illegal_op, + +/* 0x60 */ x86emuOp2_illegal_op, +/* 0x61 */ x86emuOp2_illegal_op, +/* 0x62 */ x86emuOp2_illegal_op, +/* 0x63 */ x86emuOp2_illegal_op, +/* 0x64 */ x86emuOp2_illegal_op, +/* 0x65 */ x86emuOp2_illegal_op, +/* 0x66 */ x86emuOp2_illegal_op, +/* 0x67 */ x86emuOp2_illegal_op, +/* 0x68 */ x86emuOp2_illegal_op, +/* 0x69 */ x86emuOp2_illegal_op, +/* 0x6a */ x86emuOp2_illegal_op, +/* 0x6b */ x86emuOp2_illegal_op, +/* 0x6c */ x86emuOp2_illegal_op, +/* 0x6d */ x86emuOp2_illegal_op, +/* 0x6e */ x86emuOp2_illegal_op, +/* 0x6f */ x86emuOp2_illegal_op, + +/* 0x70 */ x86emuOp2_illegal_op, +/* 0x71 */ x86emuOp2_illegal_op, +/* 0x72 */ x86emuOp2_illegal_op, +/* 0x73 */ x86emuOp2_illegal_op, +/* 0x74 */ x86emuOp2_illegal_op, +/* 0x75 */ x86emuOp2_illegal_op, +/* 0x76 */ x86emuOp2_illegal_op, +/* 0x77 */ x86emuOp2_illegal_op, +/* 0x78 */ x86emuOp2_illegal_op, +/* 0x79 */ x86emuOp2_illegal_op, +/* 0x7a */ x86emuOp2_illegal_op, +/* 0x7b */ x86emuOp2_illegal_op, +/* 0x7c */ x86emuOp2_illegal_op, +/* 0x7d */ x86emuOp2_illegal_op, +/* 0x7e */ x86emuOp2_illegal_op, +/* 0x7f */ x86emuOp2_illegal_op, + +/* 0x80 */ x86emuOp2_long_jump, +/* 0x81 */ x86emuOp2_long_jump, +/* 0x82 */ x86emuOp2_long_jump, +/* 0x83 */ x86emuOp2_long_jump, +/* 0x84 */ x86emuOp2_long_jump, +/* 0x85 */ x86emuOp2_long_jump, +/* 0x86 */ x86emuOp2_long_jump, +/* 0x87 */ x86emuOp2_long_jump, +/* 0x88 */ x86emuOp2_long_jump, +/* 0x89 */ x86emuOp2_long_jump, +/* 0x8a */ x86emuOp2_long_jump, +/* 0x8b */ x86emuOp2_long_jump, +/* 0x8c */ x86emuOp2_long_jump, +/* 0x8d */ x86emuOp2_long_jump, +/* 0x8e */ x86emuOp2_long_jump, +/* 0x8f */ x86emuOp2_long_jump, + +/* 0x90 */ x86emuOp2_set_byte, +/* 0x91 */ x86emuOp2_set_byte, +/* 0x92 */ x86emuOp2_set_byte, +/* 0x93 */ x86emuOp2_set_byte, +/* 0x94 */ x86emuOp2_set_byte, +/* 0x95 */ x86emuOp2_set_byte, +/* 0x96 */ x86emuOp2_set_byte, +/* 0x97 */ x86emuOp2_set_byte, +/* 0x98 */ x86emuOp2_set_byte, +/* 0x99 */ x86emuOp2_set_byte, +/* 0x9a */ x86emuOp2_set_byte, +/* 0x9b */ x86emuOp2_set_byte, +/* 0x9c */ x86emuOp2_set_byte, +/* 0x9d */ x86emuOp2_set_byte, +/* 0x9e */ x86emuOp2_set_byte, +/* 0x9f */ x86emuOp2_set_byte, + +/* 0xa0 */ x86emuOp2_push_FS, +/* 0xa1 */ x86emuOp2_pop_FS, +/* 0xa2 */ x86emuOp2_illegal_op, +/* 0xa3 */ x86emuOp2_bt_R, +/* 0xa4 */ x86emuOp2_shld_IMM, +/* 0xa5 */ x86emuOp2_shld_CL, +/* 0xa6 */ x86emuOp2_illegal_op, +/* 0xa7 */ x86emuOp2_illegal_op, +/* 0xa8 */ x86emuOp2_push_GS, +/* 0xa9 */ x86emuOp2_pop_GS, +/* 0xaa */ x86emuOp2_illegal_op, +/* 0xab */ x86emuOp2_bt_R, +/* 0xac */ x86emuOp2_shrd_IMM, +/* 0xad */ x86emuOp2_shrd_CL, +/* 0xae */ x86emuOp2_illegal_op, +/* 0xaf */ x86emuOp2_imul_R_RM, + +/* 0xb0 */ x86emuOp2_illegal_op, /* TODO: cmpxchg */ +/* 0xb1 */ x86emuOp2_illegal_op, /* TODO: cmpxchg */ +/* 0xb2 */ x86emuOp2_lss_R_IMM, +/* 0xb3 */ x86emuOp2_btr_R, +/* 0xb4 */ x86emuOp2_lfs_R_IMM, +/* 0xb5 */ x86emuOp2_lgs_R_IMM, +/* 0xb6 */ x86emuOp2_movzx_byte_R_RM, +/* 0xb7 */ x86emuOp2_movzx_word_R_RM, +/* 0xb8 */ x86emuOp2_illegal_op, +/* 0xb9 */ x86emuOp2_illegal_op, +/* 0xba */ x86emuOp2_btX_I, +/* 0xbb */ x86emuOp2_btc_R, +/* 0xbc */ x86emuOp2_bsf, +/* 0xbd */ x86emuOp2_bsr, +/* 0xbe */ x86emuOp2_movsx_byte_R_RM, +/* 0xbf */ x86emuOp2_movsx_word_R_RM, + +/* 0xc0 */ x86emuOp2_illegal_op, /* TODO: xadd */ +/* 0xc1 */ x86emuOp2_illegal_op, /* TODO: xadd */ +/* 0xc2 */ x86emuOp2_illegal_op, +/* 0xc3 */ x86emuOp2_illegal_op, +/* 0xc4 */ x86emuOp2_illegal_op, +/* 0xc5 */ x86emuOp2_illegal_op, +/* 0xc6 */ x86emuOp2_illegal_op, +/* 0xc7 */ x86emuOp2_illegal_op, +/* 0xc8 */ x86emuOp2_illegal_op, /* TODO: bswap */ +/* 0xc9 */ x86emuOp2_illegal_op, /* TODO: bswap */ +/* 0xca */ x86emuOp2_illegal_op, /* TODO: bswap */ +/* 0xcb */ x86emuOp2_illegal_op, /* TODO: bswap */ +/* 0xcc */ x86emuOp2_illegal_op, /* TODO: bswap */ +/* 0xcd */ x86emuOp2_illegal_op, /* TODO: bswap */ +/* 0xce */ x86emuOp2_illegal_op, /* TODO: bswap */ +/* 0xcf */ x86emuOp2_illegal_op, /* TODO: bswap */ + +/* 0xd0 */ x86emuOp2_illegal_op, +/* 0xd1 */ x86emuOp2_illegal_op, +/* 0xd2 */ x86emuOp2_illegal_op, +/* 0xd3 */ x86emuOp2_illegal_op, +/* 0xd4 */ x86emuOp2_illegal_op, +/* 0xd5 */ x86emuOp2_illegal_op, +/* 0xd6 */ x86emuOp2_illegal_op, +/* 0xd7 */ x86emuOp2_illegal_op, +/* 0xd8 */ x86emuOp2_illegal_op, +/* 0xd9 */ x86emuOp2_illegal_op, +/* 0xda */ x86emuOp2_illegal_op, +/* 0xdb */ x86emuOp2_illegal_op, +/* 0xdc */ x86emuOp2_illegal_op, +/* 0xdd */ x86emuOp2_illegal_op, +/* 0xde */ x86emuOp2_illegal_op, +/* 0xdf */ x86emuOp2_illegal_op, + +/* 0xe0 */ x86emuOp2_illegal_op, +/* 0xe1 */ x86emuOp2_illegal_op, +/* 0xe2 */ x86emuOp2_illegal_op, +/* 0xe3 */ x86emuOp2_illegal_op, +/* 0xe4 */ x86emuOp2_illegal_op, +/* 0xe5 */ x86emuOp2_illegal_op, +/* 0xe6 */ x86emuOp2_illegal_op, +/* 0xe7 */ x86emuOp2_illegal_op, +/* 0xe8 */ x86emuOp2_illegal_op, +/* 0xe9 */ x86emuOp2_illegal_op, +/* 0xea */ x86emuOp2_illegal_op, +/* 0xeb */ x86emuOp2_illegal_op, +/* 0xec */ x86emuOp2_illegal_op, +/* 0xed */ x86emuOp2_illegal_op, +/* 0xee */ x86emuOp2_illegal_op, +/* 0xef */ x86emuOp2_illegal_op, + +/* 0xf0 */ x86emuOp2_illegal_op, +/* 0xf1 */ x86emuOp2_illegal_op, +/* 0xf2 */ x86emuOp2_illegal_op, +/* 0xf3 */ x86emuOp2_illegal_op, +/* 0xf4 */ x86emuOp2_illegal_op, +/* 0xf5 */ x86emuOp2_illegal_op, +/* 0xf6 */ x86emuOp2_illegal_op, +/* 0xf7 */ x86emuOp2_illegal_op, +/* 0xf8 */ x86emuOp2_illegal_op, +/* 0xf9 */ x86emuOp2_illegal_op, +/* 0xfa */ x86emuOp2_illegal_op, +/* 0xfb */ x86emuOp2_illegal_op, +/* 0xfc */ x86emuOp2_illegal_op, +/* 0xfd */ x86emuOp2_illegal_op, +/* 0xfe */ x86emuOp2_illegal_op, +/* 0xff */ x86emuOp2_illegal_op, +}; diff --git a/cfe/cfe/x86emu/prim_ops.c b/cfe/cfe/x86emu/prim_ops.c new file mode 100644 index 0000000..dca16cd --- /dev/null +++ b/cfe/cfe/x86emu/prim_ops.c @@ -0,0 +1,2915 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: This file contains the code to implement the primitive +* machine operations used by the emulation code in ops.c +* +* Carry Chain Calculation +* +* This represents a somewhat expensive calculation which is +* apparently required to emulate the setting of the OF and AF flag. +* The latter is not so important, but the former is. The overflow +* flag is the XOR of the top two bits of the carry chain for an +* addition (similar for subtraction). Since we do not want to +* simulate the addition in a bitwise manner, we try to calculate the +* carry chain given the two operands and the result. +* +* So, given the following table, which represents the addition of two +* bits, we can derive a formula for the carry chain. +* +* a b cin r cout +* 0 0 0 0 0 +* 0 0 1 1 0 +* 0 1 0 1 0 +* 0 1 1 0 1 +* 1 0 0 1 0 +* 1 0 1 0 1 +* 1 1 0 0 1 +* 1 1 1 1 1 +* +* Construction of table for cout: +* +* ab +* r \ 00 01 11 10 +* |------------------ +* 0 | 0 1 1 1 +* 1 | 0 0 1 0 +* +* By inspection, one gets: cc = ab + r'(a + b) +* +* That represents alot of operations, but NO CHOICE.... +* +* Borrow Chain Calculation. +* +* The following table represents the subtraction of two bits, from +* which we can derive a formula for the borrow chain. +* +* a b bin r bout +* 0 0 0 0 0 +* 0 0 1 1 1 +* 0 1 0 1 1 +* 0 1 1 0 1 +* 1 0 0 1 0 +* 1 0 1 0 0 +* 1 1 0 0 0 +* 1 1 1 1 1 +* +* Construction of table for cout: +* +* ab +* r \ 00 01 11 10 +* |------------------ +* 0 | 0 1 0 0 +* 1 | 1 1 1 0 +* +* By inspection, one gets: bc = a'b + r(a' + b) +* +****************************************************************************/ + +#define PRIM_OPS_NO_REDEFINE_ASM +#include "x86emu/x86emui.h" + +/*------------------------- Global Variables ------------------------------*/ + +#ifndef __HAVE_INLINE_ASSEMBLER__ + +static u32 x86emu_parity_tab[8] = +{ + 0x96696996, + 0x69969669, + 0x69969669, + 0x96696996, + 0x69969669, + 0x96696996, + 0x96696996, + 0x69969669, +}; + +#endif + +#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0) +#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1) + +/*----------------------------- Implementation ----------------------------*/ + +#ifndef __HAVE_INLINE_ASSEMBLER__ + +/**************************************************************************** +REMARKS: +Implements the AAA instruction and side effects. +****************************************************************************/ +u16 aaa_word(u16 d) +{ + u16 res; + if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { + d += 0x6; + d += 0x100; + SET_FLAG(F_AF); + SET_FLAG(F_CF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + } + res = (u16)(d & 0xFF0F); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAA instruction and side effects. +****************************************************************************/ +u16 aas_word(u16 d) +{ + u16 res; + if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { + d -= 0x6; + d -= 0x100; + SET_FLAG(F_AF); + SET_FLAG(F_CF); + } else { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + } + res = (u16)(d & 0xFF0F); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAD instruction and side effects. +****************************************************************************/ +u16 aad_word(u16 d) +{ + u16 l; + u8 hb, lb; + + hb = (u8)((d >> 8) & 0xff); + lb = (u8)((d & 0xff)); + l = (u16)((lb + 10 * hb) & 0xFF); + + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(l & 0x80, F_SF); + CONDITIONAL_SET_FLAG(l == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); + return l; +} + +/**************************************************************************** +REMARKS: +Implements the AAM instruction and side effects. +****************************************************************************/ +u16 aam_word(u8 d) +{ + u16 h, l; + + h = (u16)(d / 10); + l = (u16)(d % 10); + l |= (u16)(h << 8); + + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(l & 0x80, F_SF); + CONDITIONAL_SET_FLAG(l == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); + return l; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u8 adc_byte(u8 d, u8 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 cc; + + if (ACCESS_FLAG(F_CF)) + res = 1 + d + s; + else + res = d + s; + + CONDITIONAL_SET_FLAG(res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u16 adc_word(u16 d, u16 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 cc; + + if (ACCESS_FLAG(F_CF)) + res = 1 + d + s; + else + res = d + s; + + CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u32 adc_long(u32 d, u32 s) +{ + register u32 lo; /* all operands in native machine order */ + register u32 hi; + register u32 res; + register u32 cc; + + if (ACCESS_FLAG(F_CF)) { + lo = 1 + (d & 0xFFFF) + (s & 0xFFFF); + res = 1 + d + s; + } + else { + lo = (d & 0xFFFF) + (s & 0xFFFF); + res = d + s; + } + hi = (lo >> 16) + (d >> 16) + (s >> 16); + + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u8 add_byte(u8 d, u8 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 cc; + + res = d + s; + CONDITIONAL_SET_FLAG(res & 0x100, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u16 add_word(u16 d, u16 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 cc; + + res = d + s; + CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u32 add_long(u32 d, u32 s) +{ + register u32 lo; /* all operands in native machine order */ + register u32 hi; + register u32 res; + register u32 cc; + + lo = (d & 0xFFFF) + (s & 0xFFFF); + res = d + s; + hi = (lo >> 16) + (d >> 16) + (s >> 16); + + CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + + return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u8 and_byte(u8 d, u8 s) +{ + register u8 res; /* all operands in native machine order */ + + res = d & s; + + /* set the flags */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u16 and_word(u16 d, u16 s) +{ + register u16 res; /* all operands in native machine order */ + + res = d & s; + + /* set the flags */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u32 and_long(u32 d, u32 s) +{ + register u32 res; /* all operands in native machine order */ + + res = d & s; + + /* set the flags */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u8 cmp_byte(u8 d, u8 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - s; + CLEAR_FLAG(F_CF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u16 cmp_word(u16 d, u16 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u32 cmp_long(u32 d, u32 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return d; +} + +/**************************************************************************** +REMARKS: +Implements the DAA instruction and side effects. +****************************************************************************/ +u8 daa_byte(u8 d) +{ + u32 res = d; + if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { + res += 6; + SET_FLAG(F_AF); + } + if (res > 0x9F || ACCESS_FLAG(F_CF)) { + res += 0x60; + SET_FLAG(F_CF); + } + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the DAS instruction and side effects. +****************************************************************************/ +u8 das_byte(u8 d) +{ + if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { + d -= 6; + SET_FLAG(F_AF); + } + if (d > 0x9F || ACCESS_FLAG(F_CF)) { + d -= 0x60; + SET_FLAG(F_CF); + } + CONDITIONAL_SET_FLAG(d & 0x80, F_SF); + CONDITIONAL_SET_FLAG(d == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF); + return d; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u8 dec_byte(u8 d) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - 1; + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + /* based on sub_byte, uses s==1. */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u16 dec_word(u16 d) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - 1; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + /* based on the sub_byte routine, with s==1 */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u32 dec_long(u32 d) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - 1; + + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | 1)) | (~d & 1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u8 inc_byte(u8 d) +{ + register u32 res; /* all operands in native machine order */ + register u32 cc; + + res = d + 1; + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = ((1 & d) | (~res)) & (1 | d); + CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u16 inc_word(u16 d) +{ + register u32 res; /* all operands in native machine order */ + register u32 cc; + + res = d + 1; + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (1 & d) | ((~res) & (1 | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u32 inc_long(u32 d) +{ + register u32 res; /* all operands in native machine order */ + register u32 cc; + + res = d + 1; + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the carry chain SEE NOTE AT TOP. */ + cc = (1 & d) | ((~res) & (1 | d)); + CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); + CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 or_byte(u8 d, u8 s) +{ + register u8 res; /* all operands in native machine order */ + + res = d | s; + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 or_word(u16 d, u16 s) +{ + register u16 res; /* all operands in native machine order */ + + res = d | s; + /* set the carry flag to be bit 8 */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 or_long(u32 d, u32 s) +{ + register u32 res; /* all operands in native machine order */ + + res = d | s; + + /* set the carry flag to be bit 8 */ + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 neg_byte(u8 s) +{ + register u8 res; + register u8 bc; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (u8)-s; + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + /* calculate the borrow chain --- modified such that d=0. + substitutiing d=0 into bc= res&(~d|s)|(~d&s); + (the one used for sub) and simplifying, since ~d=0xff..., + ~d|s == 0xffff..., and res&0xfff... == res. Similarly + ~d&s == s. So the simplified result is: */ + bc = res | s; + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 neg_word(u16 s) +{ + register u16 res; + register u16 bc; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (u16)-s; + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain --- modified such that d=0. + substitutiing d=0 into bc= res&(~d|s)|(~d&s); + (the one used for sub) and simplifying, since ~d=0xff..., + ~d|s == 0xffff..., and res&0xfff... == res. Similarly + ~d&s == s. So the simplified result is: */ + bc = res | s; + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 neg_long(u32 s) +{ + register u32 res; + register u32 bc; + + CONDITIONAL_SET_FLAG(s != 0, F_CF); + res = (u32)-s; + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain --- modified such that d=0. + substitutiing d=0 into bc= res&(~d|s)|(~d&s); + (the one used for sub) and simplifying, since ~d=0xff..., + ~d|s == 0xffff..., and res&0xfff... == res. Similarly + ~d&s == s. So the simplified result is: */ + bc = res | s; + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u8 not_byte(u8 s) +{ + return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u16 not_word(u16 s) +{ + return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u32 not_long(u32 s) +{ + return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u8 rcl_byte(u8 d, u8 s) +{ + register unsigned int res, cnt, mask, cf; + + /* s is the rotate distance. It varies from 0 - 8. */ + /* have + + CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + + want to rotate through the carry by "s" bits. We could + loop, but that's inefficient. So the width is 9, + and we split into three parts: + + The new carry flag (was B_n) + the stuff in B_n-1 .. B_0 + the stuff in B_7 .. B_n+1 + + The new rotate is done mod 9, and given this, + for a rotation of n bits (mod 9) the new carry flag is + then located n bits from the MSB. The low part is + then shifted up cnt bits, and the high part is or'd + in. Using CAPS for new values, and lowercase for the + original values, this can be expressed as: + + IF n > 0 + 1) CF <- b_(8-n) + 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 + 3) B_(n-1) <- cf + 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) + */ + res = d; + if ((cnt = s % 9) != 0) { + /* extract the new CARRY FLAG. */ + /* CF <- b_(8-n) */ + cf = (d >> (8 - cnt)) & 0x1; + + /* get the low stuff which rotated + into the range B_7 .. B_cnt */ + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */ + /* note that the right hand side done by the mask */ + res = (d << cnt) & 0xff; + + /* now the high stuff which rotated around + into the positions B_cnt-2 .. B_0 */ + /* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */ + /* shift it downward, 7-(n-2) = 9-n positions. + and mask off the result before or'ing in. + */ + mask = (1 << (cnt - 1)) - 1; + res |= (d >> (9 - cnt)) & mask; + + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + /* B_(n-1) <- cf */ + res |= 1 << (cnt - 1); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + /* parenthesized this expression since it appears to + be causing OF to be misset */ + CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)), + F_OF); + + } + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u16 rcl_word(u16 d, u8 s) +{ + register unsigned int res, cnt, mask, cf; + + res = d; + if ((cnt = s % 17) != 0) { + cf = (d >> (16 - cnt)) & 0x1; + res = (d << cnt) & 0xffff; + mask = (1 << (cnt - 1)) - 1; + res |= (d >> (17 - cnt)) & mask; + if (ACCESS_FLAG(F_CF)) { + res |= 1 << (cnt - 1); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)), + F_OF); + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u32 rcl_long(u32 d, u8 s) +{ + register u32 res, cnt, mask, cf; + + res = d; + if ((cnt = s % 33) != 0) { + cf = (d >> (32 - cnt)) & 0x1; + res = (d << cnt) & 0xffffffff; + mask = (1 << (cnt - 1)) - 1; + res |= (d >> (33 - cnt)) & mask; + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + res |= 1 << (cnt - 1); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)), + F_OF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u8 rcr_byte(u8 d, u8 s) +{ + u32 res, cnt; + u32 mask, cf, ocf = 0; + + /* rotate right through carry */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + + have + + CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + + The new rotate is done mod 9, and given this, + for a rotation of n bits (mod 9) the new carry flag is + then located n bits from the LSB. The low part is + then shifted up cnt bits, and the high part is or'd + in. Using CAPS for new values, and lowercase for the + original values, this can be expressed as: + + IF n > 0 + 1) CF <- b_(n-1) + 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) + 3) B_(8-n) <- cf + 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) + */ + res = d; + if ((cnt = s % 9) != 0) { + /* extract the new CARRY FLAG. */ + /* CF <- b_(n-1) */ + if (cnt == 1) { + cf = d & 0x1; + /* note hackery here. Access_flag(..) evaluates to either + 0 if flag not set + non-zero if flag is set. + doing access_flag(..) != 0 casts that into either + 0..1 in any representation of the flags register + (i.e. packed bit array or unpacked.) + */ + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + + /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */ + /* note that the right hand side done by the mask + This is effectively done by shifting the + object to the right. The result must be masked, + in case the object came in and was treated + as a negative number. Needed??? */ + + mask = (1 << (8 - cnt)) - 1; + res = (d >> cnt) & mask; + + /* now the high stuff which rotated around + into the positions B_cnt-2 .. B_0 */ + /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */ + /* shift it downward, 7-(n-2) = 9-n positions. + and mask off the result before or'ing in. + */ + res |= (d << (9 - cnt)); + + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + /* B_(8-n) <- cf */ + res |= 1 << (8 - cnt); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + /* parenthesized... */ + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)), + F_OF); + } + } + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u16 rcr_word(u16 d, u8 s) +{ + u32 res, cnt; + u32 mask, cf, ocf = 0; + + /* rotate right through carry */ + res = d; + if ((cnt = s % 17) != 0) { + if (cnt == 1) { + cf = d & 0x1; + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + mask = (1 << (16 - cnt)) - 1; + res = (d >> cnt) & mask; + res |= (d << (17 - cnt)); + if (ACCESS_FLAG(F_CF)) { + res |= 1 << (16 - cnt); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)), + F_OF); + } + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u32 rcr_long(u32 d, u8 s) +{ + u32 res, cnt; + u32 mask, cf, ocf = 0; + + /* rotate right through carry */ + res = d; + if ((cnt = s % 33) != 0) { + if (cnt == 1) { + cf = d & 0x1; + ocf = ACCESS_FLAG(F_CF) != 0; + } else + cf = (d >> (cnt - 1)) & 0x1; + mask = (1 << (32 - cnt)) - 1; + res = (d >> cnt) & mask; + if (cnt != 1) + res |= (d << (33 - cnt)); + if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ + res |= 1 << (32 - cnt); + } + CONDITIONAL_SET_FLAG(cf, F_CF); + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)), + F_OF); + } + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u8 rol_byte(u8 d, u8 s) +{ + register unsigned int res, cnt, mask; + + /* rotate left */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + + have + + CF B_7 ... B_0 + + The new rotate is done mod 8. + Much simpler than the "rcl" or "rcr" operations. + + IF n > 0 + 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) + 2) B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) + */ + res = d; + if ((cnt = s % 8) != 0) { + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */ + res = (d << cnt); + + /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */ + mask = (1 << cnt) - 1; + res |= (d >> (8 - cnt)) & mask; + + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + /* OVERFLOW is set *IFF* s==1, then it is the + xor of CF and the most significant bit. Blecck. */ + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 6) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u16 rol_word(u16 d, u8 s) +{ + register unsigned int res, cnt, mask; + + res = d; + if ((cnt = s % 16) != 0) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (16 - cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 14) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u32 rol_long(u32 d, u8 s) +{ + register u32 res, cnt, mask; + + res = d; + if ((cnt = s % 32) != 0) { + res = (d << cnt); + mask = (1 << cnt) - 1; + res |= (d >> (32 - cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && + XOR2((res & 0x1) + ((res >> 30) & 0x2)), + F_OF); + } if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x1, F_CF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u8 ror_byte(u8 d, u8 s) +{ + register unsigned int res, cnt, mask; + + /* rotate right */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + + have + + B_7 ... B_0 + + The rotate is done mod 8. + + IF n > 0 + 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) + 2) B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) + */ + res = d; + if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */ + /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */ + res = (d << (8 - cnt)); + + /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */ + mask = (1 << (8 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x80, F_CF); + /* OVERFLOW is set *IFF* s==1, then it is the + xor of the two most significant bits. Blecck. */ + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x80, F_CF); + } + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u16 ror_word(u16 d, u8 s) +{ + register unsigned int res, cnt, mask; + + res = d; + if ((cnt = s % 16) != 0) { + res = (d << (16 - cnt)); + mask = (1 << (16 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u32 ror_long(u32 d, u8 s) +{ + register u32 res, cnt, mask; + + res = d; + if ((cnt = s % 32) != 0) { + res = (d << (32 - cnt)); + mask = (1 << (32 - cnt)) - 1; + res |= (d >> (cnt)) & mask; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF); + } else if (s != 0) { + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u8 shl_byte(u8 d, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 8) { + cnt = s % 8; + + /* last bit shifted out goes into carry flag */ + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (8 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = (u8) d; + } + + if (cnt == 1) { + /* Needs simplification. */ + CONDITIONAL_SET_FLAG( + (((res & 0x80) == 0x80) ^ + (ACCESS_FLAG(F_CF) != 0)), + /* was (M.x86.R_FLG&F_CF)==F_CF)), */ + F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u16 shl_word(u16 d, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = (u16) d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG( + (((res & 0x8000) == 0x8000) ^ + (ACCESS_FLAG(F_CF) != 0)), + F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u32 shl_long(u32 d, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + res = d << cnt; + cf = d & (1 << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u8 shr_byte(u8 d, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 8) { + cnt = s % 8; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = (u8) d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d >> (s-1)) & 0x1, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u16 shr_word(u16 d, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u32 shr_long(u32 d, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = d >> cnt; + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u8 sar_byte(u8 d, u8 s) +{ + unsigned int cnt, res, cf, mask, sf; + + res = d; + sf = d & 0x80; + cnt = s % 8; + if (cnt > 0 && cnt < 8) { + mask = (1 << (8 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + } else if (cnt >= 8) { + if (sf) { + res = 0xff; + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + res = 0; + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + } + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u16 sar_word(u16 d, u8 s) +{ + unsigned int cnt, res, cf, mask, sf; + + sf = d & 0x8000; + cnt = s % 16; + res = d; + if (cnt > 0 && cnt < 16) { + mask = (1 << (16 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else if (cnt >= 16) { + if (sf) { + res = 0xffff; + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + res = 0; + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u32 sar_long(u32 d, u8 s) +{ + u32 cnt, res, cf, mask, sf; + + sf = d & 0x80000000; + cnt = s % 32; + res = d; + if (cnt > 0 && cnt < 32) { + mask = (1 << (32 - cnt)) - 1; + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, F_CF); + if (sf) { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else if (cnt >= 32) { + if (sf) { + res = 0xffffffff; + SET_FLAG(F_CF); + CLEAR_FLAG(F_ZF); + SET_FLAG(F_SF); + SET_FLAG(F_PF); + } else { + res = 0; + CLEAR_FLAG(F_CF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHLD instruction and side effects. +****************************************************************************/ +u16 shld_word (u16 d, u16 fill, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + res = (d << cnt) | (fill >> (16-cnt)); + cf = d & (1 << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHLD instruction and side effects. +****************************************************************************/ +u32 shld_long (u32 d, u32 fill, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + res = (d << cnt) | (fill >> (32-cnt)); + cf = d & (1 << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ + (ACCESS_FLAG(F_CF) != 0)), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF); + CLEAR_FLAG(F_OF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_PF); + SET_FLAG(F_ZF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHRD instruction and side effects. +****************************************************************************/ +u16 shrd_word (u16 d, u16 fill, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 16) { + cnt = s % 16; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) | (fill << (16 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHRD instruction and side effects. +****************************************************************************/ +u32 shrd_long (u32 d, u32 fill, u8 s) +{ + unsigned int cnt, res, cf; + + if (s < 32) { + cnt = s % 32; + if (cnt > 0) { + cf = d & (1 << (cnt - 1)); + res = (d >> cnt) | (fill << (32 - cnt)); + CONDITIONAL_SET_FLAG(cf, F_CF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + } else { + res = d; + } + if (cnt == 1) { + CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); + } else { + CLEAR_FLAG(F_OF); + } + } else { + res = 0; + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + SET_FLAG(F_ZF); + CLEAR_FLAG(F_SF); + CLEAR_FLAG(F_PF); + } + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u8 sbb_byte(u8 d, u8 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u16 sbb_word(u16 d, u16 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u32 sbb_long(u32 d, u32 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + if (ACCESS_FLAG(F_CF)) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u8 sub_byte(u8 d, u8 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u16 sub_word(u16 d, u16 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u32 sub_long(u32 d, u32 s) +{ + register u32 res; /* all operands in native machine order */ + register u32 bc; + + res = d - s; + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + + /* calculate the borrow chain. See note at top */ + bc = (res & (~d | s)) | (~d & s); + CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); + CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); + CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_byte(u8 d, u8 s) +{ + register u32 res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_word(u16 d, u16 s) +{ + register u32 res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_long(u32 d, u32 s) +{ + register u32 res; /* all operands in native machine order */ + + res = d & s; + + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + /* AF == dont care */ + CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u8 xor_byte(u8 d, u8 s) +{ + register u8 res; /* all operands in native machine order */ + + res = d ^ s; + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u16 xor_word(u16 d, u16 s) +{ + register u16 res; /* all operands in native machine order */ + + res = d ^ s; + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u32 xor_long(u32 d, u32 s) +{ + register u32 res; /* all operands in native machine order */ + + res = d ^ s; + CLEAR_FLAG(F_OF); + CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); + CONDITIONAL_SET_FLAG(res == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + return res; +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_byte(u8 s) +{ + s16 res = (s16)((s8)M.x86.R_AL * (s8)s); + + M.x86.R_AX = res; + if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) || + ((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_word(u16 s) +{ + s32 res = (s16)M.x86.R_AX * (s16)s; + + M.x86.R_AX = (u16)res; + M.x86.R_DX = (u16)(res >> 16); + if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x00) || + ((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) +{ +#ifdef __HAS_LONG_LONG__ + s64 res = (s32)d * (s32)s; + + *res_lo = (u32)res; + *res_hi = (u32)(res >> 32); +#else + u32 d_lo,d_hi,d_sign; + u32 s_lo,s_hi,s_sign; + u32 rlo_lo,rlo_hi,rhi_lo; + + if ((d_sign = d & 0x80000000) != 0) + d = -d; + d_lo = d & 0xFFFF; + d_hi = d >> 16; + if ((s_sign = s & 0x80000000) != 0) + s = -s; + s_lo = s & 0xFFFF; + s_hi = s >> 16; + rlo_lo = d_lo * s_lo; + rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16); + rhi_lo = d_hi * s_hi + (rlo_hi >> 16); + *res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF); + *res_hi = rhi_lo; + if (d_sign != s_sign) { + d = ~*res_lo; + s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16); + *res_lo = ~*res_lo+1; + *res_hi = ~*res_hi+(s >> 16); + } +#endif +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_long(u32 s) +{ + imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s); + if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00) || + ((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFF)) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_byte(u8 s) +{ + u16 res = (u16)(M.x86.R_AL * s); + + M.x86.R_AX = res; + if (M.x86.R_AH == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_word(u16 s) +{ + u32 res = M.x86.R_AX * s; + + M.x86.R_AX = (u16)res; + M.x86.R_DX = (u16)(res >> 16); + if (M.x86.R_DX == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_long(u32 s) +{ +#ifdef __HAS_LONG_LONG__ + u64 res = (u32)M.x86.R_EAX * (u32)s; + + M.x86.R_EAX = (u32)res; + M.x86.R_EDX = (u32)(res >> 32); +#else + u32 a,a_lo,a_hi; + u32 s_lo,s_hi; + u32 rlo_lo,rlo_hi,rhi_lo; + + a = M.x86.R_EAX; + a_lo = a & 0xFFFF; + a_hi = a >> 16; + s_lo = s & 0xFFFF; + s_hi = s >> 16; + rlo_lo = a_lo * s_lo; + rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16); + rhi_lo = a_hi * s_hi + (rlo_hi >> 16); + M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF); + M.x86.R_EDX = rhi_lo; +#endif + + if (M.x86.R_EDX == 0) { + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_OF); + } else { + SET_FLAG(F_CF); + SET_FLAG(F_OF); + } +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +#define abs(a) (((a) < 0) ? -(a) : (a)) +void idiv_byte(u8 s) +{ + s32 dvd, div, mod; + + dvd = (s16)M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (s8)s; + mod = dvd % (s8)s; + if (abs(div) > 0x7f) { + x86emu_intr_raise(0); + return; + } + M.x86.R_AL = (s8) div; + M.x86.R_AH = (s8) mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_word(u16 s) +{ + s32 dvd, div, mod; + + dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (s16)s; + mod = dvd % (s16)s; + if (abs(div) > 0x7fff) { + x86emu_intr_raise(0); + return; + } + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(div == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + M.x86.R_AX = (u16)div; + M.x86.R_DX = (u16)mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_long(u32 s) +{ +#ifdef __HAS_LONG_LONG__ + s64 dvd, div, mod; + + dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (s32)s; + mod = dvd % (s32)s; + if (abs(div) > 0x7fffffff) { + x86emu_intr_raise(0); + return; + } +#else + s32 div = 0, mod; + s32 h_dvd = M.x86.R_EDX; + u32 l_dvd = M.x86.R_EAX; + u32 abs_s = s & 0x7FFFFFFF; + u32 abs_h_dvd = h_dvd & 0x7FFFFFFF; + u32 h_s = abs_s >> 1; + u32 l_s = abs_s << 31; + int counter = 31; + int carry; + + if (s == 0) { + x86emu_intr_raise(0); + return; + } + do { + div <<= 1; + carry = (l_dvd >= l_s) ? 0 : 1; + + if (abs_h_dvd < (h_s + carry)) { + h_s >>= 1; + l_s = abs_s << (--counter); + continue; + } else { + abs_h_dvd -= (h_s + carry); + l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) + : (l_dvd - l_s); + h_s >>= 1; + l_s = abs_s << (--counter); + div |= 1; + continue; + } + + } while (counter > -1); + /* overflow */ + if (abs_h_dvd || (l_dvd > abs_s)) { + x86emu_intr_raise(0); + return; + } + /* sign */ + div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000)); + mod = l_dvd; + +#endif + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + M.x86.R_EAX = (u32)div; + M.x86.R_EDX = (u32)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_byte(u8 s) +{ + u32 dvd, div, mod; + + dvd = M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (u8)s; + mod = dvd % (u8)s; + if (abs(div) > 0xff) { + x86emu_intr_raise(0); + return; + } + M.x86.R_AL = (u8)div; + M.x86.R_AH = (u8)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_word(u16 s) +{ + u32 dvd, div, mod; + + dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (u16)s; + mod = dvd % (u16)s; + if (abs(div) > 0xffff) { + x86emu_intr_raise(0); + return; + } + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_SF); + CONDITIONAL_SET_FLAG(div == 0, F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + M.x86.R_AX = (u16)div; + M.x86.R_DX = (u16)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_long(u32 s) +{ +#ifdef __HAS_LONG_LONG__ + u64 dvd, div, mod; + + dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX; + if (s == 0) { + x86emu_intr_raise(0); + return; + } + div = dvd / (u32)s; + mod = dvd % (u32)s; + if (abs(div) > 0xffffffff) { + x86emu_intr_raise(0); + return; + } +#else + s32 div = 0, mod; + s32 h_dvd = M.x86.R_EDX; + u32 l_dvd = M.x86.R_EAX; + + u32 h_s = s; + u32 l_s = 0; + int counter = 32; + int carry; + + if (s == 0) { + x86emu_intr_raise(0); + return; + } + do { + div <<= 1; + carry = (l_dvd >= l_s) ? 0 : 1; + + if (h_dvd < (h_s + carry)) { + h_s >>= 1; + l_s = s << (--counter); + continue; + } else { + h_dvd -= (h_s + carry); + l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) + : (l_dvd - l_s); + h_s >>= 1; + l_s = s << (--counter); + div |= 1; + continue; + } + + } while (counter > -1); + /* overflow */ + if (h_dvd || (l_dvd > s)) { + x86emu_intr_raise(0); + return; + } + mod = l_dvd; +#endif + CLEAR_FLAG(F_CF); + CLEAR_FLAG(F_AF); + CLEAR_FLAG(F_SF); + SET_FLAG(F_ZF); + CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); + + M.x86.R_EAX = (u32)div; + M.x86.R_EDX = (u32)mod; +} + +#endif /* __HAVE_INLINE_ASSEMBLER__ */ + +/**************************************************************************** +REMARKS: +Implements the IN string instruction and side effects. +****************************************************************************/ +void ins(int size) +{ + int inc = size; + + if (ACCESS_FLAG(F_DF)) { + inc = -size; + } + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* in until CX is ZERO. */ + u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? + M.x86.R_ECX : M.x86.R_CX); + switch (size) { + case 1: + while (count--) { + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, + (*sys_inb)(M.x86.R_DX)); + M.x86.R_DI += inc; + } + break; + + case 2: + while (count--) { + store_data_word_abs(M.x86.R_ES, M.x86.R_DI, + (*sys_inw)(M.x86.R_DX)); + M.x86.R_DI += inc; + } + break; + case 4: + while (count--) { + store_data_long_abs(M.x86.R_ES, M.x86.R_DI, + (*sys_inl)(M.x86.R_DX)); + M.x86.R_DI += inc; + break; + } + } + M.x86.R_CX = 0; + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_ECX = 0; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + switch (size) { + case 1: + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, + (*sys_inb)(M.x86.R_DX)); + break; + case 2: + store_data_word_abs(M.x86.R_ES, M.x86.R_DI, + (*sys_inw)(M.x86.R_DX)); + break; + case 4: + store_data_long_abs(M.x86.R_ES, M.x86.R_DI, + (*sys_inl)(M.x86.R_DX)); + break; + } + M.x86.R_DI += inc; + } +} + +/**************************************************************************** +REMARKS: +Implements the OUT string instruction and side effects. +****************************************************************************/ +void outs(int size) +{ + int inc = size; + + if (ACCESS_FLAG(F_DF)) { + inc = -size; + } + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ + /* out until CX is ZERO. */ + u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? + M.x86.R_ECX : M.x86.R_CX); + switch (size) { + case 1: + while (count--) { + (*sys_outb)(M.x86.R_DX, + fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI)); + M.x86.R_SI += inc; + } + break; + + case 2: + while (count--) { + (*sys_outw)(M.x86.R_DX, + fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI)); + M.x86.R_SI += inc; + } + break; + case 4: + while (count--) { + (*sys_outl)(M.x86.R_DX, + fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI)); + M.x86.R_SI += inc; + break; + } + } + M.x86.R_CX = 0; + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + M.x86.R_ECX = 0; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { + switch (size) { + case 1: + (*sys_outb)(M.x86.R_DX, + fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI)); + break; + case 2: + (*sys_outw)(M.x86.R_DX, + fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI)); + break; + case 4: + (*sys_outl)(M.x86.R_DX, + fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI)); + break; + } + M.x86.R_SI += inc; + } +} + +/**************************************************************************** +PARAMETERS: +addr - Address to fetch word from + +REMARKS: +Fetches a word from emulator memory using an absolute address. +****************************************************************************/ +u16 mem_access_word(int addr) +{ +DB( if (CHECK_MEM_ACCESS()) + x86emu_check_mem_access(addr);) + return (*sys_rdw)(addr); +} + +/**************************************************************************** +REMARKS: +Pushes a word onto the stack. + +NOTE: Do not inline this, as (*sys_wrX) is already inline! +****************************************************************************/ +void push_word(u16 w) +{ +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + M.x86.R_SP -= 2; + (*sys_wrw)(((u32)M.x86.R_SS << 4) + M.x86.R_SP, w); +} + +/**************************************************************************** +REMARKS: +Pushes a long onto the stack. + +NOTE: Do not inline this, as (*sys_wrX) is already inline! +****************************************************************************/ +void push_long(u32 w) +{ +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + M.x86.R_SP -= 4; + (*sys_wrl)(((u32)M.x86.R_SS << 4) + M.x86.R_SP, w); +} + +/**************************************************************************** +REMARKS: +Pops a word from the stack. + +NOTE: Do not inline this, as (*sys_rdX) is already inline! +****************************************************************************/ +u16 pop_word(void) +{ + register u16 res; + +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + res = (*sys_rdw)(((u32)M.x86.R_SS << 4) + M.x86.R_SP); + M.x86.R_SP += 2; + return res; +} + +/**************************************************************************** +REMARKS: +Pops a long from the stack. + +NOTE: Do not inline this, as (*sys_rdX) is already inline! +****************************************************************************/ +u32 pop_long(void) +{ + register u32 res; + +DB( if (CHECK_SP_ACCESS()) + x86emu_check_sp_access();) + res = (*sys_rdl)(((u32)M.x86.R_SS << 4) + M.x86.R_SP); + M.x86.R_SP += 4; + return res; +} + +#ifdef __HAVE_INLINE_ASSEMBLER__ + +u16 aaa_word (u16 d) +{ return aaa_word_asm(&M.x86.R_EFLG,d); } + +u16 aas_word (u16 d) +{ return aas_word_asm(&M.x86.R_EFLG,d); } + +u16 aad_word (u16 d) +{ return aad_word_asm(&M.x86.R_EFLG,d); } + +u16 aam_word (u8 d) +{ return aam_word_asm(&M.x86.R_EFLG,d); } + +u8 adc_byte (u8 d, u8 s) +{ return adc_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 adc_word (u16 d, u16 s) +{ return adc_word_asm(&M.x86.R_EFLG,d,s); } + +u32 adc_long (u32 d, u32 s) +{ return adc_long_asm(&M.x86.R_EFLG,d,s); } + +u8 add_byte (u8 d, u8 s) +{ return add_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 add_word (u16 d, u16 s) +{ return add_word_asm(&M.x86.R_EFLG,d,s); } + +u32 add_long (u32 d, u32 s) +{ return add_long_asm(&M.x86.R_EFLG,d,s); } + +u8 and_byte (u8 d, u8 s) +{ return and_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 and_word (u16 d, u16 s) +{ return and_word_asm(&M.x86.R_EFLG,d,s); } + +u32 and_long (u32 d, u32 s) +{ return and_long_asm(&M.x86.R_EFLG,d,s); } + +u8 cmp_byte (u8 d, u8 s) +{ return cmp_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 cmp_word (u16 d, u16 s) +{ return cmp_word_asm(&M.x86.R_EFLG,d,s); } + +u32 cmp_long (u32 d, u32 s) +{ return cmp_long_asm(&M.x86.R_EFLG,d,s); } + +u8 daa_byte (u8 d) +{ return daa_byte_asm(&M.x86.R_EFLG,d); } + +u8 das_byte (u8 d) +{ return das_byte_asm(&M.x86.R_EFLG,d); } + +u8 dec_byte (u8 d) +{ return dec_byte_asm(&M.x86.R_EFLG,d); } + +u16 dec_word (u16 d) +{ return dec_word_asm(&M.x86.R_EFLG,d); } + +u32 dec_long (u32 d) +{ return dec_long_asm(&M.x86.R_EFLG,d); } + +u8 inc_byte (u8 d) +{ return inc_byte_asm(&M.x86.R_EFLG,d); } + +u16 inc_word (u16 d) +{ return inc_word_asm(&M.x86.R_EFLG,d); } + +u32 inc_long (u32 d) +{ return inc_long_asm(&M.x86.R_EFLG,d); } + +u8 or_byte (u8 d, u8 s) +{ return or_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 or_word (u16 d, u16 s) +{ return or_word_asm(&M.x86.R_EFLG,d,s); } + +u32 or_long (u32 d, u32 s) +{ return or_long_asm(&M.x86.R_EFLG,d,s); } + +u8 neg_byte (u8 s) +{ return neg_byte_asm(&M.x86.R_EFLG,s); } + +u16 neg_word (u16 s) +{ return neg_word_asm(&M.x86.R_EFLG,s); } + +u32 neg_long (u32 s) +{ return neg_long_asm(&M.x86.R_EFLG,s); } + +u8 not_byte (u8 s) +{ return not_byte_asm(&M.x86.R_EFLG,s); } + +u16 not_word (u16 s) +{ return not_word_asm(&M.x86.R_EFLG,s); } + +u32 not_long (u32 s) +{ return not_long_asm(&M.x86.R_EFLG,s); } + +u8 rcl_byte (u8 d, u8 s) +{ return rcl_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 rcl_word (u16 d, u8 s) +{ return rcl_word_asm(&M.x86.R_EFLG,d,s); } + +u32 rcl_long (u32 d, u8 s) +{ return rcl_long_asm(&M.x86.R_EFLG,d,s); } + +u8 rcr_byte (u8 d, u8 s) +{ return rcr_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 rcr_word (u16 d, u8 s) +{ return rcr_word_asm(&M.x86.R_EFLG,d,s); } + +u32 rcr_long (u32 d, u8 s) +{ return rcr_long_asm(&M.x86.R_EFLG,d,s); } + +u8 rol_byte (u8 d, u8 s) +{ return rol_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 rol_word (u16 d, u8 s) +{ return rol_word_asm(&M.x86.R_EFLG,d,s); } + +u32 rol_long (u32 d, u8 s) +{ return rol_long_asm(&M.x86.R_EFLG,d,s); } + +u8 ror_byte (u8 d, u8 s) +{ return ror_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 ror_word (u16 d, u8 s) +{ return ror_word_asm(&M.x86.R_EFLG,d,s); } + +u32 ror_long (u32 d, u8 s) +{ return ror_long_asm(&M.x86.R_EFLG,d,s); } + +u8 shl_byte (u8 d, u8 s) +{ return shl_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 shl_word (u16 d, u8 s) +{ return shl_word_asm(&M.x86.R_EFLG,d,s); } + +u32 shl_long (u32 d, u8 s) +{ return shl_long_asm(&M.x86.R_EFLG,d,s); } + +u8 shr_byte (u8 d, u8 s) +{ return shr_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 shr_word (u16 d, u8 s) +{ return shr_word_asm(&M.x86.R_EFLG,d,s); } + +u32 shr_long (u32 d, u8 s) +{ return shr_long_asm(&M.x86.R_EFLG,d,s); } + +u8 sar_byte (u8 d, u8 s) +{ return sar_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 sar_word (u16 d, u8 s) +{ return sar_word_asm(&M.x86.R_EFLG,d,s); } + +u32 sar_long (u32 d, u8 s) +{ return sar_long_asm(&M.x86.R_EFLG,d,s); } + +u16 shld_word (u16 d, u16 fill, u8 s) +{ return shld_word_asm(&M.x86.R_EFLG,d,fill,s); } + +u32 shld_long (u32 d, u32 fill, u8 s) +{ return shld_long_asm(&M.x86.R_EFLG,d,fill,s); } + +u16 shrd_word (u16 d, u16 fill, u8 s) +{ return shrd_word_asm(&M.x86.R_EFLG,d,fill,s); } + +u32 shrd_long (u32 d, u32 fill, u8 s) +{ return shrd_long_asm(&M.x86.R_EFLG,d,fill,s); } + +u8 sbb_byte (u8 d, u8 s) +{ return sbb_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 sbb_word (u16 d, u16 s) +{ return sbb_word_asm(&M.x86.R_EFLG,d,s); } + +u32 sbb_long (u32 d, u32 s) +{ return sbb_long_asm(&M.x86.R_EFLG,d,s); } + +u8 sub_byte (u8 d, u8 s) +{ return sub_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 sub_word (u16 d, u16 s) +{ return sub_word_asm(&M.x86.R_EFLG,d,s); } + +u32 sub_long (u32 d, u32 s) +{ return sub_long_asm(&M.x86.R_EFLG,d,s); } + +void test_byte (u8 d, u8 s) +{ test_byte_asm(&M.x86.R_EFLG,d,s); } + +void test_word (u16 d, u16 s) +{ test_word_asm(&M.x86.R_EFLG,d,s); } + +void test_long (u32 d, u32 s) +{ test_long_asm(&M.x86.R_EFLG,d,s); } + +u8 xor_byte (u8 d, u8 s) +{ return xor_byte_asm(&M.x86.R_EFLG,d,s); } + +u16 xor_word (u16 d, u16 s) +{ return xor_word_asm(&M.x86.R_EFLG,d,s); } + +u32 xor_long (u32 d, u32 s) +{ return xor_long_asm(&M.x86.R_EFLG,d,s); } + +void imul_byte (u8 s) +{ imul_byte_asm(&M.x86.R_EFLG,&M.x86.R_AX,M.x86.R_AL,s); } + +void imul_word (u16 s) +{ imul_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,s); } + +void imul_long (u32 s) +{ imul_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s); } + +void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) +{ imul_long_asm(&M.x86.R_EFLG,res_lo,res_hi,d,s); } + +void mul_byte (u8 s) +{ mul_byte_asm(&M.x86.R_EFLG,&M.x86.R_AX,M.x86.R_AL,s); } + +void mul_word (u16 s) +{ mul_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,s); } + +void mul_long (u32 s) +{ mul_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s); } + +void idiv_byte (u8 s) +{ idiv_byte_asm(&M.x86.R_EFLG,&M.x86.R_AL,&M.x86.R_AH,M.x86.R_AX,s); } + +void idiv_word (u16 s) +{ idiv_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,M.x86.R_DX,s); } + +void idiv_long (u32 s) +{ idiv_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,M.x86.R_EDX,s); } + +void div_byte (u8 s) +{ div_byte_asm(&M.x86.R_EFLG,&M.x86.R_AL,&M.x86.R_AH,M.x86.R_AX,s); } + +void div_word (u16 s) +{ div_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,M.x86.R_DX,s); } + +void div_long (u32 s) +{ div_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,M.x86.R_EDX,s); } + +#endif diff --git a/cfe/cfe/x86emu/sys.c b/cfe/cfe/x86emu/sys.c new file mode 100644 index 0000000..f80d755 --- /dev/null +++ b/cfe/cfe/x86emu/sys.c @@ -0,0 +1,603 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: This file includes subroutines which are related to +* programmed I/O and memory access. Included in this module +* are default functions with limited usefulness. For real +* uses these functions will most likely be overriden by the +* user library. +* +****************************************************************************/ +/* $XFree86: xc/extras/x86emu/src/x86emu/sys.c,v 1.5 2000/08/23 22:10:01 tsi Exp $ */ + +#include "x86emu.h" +#include "x86emu/regs.h" +#include "x86emu/debug.h" +#include "x86emu/prim_ops.h" +#ifdef IN_MODULE +#include "xf86_ansic.h" +#else +/*#include */ +#define NULL 0 +#endif +/*------------------------- Global Variables ------------------------------*/ + +X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */ +X86EMU_intrFuncs _X86EMU_intrTab[256]; + +/*----------------------------- Implementation ----------------------------*/ +#if defined(__alpha__) || defined(__alpha) +/* to cope with broken egcs-1.1.2 :-(((( */ + +/* + * inline functions to do unaligned accesses + * from linux/include/asm-alpha/unaligned.h + */ + +/* + * EGCS 1.1 knows about arbitrary unaligned loads. Define some + * packed structures to talk about such things with. + */ + +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 +struct __una_u64 { unsigned long x __attribute__((packed)); }; +struct __una_u32 { unsigned int x __attribute__((packed)); }; +struct __una_u16 { unsigned short x __attribute__((packed)); }; +#endif + +static __inline__ unsigned long ldq_u(unsigned long * r11) +{ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 + const struct __una_u64 *ptr = (const struct __una_u64 *) r11; + return ptr->x; +#else + unsigned long r1,r2; + __asm__("ldq_u %0,%3\n\t" + "ldq_u %1,%4\n\t" + "extql %0,%2,%0\n\t" + "extqh %1,%2,%1" + :"=&r" (r1), "=&r" (r2) + :"r" (r11), + "m" (*r11), + "m" (*(const unsigned long *)(7+(char *) r11))); + return r1 | r2; +#endif +} + +static __inline__ unsigned long ldl_u(unsigned int * r11) +{ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 + const struct __una_u32 *ptr = (const struct __una_u32 *) r11; + return ptr->x; +#else + unsigned long r1,r2; + __asm__("ldq_u %0,%3\n\t" + "ldq_u %1,%4\n\t" + "extll %0,%2,%0\n\t" + "extlh %1,%2,%1" + :"=&r" (r1), "=&r" (r2) + :"r" (r11), + "m" (*r11), + "m" (*(const unsigned long *)(3+(char *) r11))); + return r1 | r2; +#endif +} + +static __inline__ unsigned long ldw_u(unsigned short * r11) +{ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 + const struct __una_u16 *ptr = (const struct __una_u16 *) r11; + return ptr->x; +#else + unsigned long r1,r2; + __asm__("ldq_u %0,%3\n\t" + "ldq_u %1,%4\n\t" + "extwl %0,%2,%0\n\t" + "extwh %1,%2,%1" + :"=&r" (r1), "=&r" (r2) + :"r" (r11), + "m" (*r11), + "m" (*(const unsigned long *)(1+(char *) r11))); + return r1 | r2; +#endif +} + +/* + * Elemental unaligned stores + */ + +static __inline__ void stq_u(unsigned long r5, unsigned long * r11) +{ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 + struct __una_u64 *ptr = (struct __una_u64 *) r11; + ptr->x = r5; +#else + unsigned long r1,r2,r3,r4; + + __asm__("ldq_u %3,%1\n\t" + "ldq_u %2,%0\n\t" + "insqh %6,%7,%5\n\t" + "insql %6,%7,%4\n\t" + "mskqh %3,%7,%3\n\t" + "mskql %2,%7,%2\n\t" + "bis %3,%5,%3\n\t" + "bis %2,%4,%2\n\t" + "stq_u %3,%1\n\t" + "stq_u %2,%0" + :"=m" (*r11), + "=m" (*(unsigned long *)(7+(char *) r11)), + "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4) + :"r" (r5), "r" (r11)); +#endif +} + +static __inline__ void stl_u(unsigned long r5, unsigned int * r11) +{ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 + struct __una_u32 *ptr = (struct __una_u32 *) r11; + ptr->x = r5; +#else + unsigned long r1,r2,r3,r4; + + __asm__("ldq_u %3,%1\n\t" + "ldq_u %2,%0\n\t" + "inslh %6,%7,%5\n\t" + "insll %6,%7,%4\n\t" + "msklh %3,%7,%3\n\t" + "mskll %2,%7,%2\n\t" + "bis %3,%5,%3\n\t" + "bis %2,%4,%2\n\t" + "stq_u %3,%1\n\t" + "stq_u %2,%0" + :"=m" (*r11), + "=m" (*(unsigned long *)(3+(char *) r11)), + "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4) + :"r" (r5), "r" (r11)); +#endif +} + +static __inline__ void stw_u(unsigned long r5, unsigned short * r11) +{ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 + struct __una_u16 *ptr = (struct __una_u16 *) r11; + ptr->x = r5; +#else + unsigned long r1,r2,r3,r4; + + __asm__("ldq_u %3,%1\n\t" + "ldq_u %2,%0\n\t" + "inswh %6,%7,%5\n\t" + "inswl %6,%7,%4\n\t" + "mskwh %3,%7,%3\n\t" + "mskwl %2,%7,%2\n\t" + "bis %3,%5,%3\n\t" + "bis %2,%4,%2\n\t" + "stq_u %3,%1\n\t" + "stq_u %2,%0" + :"=m" (*r11), + "=m" (*(unsigned long *)(1+(char *) r11)), + "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4) + :"r" (r5), "r" (r11)); +#endif +} +#endif + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read + +RETURNS: +Byte value read from emulator memory. + +REMARKS: +Reads a byte value from the emulator memory. +****************************************************************************/ +u8 X86API rdb( + u32 addr) +{ + u8 val; + + if (addr > M.mem_size - 1) { + DB(printk("mem_read: address %#lx out of range!\n", addr);) + HALT_SYS(); + } + val = *(u8*)(M.mem_base + addr); +DB( if (DEBUG_MEM_TRACE()) + printk("%#08x 1 -> %#x\n", addr, val);) + return val; +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read + +RETURNS: +Word value read from emulator memory. + +REMARKS: +Reads a word value from the emulator memory. +****************************************************************************/ +u16 X86API rdw( + u32 addr) +{ + u16 val = 0; + + if (addr > M.mem_size - 2) { + DB(printk("mem_read: address %#lx out of range!\n", addr);) + HALT_SYS(); + } +#ifdef __BIG_ENDIAN__ + if (addr & 0x1) { + val = (*(u8*)(M.mem_base + addr) | + (*(u8*)(M.mem_base + addr + 1) << 8)); + } + else +#endif +#if defined(__alpha__) || defined(__alpha) + val = ldw_u((u16*)(M.mem_base + addr)); +#else + val = *(u16*)(M.mem_base + addr); +#endif + DB( if (DEBUG_MEM_TRACE()) + printk("%#08x 2 -> %#x\n", addr, val);) + return val; +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read + +RETURNS: +Long value read from emulator memory. +REMARKS: +Reads a long value from the emulator memory. +****************************************************************************/ +u32 X86API rdl( + u32 addr) +{ + u32 val = 0; + + if (addr > M.mem_size - 4) { + DB(printk("mem_read: address %#lx out of range!\n", addr);) + HALT_SYS(); + } +#ifdef __BIG_ENDIAN__ + if (addr & 0x3) { + val = (*(u8*)(M.mem_base + addr + 0) | + (*(u8*)(M.mem_base + addr + 1) << 8) | + (*(u8*)(M.mem_base + addr + 2) << 16) | + (*(u8*)(M.mem_base + addr + 3) << 24)); + } + else +#endif +#if defined(__alpha__) || defined(__alpha) + val = ldl_u((u32*)(M.mem_base + addr)); +#else + val = *(u32*)(M.mem_base + addr); +#endif +DB( if (DEBUG_MEM_TRACE()) + printk("%#08x 4 -> %#x\n", addr, val);) + return val; +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read +val - Value to store + +REMARKS: +Writes a byte value to emulator memory. +****************************************************************************/ +void X86API wrb( + u32 addr, + u8 val) +{ +DB( if (DEBUG_MEM_TRACE()) + printk("%#08x 1 <- %#x\n", addr, val);) + if (addr > M.mem_size - 1) { + DB(printk("mem_write: address %#lx out of range!\n", addr);) + HALT_SYS(); + } + *(u8*)(M.mem_base + addr) = val; +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read +val - Value to store + +REMARKS: +Writes a word value to emulator memory. +****************************************************************************/ +void X86API wrw( + u32 addr, + u16 val) +{ +DB( if (DEBUG_MEM_TRACE()) + printk("%#08x 2 <- %#x\n", addr, val);) + if (addr > M.mem_size - 2) { + DB(printk("mem_write: address %#lx out of range!\n", addr);) + HALT_SYS(); + } +#ifdef __BIG_ENDIAN__ + if (addr & 0x1) { + *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff; + *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff; + } + else +#endif +#if defined(__alpha__) || defined(__alpha) + stw_u(val,(u16*)(M.mem_base + addr)); +#else + *(u16*)(M.mem_base + addr) = val; +#endif +} + +/**************************************************************************** +PARAMETERS: +addr - Emulator memory address to read +val - Value to store + +REMARKS: +Writes a long value to emulator memory. +****************************************************************************/ +void X86API wrl( + u32 addr, + u32 val) +{ +DB( if (DEBUG_MEM_TRACE()) + printk("%#08x 4 <- %#x\n", addr, val);) + if (addr > M.mem_size - 4) { + DB(printk("mem_write: address %#lx out of range!\n", addr);) + HALT_SYS(); + } +#ifdef __BIG_ENDIAN__ + if (addr & 0x1) { + *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff; + *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff; + *(u8*)(M.mem_base + addr + 2) = (val >> 16) & 0xff; + *(u8*)(M.mem_base + addr + 3) = (val >> 24) & 0xff; + } + else +#endif +#if defined(__alpha__) || defined(__alpha) + stl_u(val,(u32*)(M.mem_base + addr)); +#else + *(u32*)(M.mem_base + addr) = val; +#endif +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to read +RETURN: +0 +REMARKS: +Default PIO byte read function. Doesn't perform real inb. +****************************************************************************/ +static u8 X86API p_inb( + X86EMU_pioAddr addr) +{ +DB( if (DEBUG_IO_TRACE()) + printk("inb %#04x \n", addr);) + return 0; +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to read +RETURN: +0 +REMARKS: +Default PIO word read function. Doesn't perform real inw. +****************************************************************************/ +static u16 X86API p_inw( + X86EMU_pioAddr addr) +{ +DB( if (DEBUG_IO_TRACE()) + printk("inw %#04x \n", addr);) + return 0; +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to read +RETURN: +0 +REMARKS: +Default PIO long read function. Doesn't perform real inl. +****************************************************************************/ +static u32 X86API p_inl( + X86EMU_pioAddr addr) +{ +DB( if (DEBUG_IO_TRACE()) + printk("inl %#04x \n", addr);) + return 0; +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to write +val - Value to store +REMARKS: +Default PIO byte write function. Doesn't perform real outb. +****************************************************************************/ +static void X86API p_outb( + X86EMU_pioAddr addr, + u8 val) +{ +DB( if (DEBUG_IO_TRACE()) + printk("outb %#02x -> %#04x \n", val, addr);) + return; +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to write +val - Value to store +REMARKS: +Default PIO word write function. Doesn't perform real outw. +****************************************************************************/ +static void X86API p_outw( + X86EMU_pioAddr addr, + u16 val) +{ +DB( if (DEBUG_IO_TRACE()) + printk("outw %#04x -> %#04x \n", val, addr);) + return; +} + +/**************************************************************************** +PARAMETERS: +addr - PIO address to write +val - Value to store +REMARKS: +Default PIO ;ong write function. Doesn't perform real outl. +****************************************************************************/ +static void X86API p_outl( + X86EMU_pioAddr addr, + u32 val) +{ +DB( if (DEBUG_IO_TRACE()) + printk("outl %#08x -> %#04x \n", val, addr);) + return; +} + +/*------------------------- Global Variables ------------------------------*/ + +u8 (X86APIP sys_rdb)(u32 addr) = rdb; +u16 (X86APIP sys_rdw)(u32 addr) = rdw; +u32 (X86APIP sys_rdl)(u32 addr) = rdl; +void (X86APIP sys_wrb)(u32 addr,u8 val) = wrb; +void (X86APIP sys_wrw)(u32 addr,u16 val) = wrw; +void (X86APIP sys_wrl)(u32 addr,u32 val) = wrl; +u8 (X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb; +u16 (X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw; +u32 (X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl; +void (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb; +void (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw; +void (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl; + +/*----------------------------- Setup -------------------------------------*/ + +/**************************************************************************** +PARAMETERS: +funcs - New memory function pointers to make active + +REMARKS: +This function is used to set the pointers to functions which access +memory space, allowing the user application to override these functions +and hook them out as necessary for their application. +****************************************************************************/ +void X86EMU_setupMemFuncs( + X86EMU_memFuncs *funcs) +{ + sys_rdb = funcs->rdb; + sys_rdw = funcs->rdw; + sys_rdl = funcs->rdl; + sys_wrb = funcs->wrb; + sys_wrw = funcs->wrw; + sys_wrl = funcs->wrl; +} + +/**************************************************************************** +PARAMETERS: +funcs - New programmed I/O function pointers to make active + +REMARKS: +This function is used to set the pointers to functions which access +I/O space, allowing the user application to override these functions +and hook them out as necessary for their application. +****************************************************************************/ +void X86EMU_setupPioFuncs( + X86EMU_pioFuncs *funcs) +{ + sys_inb = funcs->inb; + sys_inw = funcs->inw; + sys_inl = funcs->inl; + sys_outb = funcs->outb; + sys_outw = funcs->outw; + sys_outl = funcs->outl; +} + +/**************************************************************************** +PARAMETERS: +funcs - New interrupt vector table to make active + +REMARKS: +This function is used to set the pointers to functions which handle +interrupt processing in the emulator, allowing the user application to +hook interrupts as necessary for their application. Any interrupts that +are not hooked by the user application, and reflected and handled internally +in the emulator via the interrupt vector table. This allows the application +to get control when the code being emulated executes specific software +interrupts. +****************************************************************************/ +void X86EMU_setupIntrFuncs( + X86EMU_intrFuncs funcs[]) +{ + int i; + + for (i=0; i < 256; i++) + _X86EMU_intrTab[i] = NULL; + if (funcs) { + for (i = 0; i < 256; i++) + _X86EMU_intrTab[i] = funcs[i]; + } +} + +/**************************************************************************** +PARAMETERS: +int - New software interrupt to prepare for + +REMARKS: +This function is used to set up the emulator state to exceute a software +interrupt. This can be used by the user application code to allow an +interrupt to be hooked, examined and then reflected back to the emulator +so that the code in the emulator will continue processing the software +interrupt as per normal. This essentially allows system code to actively +hook and handle certain software interrupts as necessary. +****************************************************************************/ +void X86EMU_prepareForInt( + int num) +{ + push_word((u16)M.x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + push_word(M.x86.R_CS); + M.x86.R_CS = mem_access_word(num * 4 + 2); + push_word(M.x86.R_IP); + M.x86.R_IP = mem_access_word(num * 4); + M.x86.intr = 0; +} diff --git a/cfe/cfe/x86emu/validate.c b/cfe/cfe/x86emu/validate.c new file mode 100644 index 0000000..239f6c1 --- /dev/null +++ b/cfe/cfe/x86emu/validate.c @@ -0,0 +1,765 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: Watcom C 10.6 or later +* Environment: 32-bit DOS +* Developer: Kendall Bennett +* +* Description: Program to validate the x86 emulator library for +* correctness. We run the emulator primitive operations +* functions against the real x86 CPU, and compare the result +* and flags to ensure correctness. +* +* We use inline assembler to compile and build this program. +* +****************************************************************************/ + +#include +#include +#include +#include +#include "x86emu.h" +#include "x86emu/prim_asm.h" + +/*-------------------------- Implementation -------------------------------*/ + +#define true 1 +#define false 0 + +#define ALL_FLAGS (F_CF | F_PF | F_AF | F_ZF | F_SF | F_OF) + +#define VAL_START_BINARY(parm_type,res_type,dmax,smax,dincr,sincr) \ +{ \ + parm_type d,s; \ + res_type r,r_asm; \ + ulong flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < dmax; d += dincr) { \ + for (s = 0; s < smax; s += sincr) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { + +#define VAL_TEST_BINARY(name) \ + r_asm = name##_asm(&flags,d,s); \ + r = name(d,s); \ + if (r != r_asm || M.x86.R_EFLG != flags) \ + failed = true; \ + if (failed || trace) { + +#define VAL_TEST_BINARY_VOID(name) \ + name##_asm(&flags,d,s); \ + name(d,s); \ + r = r_asm = 0; \ + if (M.x86.R_EFLG != flags) \ + failed = true; \ + if (failed || trace) { + +#define VAL_FAIL_BYTE_BYTE_BINARY(name) \ + if (failed) \ + printk("fail\n"); \ + printk("0x%02X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ + r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%02X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_FAIL_WORD_WORD_BINARY(name) \ + if (failed) \ + printk("fail\n"); \ + printk("0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ + r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_FAIL_LONG_LONG_BINARY(name) \ + if (failed) \ + printk("fail\n"); \ + printk("0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ + r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_END_BINARY() \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_BYTE_BYTE_BINARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u8,u8,0xFF,0xFF,1,1) \ + VAL_TEST_BINARY(name) \ + VAL_FAIL_BYTE_BYTE_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_WORD_WORD_BINARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u16,u16,0xFF00,0xFF00,0x100,0x100) \ + VAL_TEST_BINARY(name) \ + VAL_FAIL_WORD_WORD_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_LONG_LONG_BINARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u32,u32,0xFF000000,0xFF000000,0x1000000,0x1000000) \ + VAL_TEST_BINARY(name) \ + VAL_FAIL_LONG_LONG_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_VOID_BYTE_BINARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u8,u8,0xFF,0xFF,1,1) \ + VAL_TEST_BINARY_VOID(name) \ + VAL_FAIL_BYTE_BYTE_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_VOID_WORD_BINARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u16,u16,0xFF00,0xFF00,0x100,0x100) \ + VAL_TEST_BINARY_VOID(name) \ + VAL_FAIL_WORD_WORD_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_VOID_LONG_BINARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u32,u32,0xFF000000,0xFF000000,0x1000000,0x1000000) \ + VAL_TEST_BINARY_VOID(name) \ + VAL_FAIL_LONG_LONG_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_BYTE_ROTATE(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u8,u8,0xFF,8,1,1) \ + VAL_TEST_BINARY(name) \ + VAL_FAIL_BYTE_BYTE_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_WORD_ROTATE(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u16,u16,0xFF00,16,0x100,1) \ + VAL_TEST_BINARY(name) \ + VAL_FAIL_WORD_WORD_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_LONG_ROTATE(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_BINARY(u32,u32,0xFF000000,32,0x1000000,1) \ + VAL_TEST_BINARY(name) \ + VAL_FAIL_LONG_LONG_BINARY(name) \ + VAL_END_BINARY() + +#define VAL_START_TERNARY(parm_type,res_type,dmax,smax,dincr,sincr,maxshift)\ +{ \ + parm_type d,s; \ + res_type r,r_asm; \ + u8 shift; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < dmax; d += dincr) { \ + for (s = 0; s < smax; s += sincr) { \ + for (shift = 0; shift < maxshift; shift += 1) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { + +#define VAL_TEST_TERNARY(name) \ + r_asm = name##_asm(&flags,d,s,shift); \ + r = name(d,s,shift); \ + if (r != r_asm || M.x86.R_EFLG != flags) \ + failed = true; \ + if (failed || trace) { + +#define VAL_FAIL_WORD_WORD_TERNARY(name) \ + if (failed) \ + printk("fail\n"); \ + printk("0x%04X = %-15s(0x%04X,0x%04X,%d), flags = %s -> %s\n", \ + r, #name, d, s, shift, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%04X = %-15s(0x%04X,0x%04X,%d), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, s, shift, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_FAIL_LONG_LONG_TERNARY(name) \ + if (failed) \ + printk("fail\n"); \ + printk("0x%08X = %-15s(0x%08X,0x%08X,%d), flags = %s -> %s\n", \ + r, #name, d, s, shift, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%08X = %-15s(0x%08X,0x%08X,%d), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, s, shift, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_END_TERNARY() \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_WORD_ROTATE_DBL(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_TERNARY(u16,u16,0xFF00,0xFF00,0x100,0x100,16) \ + VAL_TEST_TERNARY(name) \ + VAL_FAIL_WORD_WORD_TERNARY(name) \ + VAL_END_TERNARY() + +#define VAL_LONG_ROTATE_DBL(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_TERNARY(u32,u32,0xFF000000,0xFF000000,0x1000000,0x1000000,32) \ + VAL_TEST_TERNARY(name) \ + VAL_FAIL_LONG_LONG_TERNARY(name) \ + VAL_END_TERNARY() + +#define VAL_START_UNARY(parm_type,max,incr) \ +{ \ + parm_type d,r,r_asm; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < max; d += incr) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { + +#define VAL_TEST_UNARY(name) \ + r_asm = name##_asm(&flags,d); \ + r = name(d); \ + if (r != r_asm || M.x86.R_EFLG != flags) { \ + failed = true; + +#define VAL_FAIL_BYTE_UNARY(name) \ + printk("fail\n"); \ + printk("0x%02X = %-15s(0x%02X), flags = %s -> %s\n", \ + r, #name, d, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%02X = %-15s(0x%02X), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_FAIL_WORD_UNARY(name) \ + printk("fail\n"); \ + printk("0x%04X = %-15s(0x%04X), flags = %s -> %s\n", \ + r, #name, d, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%04X = %-15s(0x%04X), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_FAIL_LONG_UNARY(name) \ + printk("fail\n"); \ + printk("0x%08X = %-15s(0x%08X), flags = %s -> %s\n", \ + r, #name, d, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%08X = %-15s(0x%08X), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, print_flags(buf1,inflags), print_flags(buf2,flags)); + +#define VAL_END_UNARY() \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | ALL_FLAGS; \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_BYTE_UNARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_UNARY(u8,0xFF,0x1) \ + VAL_TEST_UNARY(name) \ + VAL_FAIL_BYTE_UNARY(name) \ + VAL_END_UNARY() + +#define VAL_WORD_UNARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_UNARY(u16,0xFF00,0x100) \ + VAL_TEST_UNARY(name) \ + VAL_FAIL_WORD_UNARY(name) \ + VAL_END_UNARY() + +#define VAL_WORD_BYTE_UNARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_UNARY(u16,0xFF,0x1) \ + VAL_TEST_UNARY(name) \ + VAL_FAIL_WORD_UNARY(name) \ + VAL_END_UNARY() + +#define VAL_LONG_UNARY(name) \ + printk("Validating %s ... ", #name); \ + VAL_START_UNARY(u32,0xFF000000,0x1000000) \ + VAL_TEST_UNARY(name) \ + VAL_FAIL_LONG_UNARY(name) \ + VAL_END_UNARY() + +#define VAL_BYTE_MUL(name) \ + printk("Validating %s ... ", #name); \ +{ \ + u8 d,s; \ + u16 r,r_asm; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < 0xFF; d += 1) { \ + for (s = 0; s < 0xFF; s += 1) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { \ + name##_asm(&flags,&r_asm,d,s); \ + M.x86.R_AL = d; \ + name(s); \ + r = M.x86.R_AX; \ + if (r != r_asm || M.x86.R_EFLG != flags) \ + failed = true; \ + if (failed || trace) { \ + if (failed) \ + printk("fail\n"); \ + printk("0x%04X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ + r, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%04X = %-15s(0x%02X,0x%02X), flags = %s -> %s\n", \ + r_asm, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_WORD_MUL(name) \ + printk("Validating %s ... ", #name); \ +{ \ + u16 d,s; \ + u16 r_lo,r_asm_lo; \ + u16 r_hi,r_asm_hi; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < 0xFF00; d += 0x100) { \ + for (s = 0; s < 0xFF00; s += 0x100) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { \ + name##_asm(&flags,&r_asm_lo,&r_asm_hi,d,s); \ + M.x86.R_AX = d; \ + name(s); \ + r_lo = M.x86.R_AX; \ + r_hi = M.x86.R_DX; \ + if (r_lo != r_asm_lo || r_hi != r_asm_hi || M.x86.R_EFLG != flags)\ + failed = true; \ + if (failed || trace) { \ + if (failed) \ + printk("fail\n"); \ + printk("0x%04X:0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ + r_hi,r_lo, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%04X:0x%04X = %-15s(0x%04X,0x%04X), flags = %s -> %s\n", \ + r_asm_hi,r_asm_lo, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_LONG_MUL(name) \ + printk("Validating %s ... ", #name); \ +{ \ + u32 d,s; \ + u32 r_lo,r_asm_lo; \ + u32 r_hi,r_asm_hi; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < 0xFF000000; d += 0x1000000) { \ + for (s = 0; s < 0xFF000000; s += 0x1000000) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { \ + name##_asm(&flags,&r_asm_lo,&r_asm_hi,d,s); \ + M.x86.R_EAX = d; \ + name(s); \ + r_lo = M.x86.R_EAX; \ + r_hi = M.x86.R_EDX; \ + if (r_lo != r_asm_lo || r_hi != r_asm_hi || M.x86.R_EFLG != flags)\ + failed = true; \ + if (failed || trace) { \ + if (failed) \ + printk("fail\n"); \ + printk("0x%08X:0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ + r_hi,r_lo, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%08X:0x%08X = %-15s(0x%08X,0x%08X), flags = %s -> %s\n", \ + r_asm_hi,r_asm_lo, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_BYTE_DIV(name) \ + printk("Validating %s ... ", #name); \ +{ \ + u16 d,s; \ + u8 r_quot,r_rem,r_asm_quot,r_asm_rem; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < 0xFF00; d += 0x100) { \ + for (s = 1; s < 0xFF; s += 1) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { \ + M.x86.intr = 0; \ + M.x86.R_AX = d; \ + name(s); \ + r_quot = M.x86.R_AL; \ + r_rem = M.x86.R_AH; \ + if (M.x86.intr & INTR_SYNCH) \ + continue; \ + name##_asm(&flags,&r_asm_quot,&r_asm_rem,d,s); \ + if (r_quot != r_asm_quot || r_rem != r_asm_rem || M.x86.R_EFLG != flags) \ + failed = true; \ + if (failed || trace) { \ + if (failed) \ + printk("fail\n"); \ + printk("0x%02X:0x%02X = %-15s(0x%04X,0x%02X), flags = %s -> %s\n", \ + r_quot, r_rem, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%02X:0x%02X = %-15s(0x%04X,0x%02X), flags = %s -> %s\n", \ + r_asm_quot, r_asm_rem, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_WORD_DIV(name) \ + printk("Validating %s ... ", #name); \ +{ \ + u32 d,s; \ + u16 r_quot,r_rem,r_asm_quot,r_asm_rem; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < 0xFF000000; d += 0x1000000) { \ + for (s = 0x100; s < 0xFF00; s += 0x100) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { \ + M.x86.intr = 0; \ + M.x86.R_AX = d & 0xFFFF; \ + M.x86.R_DX = d >> 16; \ + name(s); \ + r_quot = M.x86.R_AX; \ + r_rem = M.x86.R_DX; \ + if (M.x86.intr & INTR_SYNCH) \ + continue; \ + name##_asm(&flags,&r_asm_quot,&r_asm_rem,d & 0xFFFF,d >> 16,s);\ + if (r_quot != r_asm_quot || r_rem != r_asm_rem || M.x86.R_EFLG != flags) \ + failed = true; \ + if (failed || trace) { \ + if (failed) \ + printk("fail\n"); \ + printk("0x%04X:0x%04X = %-15s(0x%08X,0x%04X), flags = %s -> %s\n", \ + r_quot, r_rem, #name, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%04X:0x%04X = %-15s(0x%08X,0x%04X), flags = %s -> %s\n", \ + r_asm_quot, r_asm_rem, #name"_asm", d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +#define VAL_LONG_DIV(name) \ + printk("Validating %s ... ", #name); \ +{ \ + u32 d,s; \ + u32 r_quot,r_rem,r_asm_quot,r_asm_rem; \ + u32 flags,inflags; \ + int f,failed = false; \ + char buf1[80],buf2[80]; \ + for (d = 0; d < 0xFF000000; d += 0x1000000) { \ + for (s = 0x100; s < 0xFF00; s += 0x100) { \ + M.x86.R_EFLG = inflags = flags = def_flags; \ + for (f = 0; f < 2; f++) { \ + M.x86.intr = 0; \ + M.x86.R_EAX = d; \ + M.x86.R_EDX = 0; \ + name(s); \ + r_quot = M.x86.R_EAX; \ + r_rem = M.x86.R_EDX; \ + if (M.x86.intr & INTR_SYNCH) \ + continue; \ + name##_asm(&flags,&r_asm_quot,&r_asm_rem,d,0,s); \ + if (r_quot != r_asm_quot || r_rem != r_asm_rem || M.x86.R_EFLG != flags) \ + failed = true; \ + if (failed || trace) { \ + if (failed) \ + printk("fail\n"); \ + printk("0x%08X:0x%08X = %-15s(0x%08X:0x%08X,0x%08X), flags = %s -> %s\n", \ + r_quot, r_rem, #name, 0, d, s, print_flags(buf1,inflags), print_flags(buf2,M.x86.R_EFLG)); \ + printk("0x%08X:0x%08X = %-15s(0x%08X:0x%08X,0x%08X), flags = %s -> %s\n", \ + r_asm_quot, r_asm_rem, #name"_asm", 0, d, s, print_flags(buf1,inflags), print_flags(buf2,flags)); \ + } \ + M.x86.R_EFLG = inflags = flags = def_flags | (ALL_FLAGS & ~F_OF); \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (failed) \ + break; \ + } \ + if (!failed) \ + printk("passed\n"); \ +} + +void printk(const char *fmt, ...) +{ + va_list argptr; + va_start(argptr, fmt); + vfprintf(stdout, fmt, argptr); + fflush(stdout); + va_end(argptr); +} + +char * print_flags(char *buf,ulong flags) +{ + char *separator = ""; + + buf[0] = 0; + if (flags & F_CF) { + strcat(buf,separator); + strcat(buf,"CF"); + separator = ","; + } + if (flags & F_PF) { + strcat(buf,separator); + strcat(buf,"PF"); + separator = ","; + } + if (flags & F_AF) { + strcat(buf,separator); + strcat(buf,"AF"); + separator = ","; + } + if (flags & F_ZF) { + strcat(buf,separator); + strcat(buf,"ZF"); + separator = ","; + } + if (flags & F_SF) { + strcat(buf,separator); + strcat(buf,"SF"); + separator = ","; + } + if (flags & F_OF) { + strcat(buf,separator); + strcat(buf,"OF"); + separator = ","; + } + if (separator[0] == 0) + strcpy(buf,"None"); + return buf; +} + +int main(int argc) +{ + ulong def_flags; + int trace = false; + + if (argc > 1) + trace = true; + memset(&M, 0, sizeof(M)); + def_flags = get_flags_asm() & ~ALL_FLAGS; + + VAL_WORD_UNARY(aaa_word); + VAL_WORD_UNARY(aas_word); + + VAL_WORD_UNARY(aad_word); + VAL_WORD_UNARY(aam_word); + + VAL_BYTE_BYTE_BINARY(adc_byte); + VAL_WORD_WORD_BINARY(adc_word); + VAL_LONG_LONG_BINARY(adc_long); + + VAL_BYTE_BYTE_BINARY(add_byte); + VAL_WORD_WORD_BINARY(add_word); + VAL_LONG_LONG_BINARY(add_long); + + VAL_BYTE_BYTE_BINARY(and_byte); + VAL_WORD_WORD_BINARY(and_word); + VAL_LONG_LONG_BINARY(and_long); + + VAL_BYTE_BYTE_BINARY(cmp_byte); + VAL_WORD_WORD_BINARY(cmp_word); + VAL_LONG_LONG_BINARY(cmp_long); + + VAL_BYTE_UNARY(daa_byte); + VAL_BYTE_UNARY(das_byte); // Fails for 0x9A (out of range anyway) + + VAL_BYTE_UNARY(dec_byte); + VAL_WORD_UNARY(dec_word); + VAL_LONG_UNARY(dec_long); + + VAL_BYTE_UNARY(inc_byte); + VAL_WORD_UNARY(inc_word); + VAL_LONG_UNARY(inc_long); + + VAL_BYTE_BYTE_BINARY(or_byte); + VAL_WORD_WORD_BINARY(or_word); + VAL_LONG_LONG_BINARY(or_long); + + VAL_BYTE_UNARY(neg_byte); + VAL_WORD_UNARY(neg_word); + VAL_LONG_UNARY(neg_long); + + VAL_BYTE_UNARY(not_byte); + VAL_WORD_UNARY(not_word); + VAL_LONG_UNARY(not_long); + + VAL_BYTE_ROTATE(rcl_byte); + VAL_WORD_ROTATE(rcl_word); + VAL_LONG_ROTATE(rcl_long); + + VAL_BYTE_ROTATE(rcr_byte); + VAL_WORD_ROTATE(rcr_word); + VAL_LONG_ROTATE(rcr_long); + + VAL_BYTE_ROTATE(rol_byte); + VAL_WORD_ROTATE(rol_word); + VAL_LONG_ROTATE(rol_long); + + VAL_BYTE_ROTATE(ror_byte); + VAL_WORD_ROTATE(ror_word); + VAL_LONG_ROTATE(ror_long); + + VAL_BYTE_ROTATE(shl_byte); + VAL_WORD_ROTATE(shl_word); + VAL_LONG_ROTATE(shl_long); + + VAL_BYTE_ROTATE(shr_byte); + VAL_WORD_ROTATE(shr_word); + VAL_LONG_ROTATE(shr_long); + + VAL_BYTE_ROTATE(sar_byte); + VAL_WORD_ROTATE(sar_word); + VAL_LONG_ROTATE(sar_long); + + VAL_WORD_ROTATE_DBL(shld_word); + VAL_LONG_ROTATE_DBL(shld_long); + + VAL_WORD_ROTATE_DBL(shrd_word); + VAL_LONG_ROTATE_DBL(shrd_long); + + VAL_BYTE_BYTE_BINARY(sbb_byte); + VAL_WORD_WORD_BINARY(sbb_word); + VAL_LONG_LONG_BINARY(sbb_long); + + VAL_BYTE_BYTE_BINARY(sub_byte); + VAL_WORD_WORD_BINARY(sub_word); + VAL_LONG_LONG_BINARY(sub_long); + + VAL_BYTE_BYTE_BINARY(xor_byte); + VAL_WORD_WORD_BINARY(xor_word); + VAL_LONG_LONG_BINARY(xor_long); + + VAL_VOID_BYTE_BINARY(test_byte); + VAL_VOID_WORD_BINARY(test_word); + VAL_VOID_LONG_BINARY(test_long); + + VAL_BYTE_MUL(imul_byte); + VAL_WORD_MUL(imul_word); + VAL_LONG_MUL(imul_long); + + VAL_BYTE_MUL(mul_byte); + VAL_WORD_MUL(mul_word); + VAL_LONG_MUL(mul_long); + + VAL_BYTE_DIV(idiv_byte); + VAL_WORD_DIV(idiv_word); + VAL_LONG_DIV(idiv_long); + + VAL_BYTE_DIV(div_byte); + VAL_WORD_DIV(div_word); + VAL_LONG_DIV(div_long); + + return 0; +} diff --git a/cfe/cfe/x86emu/x86emu.h b/cfe/cfe/x86emu/x86emu.h new file mode 100644 index 0000000..7c7d367 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu.h @@ -0,0 +1,198 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for public specific functions. +* Any application linking against us should only +* include this header +* +****************************************************************************/ +/* $XFree86: xc/extras/x86emu/include/x86emu.h,v 1.2 2000/11/21 23:10:25 tsi Exp $ */ + +#ifndef __X86EMU_X86EMU_H +#define __X86EMU_X86EMU_H + +#ifdef SCITECH +#include "scitech.h" +#define X86API _ASMAPI +#define X86APIP _ASMAPIP +typedef int X86EMU_pioAddr; +#else +#include "x86emu/types.h" +#define X86API +#define X86APIP * +#endif +#include "x86emu/regs.h" + +/*---------------------- Macros and type definitions ----------------------*/ + +#ifndef __mips +#pragma pack(1) +#endif + +/**************************************************************************** +REMARKS: +Data structure containing ponters to programmed I/O functions used by the +emulator. This is used so that the user program can hook all programmed +I/O for the emulator to handled as necessary by the user program. By +default the emulator contains simple functions that do not do access the +hardware in any way. To allow the emualtor access the hardware, you will +need to override the programmed I/O functions using the X86EMU_setupPioFuncs +function. + +HEADER: +x86emu.h + +MEMBERS: +inb - Function to read a byte from an I/O port +inw - Function to read a word from an I/O port +inl - Function to read a dword from an I/O port +outb - Function to write a byte to an I/O port +outw - Function to write a word to an I/O port +outl - Function to write a dword to an I/O port +****************************************************************************/ +typedef struct { + u8 (X86APIP inb)(X86EMU_pioAddr addr); + u16 (X86APIP inw)(X86EMU_pioAddr addr); + u32 (X86APIP inl)(X86EMU_pioAddr addr); + void (X86APIP outb)(X86EMU_pioAddr addr, u8 val); + void (X86APIP outw)(X86EMU_pioAddr addr, u16 val); + void (X86APIP outl)(X86EMU_pioAddr addr, u32 val); + } X86EMU_pioFuncs; + +/**************************************************************************** +REMARKS: +Data structure containing ponters to memory access functions used by the +emulator. This is used so that the user program can hook all memory +access functions as necessary for the emulator. By default the emulator +contains simple functions that only access the internal memory of the +emulator. If you need specialised functions to handle access to different +types of memory (ie: hardware framebuffer accesses and BIOS memory access +etc), you will need to override this using the X86EMU_setupMemFuncs +function. + +HEADER: +x86emu.h + +MEMBERS: +rdb - Function to read a byte from an address +rdw - Function to read a word from an address +rdl - Function to read a dword from an address +wrb - Function to write a byte to an address +wrw - Function to write a word to an address +wrl - Function to write a dword to an address +****************************************************************************/ +typedef struct { + u8 (X86APIP rdb)(u32 addr); + u16 (X86APIP rdw)(u32 addr); + u32 (X86APIP rdl)(u32 addr); + void (X86APIP wrb)(u32 addr, u8 val); + void (X86APIP wrw)(u32 addr, u16 val); + void (X86APIP wrl)(u32 addr, u32 val); + } X86EMU_memFuncs; + +/**************************************************************************** + Here are the default memory read and write + function in case they are needed as fallbacks. +***************************************************************************/ +extern u8 X86API rdb(u32 addr); +extern u16 X86API rdw(u32 addr); +extern u32 X86API rdl(u32 addr); +extern void X86API wrb(u32 addr, u8 val); +extern void X86API wrw(u32 addr, u16 val); +extern void X86API wrl(u32 addr, u32 val); + +#ifndef __mips +#pragma pack() +#endif + +/*--------------------- type definitions -----------------------------------*/ + +typedef void (X86APIP X86EMU_intrFuncs)(int num); +extern X86EMU_intrFuncs _X86EMU_intrTab[256]; + +/*-------------------------- Function Prototypes --------------------------*/ + +#ifdef __cplusplus +extern "C" { /* Use "C" linkage when in C++ mode */ +#endif + +void X86EMU_setupMemFuncs(X86EMU_memFuncs *funcs); +void X86EMU_setupPioFuncs(X86EMU_pioFuncs *funcs); +void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]); +void X86EMU_prepareForInt(int num); + +/* decode.c */ + +void X86EMU_exec(void); +void X86EMU_halt_sys(void); + +#ifdef DEBUG +#define HALT_SYS() \ + printk("halt_sys: file %s, line %d\n", __FILE__, __LINE__), \ + X86EMU_halt_sys() +#else +#define HALT_SYS() X86EMU_halt_sys() +#endif + +/* Debug options */ + +#define DEBUG_DECODE_F 0x000001 /* print decoded instruction */ +#define DEBUG_TRACE_F 0x000002 /* dump regs before/after execution */ +#define DEBUG_STEP_F 0x000004 +#define DEBUG_DISASSEMBLE_F 0x000008 +#define DEBUG_BREAK_F 0x000010 +#define DEBUG_SVC_F 0x000020 +#define DEBUG_FS_F 0x000080 +#define DEBUG_PROC_F 0x000100 +#define DEBUG_SYSINT_F 0x000200 /* bios system interrupts. */ +#define DEBUG_TRACECALL_F 0x000400 +#define DEBUG_INSTRUMENT_F 0x000800 +#define DEBUG_MEM_TRACE_F 0x001000 +#define DEBUG_IO_TRACE_F 0x002000 +#define DEBUG_TRACECALL_REGS_F 0x004000 +#define DEBUG_DECODE_NOPRINT_F 0x008000 +#define DEBUG_SAVE_IP_CS_F 0x010000 +#define DEBUG_SYS_F (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F) + +void X86EMU_trace_regs(void); +void X86EMU_trace_xregs(void); +void X86EMU_dump_memory(u16 seg, u16 off, u32 amt); +int X86EMU_trace_on(void); +int X86EMU_trace_off(void); + +#ifdef __cplusplus +} /* End of "C" linkage for C++ */ +#endif + +#endif /* __X86EMU_X86EMU_H */ diff --git a/cfe/cfe/x86emu/x86emu/debug.h b/cfe/cfe/x86emu/x86emu/debug.h new file mode 100644 index 0000000..45271c9 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/debug.h @@ -0,0 +1,212 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for debug definitions. +* +****************************************************************************/ +/* $XFree86: xc/extras/x86emu/src/x86emu/x86emu/debug.h,v 1.4 2000/11/21 23:10:27 tsi Exp $ */ + +#ifndef __X86EMU_DEBUG_H +#define __X86EMU_DEBUG_H + +/*---------------------- Macros and type definitions ----------------------*/ + +/* checks to be enabled for "runtime" */ + +#define CHECK_IP_FETCH_F 0x1 +#define CHECK_SP_ACCESS_F 0x2 +#define CHECK_MEM_ACCESS_F 0x4 /*using regular linear pointer */ +#define CHECK_DATA_ACCESS_F 0x8 /*using segment:offset*/ + +#ifdef DEBUG +# define CHECK_IP_FETCH() (M.x86.check & CHECK_IP_FETCH_F) +# define CHECK_SP_ACCESS() (M.x86.check & CHECK_SP_ACCESS_F) +# define CHECK_MEM_ACCESS() (M.x86.check & CHECK_MEM_ACCESS_F) +# define CHECK_DATA_ACCESS() (M.x86.check & CHECK_DATA_ACCESS_F) +#else +# define CHECK_IP_FETCH() +# define CHECK_SP_ACCESS() +# define CHECK_MEM_ACCESS() +# define CHECK_DATA_ACCESS() +#endif + +#ifdef DEBUG +# define DEBUG_INSTRUMENT() (M.x86.debug & DEBUG_INSTRUMENT_F) +# define DEBUG_DECODE() (M.x86.debug & DEBUG_DECODE_F) +# define DEBUG_TRACE() (M.x86.debug & DEBUG_TRACE_F) +# define DEBUG_STEP() (M.x86.debug & DEBUG_STEP_F) +# define DEBUG_DISASSEMBLE() (M.x86.debug & DEBUG_DISASSEMBLE_F) +# define DEBUG_BREAK() (M.x86.debug & DEBUG_BREAK_F) +# define DEBUG_SVC() (M.x86.debug & DEBUG_SVC_F) +# define DEBUG_SAVE_IP_CS() (M.x86.debug & DEBUG_SAVE_IP_CS_F) + +# define DEBUG_FS() (M.x86.debug & DEBUG_FS_F) +# define DEBUG_PROC() (M.x86.debug & DEBUG_PROC_F) +# define DEBUG_SYSINT() (M.x86.debug & DEBUG_SYSINT_F) +# define DEBUG_TRACECALL() (M.x86.debug & DEBUG_TRACECALL_F) +# define DEBUG_TRACECALLREGS() (M.x86.debug & DEBUG_TRACECALL_REGS_F) +# define DEBUG_SYS() (M.x86.debug & DEBUG_SYS_F) +# define DEBUG_MEM_TRACE() (M.x86.debug & DEBUG_MEM_TRACE_F) +# define DEBUG_IO_TRACE() (M.x86.debug & DEBUG_IO_TRACE_F) +# define DEBUG_DECODE_NOPRINT() (M.x86.debug & DEBUG_DECODE_NOPRINT_F) +#else +# define DEBUG_INSTRUMENT() 0 +# define DEBUG_DECODE() 0 +# define DEBUG_TRACE() 0 +# define DEBUG_STEP() 0 +# define DEBUG_DISASSEMBLE() 0 +# define DEBUG_BREAK() 0 +# define DEBUG_SVC() 0 +# define DEBUG_SAVE_IP_CS() 0 +# define DEBUG_FS() 0 +# define DEBUG_PROC() 0 +# define DEBUG_SYSINT() 0 +# define DEBUG_TRACECALL() 0 +# define DEBUG_TRACECALLREGS() 0 +# define DEBUG_SYS() 0 +# define DEBUG_MEM_TRACE() 0 +# define DEBUG_IO_TRACE() 0 +# define DEBUG_DECODE_NOPRINT() 0 +#endif + +#ifdef DEBUG + +# define DECODE_PRINTF(x) if (DEBUG_DECODE()) \ + x86emu_decode_printf(x) +# define DECODE_PRINTF2(x,y) if (DEBUG_DECODE()) \ + x86emu_decode_printf2(x,y) + +/* + * The following allow us to look at the bytes of an instruction. The + * first INCR_INSTRN_LEN, is called everytime bytes are consumed in + * the decoding process. The SAVE_IP_CS is called initially when the + * major opcode of the instruction is accessed. + */ +#define INC_DECODED_INST_LEN(x) \ + if (DEBUG_DECODE()) \ + x86emu_inc_decoded_inst_len(x) + +#define SAVE_IP_CS(x,y) \ + if (DEBUG_DECODE() | DEBUG_TRACECALL() | DEBUG_BREAK() \ + | DEBUG_IO_TRACE() | DEBUG_SAVE_IP_CS()) { \ + M.x86.saved_cs = x; \ + M.x86.saved_ip = y; \ + } +#else +# define INC_DECODED_INST_LEN(x) +# define DECODE_PRINTF(x) +# define DECODE_PRINTF2(x,y) +# define SAVE_IP_CS(x,y) +#endif + +#ifdef DEBUG +#define TRACE_REGS() \ + if (DEBUG_DISASSEMBLE()) { \ + x86emu_just_disassemble(); \ + goto EndOfTheInstructionProcedure; \ + } \ + if (DEBUG_TRACE() || DEBUG_DECODE()) X86EMU_trace_regs() +#else +# define TRACE_REGS() +#endif + +#ifdef DEBUG +# define SINGLE_STEP() if (DEBUG_STEP()) x86emu_single_step() +#else +# define SINGLE_STEP() +#endif + +#define TRACE_AND_STEP() \ + TRACE_REGS(); \ + SINGLE_STEP() + +#ifdef DEBUG +# define START_OF_INSTR() +# define END_OF_INSTR() EndOfTheInstructionProcedure: x86emu_end_instr(); +# define END_OF_INSTR_NO_TRACE() x86emu_end_instr(); +#else +# define START_OF_INSTR() +# define END_OF_INSTR() +# define END_OF_INSTR_NO_TRACE() +#endif + +#ifdef DEBUG +# define CALL_TRACE(u,v,w,x,s) \ + if (DEBUG_TRACECALLREGS()) \ + x86emu_dump_regs(); \ + if (DEBUG_TRACECALL()) \ + printk("%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x); +# define RETURN_TRACE(n,u,v) \ + if (DEBUG_TRACECALLREGS()) \ + x86emu_dump_regs(); \ + if (DEBUG_TRACECALL()) \ + printk("%04x:%04x: %s\n",u,v,n); +#else +# define CALL_TRACE(u,v,w,x,s) +# define RETURN_TRACE(n,u,v) +#endif + +#ifdef DEBUG +#define DB(x) x +#else +#define DB(x) +#endif + +/*-------------------------- Function Prototypes --------------------------*/ + +#ifdef __cplusplus +extern "C" { /* Use "C" linkage when in C++ mode */ +#endif + +extern void x86emu_inc_decoded_inst_len (int x); +extern void x86emu_decode_printf (char *x); +extern void x86emu_decode_printf2 (char *x, int y); +extern void x86emu_just_disassemble (void); +extern void x86emu_single_step (void); +extern void x86emu_end_instr (void); +extern void x86emu_dump_regs (void); +extern void x86emu_dump_xregs (void); +extern void x86emu_print_int_vect (u16 iv); +extern void x86emu_instrument_instruction (void); +extern void x86emu_check_ip_access (void); +extern void x86emu_check_sp_access (void); +extern void x86emu_check_mem_access (u32 p); +extern void x86emu_check_data_access (uint s, uint o); + +#ifdef __cplusplus +} /* End of "C" linkage for C++ */ +#endif + + +#endif /* __X86EMU_DEBUG_H */ diff --git a/cfe/cfe/x86emu/x86emu/decode.h b/cfe/cfe/x86emu/x86emu/decode.h new file mode 100644 index 0000000..321a345 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/decode.h @@ -0,0 +1,87 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for instruction decoding logic. +* +****************************************************************************/ + +#ifndef __X86EMU_DECODE_H +#define __X86EMU_DECODE_H + +/*---------------------- Macros and type definitions ----------------------*/ + +/* Instruction Decoding Stuff */ + +#define FETCH_DECODE_MODRM(mod,rh,rl) fetch_decode_modrm(&mod,&rh,&rl) +#define DECODE_RM_BYTE_REGISTER(r) decode_rm_byte_register(r) +#define DECODE_RM_WORD_REGISTER(r) decode_rm_word_register(r) +#define DECODE_RM_LONG_REGISTER(r) decode_rm_long_register(r) +#define DECODE_CLEAR_SEGOVR() M.x86.mode &= ~SYSMODE_CLRMASK + +/*-------------------------- Function Prototypes --------------------------*/ + +#ifdef __cplusplus +extern "C" { /* Use "C" linkage when in C++ mode */ +#endif + +void x86emu_intr_raise (u8 type); +void fetch_decode_modrm (int *mod,int *regh,int *regl); +u8 fetch_byte_imm (void); +u16 fetch_word_imm (void); +u32 fetch_long_imm (void); +u8 fetch_data_byte (uint offset); +u8 fetch_data_byte_abs (uint segment, uint offset); +u16 fetch_data_word (uint offset); +u16 fetch_data_word_abs (uint segment, uint offset); +u32 fetch_data_long (uint offset); +u32 fetch_data_long_abs (uint segment, uint offset); +void store_data_byte (uint offset, u8 val); +void store_data_byte_abs (uint segment, uint offset, u8 val); +void store_data_word (uint offset, u16 val); +void store_data_word_abs (uint segment, uint offset, u16 val); +void store_data_long (uint offset, u32 val); +void store_data_long_abs (uint segment, uint offset, u32 val); +u8* decode_rm_byte_register(int reg); +u16* decode_rm_word_register(int reg); +u32* decode_rm_long_register(int reg); +u16* decode_rm_seg_register(int reg); +unsigned decode_rm00_address(int rm); +unsigned decode_rm01_address(int rm); +unsigned decode_rm10_address(int rm); + +#ifdef __cplusplus +} /* End of "C" linkage for C++ */ +#endif + +#endif /* __X86EMU_DECODE_H */ diff --git a/cfe/cfe/x86emu/x86emu/fpu.h b/cfe/cfe/x86emu/x86emu/fpu.h new file mode 100644 index 0000000..5fb2714 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/fpu.h @@ -0,0 +1,61 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for FPU instruction decoding. +* +****************************************************************************/ + +#ifndef __X86EMU_FPU_H +#define __X86EMU_FPU_H + +#ifdef __cplusplus +extern "C" { /* Use "C" linkage when in C++ mode */ +#endif + +/* these have to be defined, whether 8087 support compiled in or not. */ + +extern void x86emuOp_esc_coprocess_d8 (u8 op1); +extern void x86emuOp_esc_coprocess_d9 (u8 op1); +extern void x86emuOp_esc_coprocess_da (u8 op1); +extern void x86emuOp_esc_coprocess_db (u8 op1); +extern void x86emuOp_esc_coprocess_dc (u8 op1); +extern void x86emuOp_esc_coprocess_dd (u8 op1); +extern void x86emuOp_esc_coprocess_de (u8 op1); +extern void x86emuOp_esc_coprocess_df (u8 op1); + +#ifdef __cplusplus +} /* End of "C" linkage for C++ */ +#endif + +#endif /* __X86EMU_FPU_H */ diff --git a/cfe/cfe/x86emu/x86emu/fpu_regs.h b/cfe/cfe/x86emu/x86emu/fpu_regs.h new file mode 100644 index 0000000..56e9a04 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/fpu_regs.h @@ -0,0 +1,115 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for FPU register definitions. +* +****************************************************************************/ + +#ifndef __X86EMU_FPU_REGS_H +#define __X86EMU_FPU_REGS_H + +#ifdef X86_FPU_SUPPORT + +#pragma pack(1) + +/* Basic 8087 register can hold any of the following values: */ + +union x86_fpu_reg_u { + s8 tenbytes[10]; + double dval; + float fval; + s16 sval; + s32 lval; + }; + +struct x86_fpu_reg { + union x86_fpu_reg_u reg; + char tag; + }; + +/* + * Since we are not going to worry about the problems of aliasing + * registers, every time a register is modified, its result type is + * set in the tag fields for that register. If some operation + * attempts to access the type in a way inconsistent with its current + * storage format, then we flag the operation. If common, we'll + * attempt the conversion. + */ + +#define X86_FPU_VALID 0x80 +#define X86_FPU_REGTYP(r) ((r) & 0x7F) + +#define X86_FPU_WORD 0x0 +#define X86_FPU_SHORT 0x1 +#define X86_FPU_LONG 0x2 +#define X86_FPU_FLOAT 0x3 +#define X86_FPU_DOUBLE 0x4 +#define X86_FPU_LDBL 0x5 +#define X86_FPU_BSD 0x6 + +#define X86_FPU_STKTOP 0 + +struct x86_fpu_registers { + struct x86_fpu_reg x86_fpu_stack[8]; + int x86_fpu_flags; + int x86_fpu_config; /* rounding modes, etc. */ + short x86_fpu_tos, x86_fpu_bos; + }; + +#pragma pack() + +/* + * There are two versions of the following macro. + * + * One version is for opcode D9, for which there are more than 32 + * instructions encoded in the second byte of the opcode. + * + * The other version, deals with all the other 7 i87 opcodes, for + * which there are only 32 strings needed to describe the + * instructions. + */ + +#endif /* X86_FPU_SUPPORT */ + +#ifdef DEBUG +# define DECODE_PRINTINSTR32(t,mod,rh,rl) \ + DECODE_PRINTF(t[(mod<<3)+(rh)]); +# define DECODE_PRINTINSTR256(t,mod,rh,rl) \ + DECODE_PRINTF(t[(mod<<6)+(rh<<3)+(rl)]); +#else +# define DECODE_PRINTINSTR32(t,mod,rh,rl) +# define DECODE_PRINTINSTR256(t,mod,rh,rl) +#endif + +#endif /* __X86EMU_FPU_REGS_H */ diff --git a/cfe/cfe/x86emu/x86emu/ops.h b/cfe/cfe/x86emu/x86emu/ops.h new file mode 100644 index 0000000..65ea676 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/ops.h @@ -0,0 +1,45 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for operand decoding functions. +* +****************************************************************************/ + +#ifndef __X86EMU_OPS_H +#define __X86EMU_OPS_H + +extern void (*x86emu_optab[0x100])(u8 op1); +extern void (*x86emu_optab2[0x100])(u8 op2); + +#endif /* __X86EMU_OPS_H */ diff --git a/cfe/cfe/x86emu/x86emu/ops_protos.h b/cfe/cfe/x86emu/x86emu/ops_protos.h new file mode 100644 index 0000000..8787c5a --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/ops_protos.h @@ -0,0 +1,277 @@ + +#define OPPROTO(x) void x(u8) + +OPPROTO(x86emuOp_illegal_op); +OPPROTO(x86emuOp_add_byte_RM_R); +OPPROTO(x86emuOp_add_word_RM_R); +OPPROTO(x86emuOp_add_byte_R_RM); +OPPROTO(x86emuOp_add_word_R_RM); +OPPROTO(x86emuOp_add_byte_AL_IMM); +OPPROTO(x86emuOp_add_word_AX_IMM); +OPPROTO(x86emuOp_push_ES); +OPPROTO(x86emuOp_pop_ES); +OPPROTO(x86emuOp_or_byte_RM_R); +OPPROTO(x86emuOp_or_word_RM_R); +OPPROTO(x86emuOp_or_byte_R_RM); +OPPROTO(x86emuOp_or_word_R_RM); +OPPROTO(x86emuOp_or_byte_AL_IMM); +OPPROTO(x86emuOp_or_word_AX_IMM); +OPPROTO(x86emuOp_push_CS); +OPPROTO(x86emuOp_two_byte); +OPPROTO(x86emuOp_adc_byte_RM_R); +OPPROTO(x86emuOp_adc_word_RM_R); +OPPROTO(x86emuOp_adc_byte_R_RM); +OPPROTO(x86emuOp_adc_word_R_RM); +OPPROTO(x86emuOp_adc_byte_AL_IMM); +OPPROTO(x86emuOp_adc_word_AX_IMM); +OPPROTO(x86emuOp_push_SS); +OPPROTO(x86emuOp_pop_SS); +OPPROTO(x86emuOp_sbb_byte_RM_R); +OPPROTO(x86emuOp_sbb_word_RM_R); +OPPROTO(x86emuOp_sbb_byte_R_RM); +OPPROTO(x86emuOp_sbb_word_R_RM); +OPPROTO(x86emuOp_sbb_byte_AL_IMM); +OPPROTO(x86emuOp_sbb_word_AX_IMM); +OPPROTO(x86emuOp_push_DS); +OPPROTO(x86emuOp_pop_DS); +OPPROTO(x86emuOp_and_byte_RM_R); +OPPROTO(x86emuOp_and_word_RM_R); +OPPROTO(x86emuOp_and_byte_R_RM); +OPPROTO(x86emuOp_and_word_R_RM); +OPPROTO(x86emuOp_and_byte_AL_IMM); +OPPROTO(x86emuOp_and_word_AX_IMM); +OPPROTO(x86emuOp_segovr_ES); +OPPROTO(x86emuOp_daa); +OPPROTO(x86emuOp_sub_byte_RM_R); +OPPROTO(x86emuOp_sub_word_RM_R); +OPPROTO(x86emuOp_sub_byte_R_RM); +OPPROTO(x86emuOp_sub_word_R_RM); +OPPROTO(x86emuOp_sub_byte_AL_IMM); +OPPROTO(x86emuOp_sub_word_AX_IMM); +OPPROTO(x86emuOp_segovr_CS); +OPPROTO(x86emuOp_das); +OPPROTO(x86emuOp_xor_byte_RM_R); +OPPROTO(x86emuOp_xor_word_RM_R); +OPPROTO(x86emuOp_xor_byte_R_RM); +OPPROTO(x86emuOp_xor_word_R_RM); +OPPROTO(x86emuOp_xor_byte_AL_IMM); +OPPROTO(x86emuOp_xor_word_AX_IMM); +OPPROTO(x86emuOp_segovr_SS); +OPPROTO(x86emuOp_aaa); +OPPROTO(x86emuOp_cmp_byte_RM_R); +OPPROTO(x86emuOp_cmp_word_RM_R); +OPPROTO(x86emuOp_cmp_byte_R_RM); +OPPROTO(x86emuOp_cmp_word_R_RM); +OPPROTO(x86emuOp_cmp_byte_AL_IMM); +OPPROTO(x86emuOp_cmp_word_AX_IMM); +OPPROTO(x86emuOp_segovr_DS); +OPPROTO(x86emuOp_aas); +OPPROTO(x86emuOp_inc_AX); +OPPROTO(x86emuOp_inc_CX); +OPPROTO(x86emuOp_inc_DX); +OPPROTO(x86emuOp_inc_BX); +OPPROTO(x86emuOp_inc_SP); +OPPROTO(x86emuOp_inc_BP); +OPPROTO(x86emuOp_inc_SI); +OPPROTO(x86emuOp_inc_DI); +OPPROTO(x86emuOp_dec_AX); +OPPROTO(x86emuOp_dec_CX); +OPPROTO(x86emuOp_dec_DX); +OPPROTO(x86emuOp_dec_BX); +OPPROTO(x86emuOp_dec_SP); +OPPROTO(x86emuOp_dec_BP); +OPPROTO(x86emuOp_dec_SI); +OPPROTO(x86emuOp_dec_DI); +OPPROTO(x86emuOp_push_AX); +OPPROTO(x86emuOp_push_CX); +OPPROTO(x86emuOp_push_DX); +OPPROTO(x86emuOp_push_BX); +OPPROTO(x86emuOp_push_SP); +OPPROTO(x86emuOp_push_BP); +OPPROTO(x86emuOp_push_SI); +OPPROTO(x86emuOp_push_DI); +OPPROTO(x86emuOp_pop_AX); +OPPROTO(x86emuOp_pop_CX); +OPPROTO(x86emuOp_pop_DX); +OPPROTO(x86emuOp_pop_BX); +OPPROTO(x86emuOp_pop_SP); +OPPROTO(x86emuOp_pop_BP); +OPPROTO(x86emuOp_pop_SI); +OPPROTO(x86emuOp_pop_DI); +OPPROTO(x86emuOp_push_all); +OPPROTO(x86emuOp_pop_all); +OPPROTO(x86emuOp_segovr_FS); +OPPROTO(x86emuOp_segovr_GS); +OPPROTO(x86emuOp_prefix_data); +OPPROTO(x86emuOp_prefix_addr); +OPPROTO(x86emuOp_push_word_IMM); +OPPROTO(x86emuOp_imul_word_IMM); +OPPROTO(x86emuOp_push_byte_IMM); +OPPROTO(x86emuOp_imul_byte_IMM); +OPPROTO(x86emuOp_ins_byte); +OPPROTO(x86emuOp_ins_word); +OPPROTO(x86emuOp_outs_byte); +OPPROTO(x86emuOp_outs_word); +OPPROTO(x86emuOp_jump_near_O); +OPPROTO(x86emuOp_jump_near_NO); +OPPROTO(x86emuOp_jump_near_B); +OPPROTO(x86emuOp_jump_near_NB); +OPPROTO(x86emuOp_jump_near_Z); +OPPROTO(x86emuOp_jump_near_NZ); +OPPROTO(x86emuOp_jump_near_BE); +OPPROTO(x86emuOp_jump_near_NBE); +OPPROTO(x86emuOp_jump_near_S); +OPPROTO(x86emuOp_jump_near_NS); +OPPROTO(x86emuOp_jump_near_P); +OPPROTO(x86emuOp_jump_near_NP); +OPPROTO(x86emuOp_jump_near_L); +OPPROTO(x86emuOp_jump_near_NL); +OPPROTO(x86emuOp_jump_near_LE); +OPPROTO(x86emuOp_jump_near_NLE); +OPPROTO(x86emuOp_opc80_byte_RM_IMM); +OPPROTO(x86emuOp_opc81_word_RM_IMM); +OPPROTO(x86emuOp_opc82_byte_RM_IMM); +OPPROTO(x86emuOp_opc83_word_RM_IMM); +OPPROTO(x86emuOp_test_byte_RM_R); +OPPROTO(x86emuOp_test_word_RM_R); +OPPROTO(x86emuOp_xchg_byte_RM_R); +OPPROTO(x86emuOp_xchg_word_RM_R); +OPPROTO(x86emuOp_mov_byte_RM_R); +OPPROTO(x86emuOp_mov_word_RM_R); +OPPROTO(x86emuOp_mov_byte_R_RM); +OPPROTO(x86emuOp_mov_word_R_RM); +OPPROTO(x86emuOp_mov_word_RM_SR); +OPPROTO(x86emuOp_lea_word_R_M); +OPPROTO(x86emuOp_mov_word_SR_RM); +OPPROTO(x86emuOp_pop_RM); +OPPROTO(x86emuOp_nop); +OPPROTO(x86emuOp_xchg_word_AX_CX); +OPPROTO(x86emuOp_xchg_word_AX_DX); +OPPROTO(x86emuOp_xchg_word_AX_BX); +OPPROTO(x86emuOp_xchg_word_AX_SP); +OPPROTO(x86emuOp_xchg_word_AX_BP); +OPPROTO(x86emuOp_xchg_word_AX_SI); +OPPROTO(x86emuOp_xchg_word_AX_DI); +OPPROTO(x86emuOp_cbw); +OPPROTO(x86emuOp_cwd); +OPPROTO(x86emuOp_call_far_IMM); +OPPROTO(x86emuOp_wait); +OPPROTO(x86emuOp_pushf_word); +OPPROTO(x86emuOp_popf_word); +OPPROTO(x86emuOp_sahf); +OPPROTO(x86emuOp_lahf); +OPPROTO(x86emuOp_mov_AL_M_IMM); +OPPROTO(x86emuOp_mov_AX_M_IMM); +OPPROTO(x86emuOp_mov_M_AL_IMM); +OPPROTO(x86emuOp_mov_M_AX_IMM); +OPPROTO(x86emuOp_movs_byte); +OPPROTO(x86emuOp_movs_word); +OPPROTO(x86emuOp_cmps_byte); +OPPROTO(x86emuOp_cmps_word); +OPPROTO(x86emuOp_test_AL_IMM); +OPPROTO(x86emuOp_test_AX_IMM); +OPPROTO(x86emuOp_stos_byte); +OPPROTO(x86emuOp_stos_word); +OPPROTO(x86emuOp_lods_byte); +OPPROTO(x86emuOp_lods_word); +OPPROTO(x86emuOp_scas_byte); +OPPROTO(x86emuOp_scas_word); +OPPROTO(x86emuOp_mov_byte_AL_IMM); +OPPROTO(x86emuOp_mov_byte_CL_IMM); +OPPROTO(x86emuOp_mov_byte_DL_IMM); +OPPROTO(x86emuOp_mov_byte_BL_IMM); +OPPROTO(x86emuOp_mov_byte_AH_IMM); +OPPROTO(x86emuOp_mov_byte_CH_IMM); +OPPROTO(x86emuOp_mov_byte_DH_IMM); +OPPROTO(x86emuOp_mov_byte_BH_IMM); +OPPROTO(x86emuOp_mov_word_AX_IMM); +OPPROTO(x86emuOp_mov_word_CX_IMM); +OPPROTO(x86emuOp_mov_word_DX_IMM); +OPPROTO(x86emuOp_mov_word_BX_IMM); +OPPROTO(x86emuOp_mov_word_SP_IMM); +OPPROTO(x86emuOp_mov_word_BP_IMM); +OPPROTO(x86emuOp_mov_word_SI_IMM); +OPPROTO(x86emuOp_mov_word_DI_IMM); +OPPROTO(x86emuOp_opcC0_byte_RM_MEM); +OPPROTO(x86emuOp_opcC1_word_RM_MEM); +OPPROTO(x86emuOp_ret_near_IMM); +OPPROTO(x86emuOp_ret_near); +OPPROTO(x86emuOp_les_R_IMM); +OPPROTO(x86emuOp_lds_R_IMM); +OPPROTO(x86emuOp_mov_byte_RM_IMM); +OPPROTO(x86emuOp_mov_word_RM_IMM); +OPPROTO(x86emuOp_enter); +OPPROTO(x86emuOp_leave); +OPPROTO(x86emuOp_ret_far_IMM); +OPPROTO(x86emuOp_ret_far); +OPPROTO(x86emuOp_int3); +OPPROTO(x86emuOp_int_IMM); +OPPROTO(x86emuOp_into); +OPPROTO(x86emuOp_iret); +OPPROTO(x86emuOp_opcD0_byte_RM_1); +OPPROTO(x86emuOp_opcD1_word_RM_1); +OPPROTO(x86emuOp_opcD2_byte_RM_CL); +OPPROTO(x86emuOp_opcD3_word_RM_CL); +OPPROTO(x86emuOp_aam); +OPPROTO(x86emuOp_aad); +OPPROTO(x86emuOp_xlat); +OPPROTO(x86emuOp_loopne); +OPPROTO(x86emuOp_loope); +OPPROTO(x86emuOp_loop); +OPPROTO(x86emuOp_jcxz); +OPPROTO(x86emuOp_in_byte_AL_IMM); +OPPROTO(x86emuOp_in_word_AX_IMM); +OPPROTO(x86emuOp_out_byte_IMM_AL); +OPPROTO(x86emuOp_out_word_IMM_AX); +OPPROTO(x86emuOp_call_near_IMM); +OPPROTO(x86emuOp_jump_near_IMM); +OPPROTO(x86emuOp_jump_far_IMM); +OPPROTO(x86emuOp_jump_byte_IMM); +OPPROTO(x86emuOp_in_byte_AL_DX); +OPPROTO(x86emuOp_in_word_AX_DX); +OPPROTO(x86emuOp_out_byte_DX_AL); +OPPROTO(x86emuOp_out_word_DX_AX); +OPPROTO(x86emuOp_lock); +OPPROTO(x86emuOp_repne); +OPPROTO(x86emuOp_repe); +OPPROTO(x86emuOp_halt); +OPPROTO(x86emuOp_cmc); +OPPROTO(x86emuOp_opcF6_byte_RM); +OPPROTO(x86emuOp_opcF7_word_RM); +OPPROTO(x86emuOp_clc); +OPPROTO(x86emuOp_stc); +OPPROTO(x86emuOp_cli); +OPPROTO(x86emuOp_sti); +OPPROTO(x86emuOp_cld); +OPPROTO(x86emuOp_std); +OPPROTO(x86emuOp_opcFE_byte_RM); +OPPROTO(x86emuOp_opcFF_word_RM); + + +OPPROTO(x86emuOp2_illegal_op); +OPPROTO(x86emuOp2_long_jump); +OPPROTO(x86emuOp2_set_byte); +OPPROTO(x86emuOp2_push_FS); +OPPROTO(x86emuOp2_pop_FS); +OPPROTO(x86emuOp2_bt_R); +OPPROTO(x86emuOp2_shld_IMM); +OPPROTO(x86emuOp2_shld_CL); +OPPROTO(x86emuOp2_push_GS); +OPPROTO(x86emuOp2_pop_GS); +OPPROTO(x86emuOp2_bts_R); +OPPROTO(x86emuOp2_shrd_IMM); +OPPROTO(x86emuOp2_shrd_CL); +OPPROTO(x86emuOp2_imul_R_RM); +OPPROTO(x86emuOp2_lss_R_IMM); +OPPROTO(x86emuOp2_btr_R); +OPPROTO(x86emuOp2_lfs_R_IMM); +OPPROTO(x86emuOp2_lgs_R_IMM); +OPPROTO(x86emuOp2_movzx_byte_R_RM); +OPPROTO(x86emuOp2_movzx_word_R_RM); +OPPROTO(x86emuOp2_btX_I); +OPPROTO(x86emuOp2_btc_R); +OPPROTO(x86emuOp2_bsf); +OPPROTO(x86emuOp2_bsr); +OPPROTO(x86emuOp2_movsx_byte_R_RM); +OPPROTO(x86emuOp2_movsx_word_R_R); +OPPROTO(x86emuOp2_movsx_word_R_RM); diff --git a/cfe/cfe/x86emu/x86emu/prim_asm.h b/cfe/cfe/x86emu/x86emu/prim_asm.h new file mode 100644 index 0000000..4fa8d55 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/prim_asm.h @@ -0,0 +1,971 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: Watcom C++ 10.6 or later +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Inline assembler versions of the primitive operand +* functions for faster performance. At the moment this is +* x86 inline assembler, but these functions could be replaced +* with native inline assembler for each supported processor +* platform. +* +****************************************************************************/ +/* $XFree86: xc/extras/x86emu/src/x86emu/x86emu/prim_asm.h,v 1.3 2000/04/19 15:48:15 tsi Exp $ */ + +#ifndef __X86EMU_PRIM_ASM_H +#define __X86EMU_PRIM_ASM_H + +#ifdef __WATCOMC__ + +#ifndef VALIDATE +#define __HAVE_INLINE_ASSEMBLER__ +#endif + +u32 get_flags_asm(void); +#pragma aux get_flags_asm = \ + "pushf" \ + "pop eax" \ + value [eax] \ + modify exact [eax]; + +u16 aaa_word_asm(u32 *flags,u16 d); +#pragma aux aaa_word_asm = \ + "push [edi]" \ + "popf" \ + "aaa" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] \ + value [ax] \ + modify exact [ax]; + +u16 aas_word_asm(u32 *flags,u16 d); +#pragma aux aas_word_asm = \ + "push [edi]" \ + "popf" \ + "aas" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] \ + value [ax] \ + modify exact [ax]; + +u16 aad_word_asm(u32 *flags,u16 d); +#pragma aux aad_word_asm = \ + "push [edi]" \ + "popf" \ + "aad" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] \ + value [ax] \ + modify exact [ax]; + +u16 aam_word_asm(u32 *flags,u8 d); +#pragma aux aam_word_asm = \ + "push [edi]" \ + "popf" \ + "aam" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] \ + value [ax] \ + modify exact [ax]; + +u8 adc_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux adc_byte_asm = \ + "push [edi]" \ + "popf" \ + "adc al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 adc_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux adc_word_asm = \ + "push [edi]" \ + "popf" \ + "adc ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 adc_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux adc_long_asm = \ + "push [edi]" \ + "popf" \ + "adc eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +u8 add_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux add_byte_asm = \ + "push [edi]" \ + "popf" \ + "add al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 add_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux add_word_asm = \ + "push [edi]" \ + "popf" \ + "add ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 add_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux add_long_asm = \ + "push [edi]" \ + "popf" \ + "add eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +u8 and_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux and_byte_asm = \ + "push [edi]" \ + "popf" \ + "and al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 and_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux and_word_asm = \ + "push [edi]" \ + "popf" \ + "and ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 and_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux and_long_asm = \ + "push [edi]" \ + "popf" \ + "and eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +u8 cmp_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux cmp_byte_asm = \ + "push [edi]" \ + "popf" \ + "cmp al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 cmp_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux cmp_word_asm = \ + "push [edi]" \ + "popf" \ + "cmp ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 cmp_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux cmp_long_asm = \ + "push [edi]" \ + "popf" \ + "cmp eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +u8 daa_byte_asm(u32 *flags,u8 d); +#pragma aux daa_byte_asm = \ + "push [edi]" \ + "popf" \ + "daa" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] \ + value [al] \ + modify exact [al]; + +u8 das_byte_asm(u32 *flags,u8 d); +#pragma aux das_byte_asm = \ + "push [edi]" \ + "popf" \ + "das" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] \ + value [al] \ + modify exact [al]; + +u8 dec_byte_asm(u32 *flags,u8 d); +#pragma aux dec_byte_asm = \ + "push [edi]" \ + "popf" \ + "dec al" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] \ + value [al] \ + modify exact [al]; + +u16 dec_word_asm(u32 *flags,u16 d); +#pragma aux dec_word_asm = \ + "push [edi]" \ + "popf" \ + "dec ax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] \ + value [ax] \ + modify exact [ax]; + +u32 dec_long_asm(u32 *flags,u32 d); +#pragma aux dec_long_asm = \ + "push [edi]" \ + "popf" \ + "dec eax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] \ + value [eax] \ + modify exact [eax]; + +u8 inc_byte_asm(u32 *flags,u8 d); +#pragma aux inc_byte_asm = \ + "push [edi]" \ + "popf" \ + "inc al" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] \ + value [al] \ + modify exact [al]; + +u16 inc_word_asm(u32 *flags,u16 d); +#pragma aux inc_word_asm = \ + "push [edi]" \ + "popf" \ + "inc ax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] \ + value [ax] \ + modify exact [ax]; + +u32 inc_long_asm(u32 *flags,u32 d); +#pragma aux inc_long_asm = \ + "push [edi]" \ + "popf" \ + "inc eax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] \ + value [eax] \ + modify exact [eax]; + +u8 or_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux or_byte_asm = \ + "push [edi]" \ + "popf" \ + "or al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 or_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux or_word_asm = \ + "push [edi]" \ + "popf" \ + "or ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 or_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux or_long_asm = \ + "push [edi]" \ + "popf" \ + "or eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +u8 neg_byte_asm(u32 *flags,u8 d); +#pragma aux neg_byte_asm = \ + "push [edi]" \ + "popf" \ + "neg al" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] \ + value [al] \ + modify exact [al]; + +u16 neg_word_asm(u32 *flags,u16 d); +#pragma aux neg_word_asm = \ + "push [edi]" \ + "popf" \ + "neg ax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] \ + value [ax] \ + modify exact [ax]; + +u32 neg_long_asm(u32 *flags,u32 d); +#pragma aux neg_long_asm = \ + "push [edi]" \ + "popf" \ + "neg eax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] \ + value [eax] \ + modify exact [eax]; + +u8 not_byte_asm(u32 *flags,u8 d); +#pragma aux not_byte_asm = \ + "push [edi]" \ + "popf" \ + "not al" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] \ + value [al] \ + modify exact [al]; + +u16 not_word_asm(u32 *flags,u16 d); +#pragma aux not_word_asm = \ + "push [edi]" \ + "popf" \ + "not ax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] \ + value [ax] \ + modify exact [ax]; + +u32 not_long_asm(u32 *flags,u32 d); +#pragma aux not_long_asm = \ + "push [edi]" \ + "popf" \ + "not eax" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] \ + value [eax] \ + modify exact [eax]; + +u8 rcl_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux rcl_byte_asm = \ + "push [edi]" \ + "popf" \ + "rcl al,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [cl] \ + value [al] \ + modify exact [al cl]; + +u16 rcl_word_asm(u32 *flags,u16 d, u8 s); +#pragma aux rcl_word_asm = \ + "push [edi]" \ + "popf" \ + "rcl ax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [cl] \ + value [ax] \ + modify exact [ax cl]; + +u32 rcl_long_asm(u32 *flags,u32 d, u8 s); +#pragma aux rcl_long_asm = \ + "push [edi]" \ + "popf" \ + "rcl eax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [cl] \ + value [eax] \ + modify exact [eax cl]; + +u8 rcr_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux rcr_byte_asm = \ + "push [edi]" \ + "popf" \ + "rcr al,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [cl] \ + value [al] \ + modify exact [al cl]; + +u16 rcr_word_asm(u32 *flags,u16 d, u8 s); +#pragma aux rcr_word_asm = \ + "push [edi]" \ + "popf" \ + "rcr ax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [cl] \ + value [ax] \ + modify exact [ax cl]; + +u32 rcr_long_asm(u32 *flags,u32 d, u8 s); +#pragma aux rcr_long_asm = \ + "push [edi]" \ + "popf" \ + "rcr eax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [cl] \ + value [eax] \ + modify exact [eax cl]; + +u8 rol_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux rol_byte_asm = \ + "push [edi]" \ + "popf" \ + "rol al,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [cl] \ + value [al] \ + modify exact [al cl]; + +u16 rol_word_asm(u32 *flags,u16 d, u8 s); +#pragma aux rol_word_asm = \ + "push [edi]" \ + "popf" \ + "rol ax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [cl] \ + value [ax] \ + modify exact [ax cl]; + +u32 rol_long_asm(u32 *flags,u32 d, u8 s); +#pragma aux rol_long_asm = \ + "push [edi]" \ + "popf" \ + "rol eax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [cl] \ + value [eax] \ + modify exact [eax cl]; + +u8 ror_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux ror_byte_asm = \ + "push [edi]" \ + "popf" \ + "ror al,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [cl] \ + value [al] \ + modify exact [al cl]; + +u16 ror_word_asm(u32 *flags,u16 d, u8 s); +#pragma aux ror_word_asm = \ + "push [edi]" \ + "popf" \ + "ror ax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [cl] \ + value [ax] \ + modify exact [ax cl]; + +u32 ror_long_asm(u32 *flags,u32 d, u8 s); +#pragma aux ror_long_asm = \ + "push [edi]" \ + "popf" \ + "ror eax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [cl] \ + value [eax] \ + modify exact [eax cl]; + +u8 shl_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux shl_byte_asm = \ + "push [edi]" \ + "popf" \ + "shl al,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [cl] \ + value [al] \ + modify exact [al cl]; + +u16 shl_word_asm(u32 *flags,u16 d, u8 s); +#pragma aux shl_word_asm = \ + "push [edi]" \ + "popf" \ + "shl ax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [cl] \ + value [ax] \ + modify exact [ax cl]; + +u32 shl_long_asm(u32 *flags,u32 d, u8 s); +#pragma aux shl_long_asm = \ + "push [edi]" \ + "popf" \ + "shl eax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [cl] \ + value [eax] \ + modify exact [eax cl]; + +u8 shr_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux shr_byte_asm = \ + "push [edi]" \ + "popf" \ + "shr al,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [cl] \ + value [al] \ + modify exact [al cl]; + +u16 shr_word_asm(u32 *flags,u16 d, u8 s); +#pragma aux shr_word_asm = \ + "push [edi]" \ + "popf" \ + "shr ax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [cl] \ + value [ax] \ + modify exact [ax cl]; + +u32 shr_long_asm(u32 *flags,u32 d, u8 s); +#pragma aux shr_long_asm = \ + "push [edi]" \ + "popf" \ + "shr eax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [cl] \ + value [eax] \ + modify exact [eax cl]; + +u8 sar_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux sar_byte_asm = \ + "push [edi]" \ + "popf" \ + "sar al,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [cl] \ + value [al] \ + modify exact [al cl]; + +u16 sar_word_asm(u32 *flags,u16 d, u8 s); +#pragma aux sar_word_asm = \ + "push [edi]" \ + "popf" \ + "sar ax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [cl] \ + value [ax] \ + modify exact [ax cl]; + +u32 sar_long_asm(u32 *flags,u32 d, u8 s); +#pragma aux sar_long_asm = \ + "push [edi]" \ + "popf" \ + "sar eax,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [cl] \ + value [eax] \ + modify exact [eax cl]; + +u16 shld_word_asm(u32 *flags,u16 d, u16 fill, u8 s); +#pragma aux shld_word_asm = \ + "push [edi]" \ + "popf" \ + "shld ax,dx,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [dx] [cl] \ + value [ax] \ + modify exact [ax dx cl]; + +u32 shld_long_asm(u32 *flags,u32 d, u32 fill, u8 s); +#pragma aux shld_long_asm = \ + "push [edi]" \ + "popf" \ + "shld eax,edx,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [edx] [cl] \ + value [eax] \ + modify exact [eax edx cl]; + +u16 shrd_word_asm(u32 *flags,u16 d, u16 fill, u8 s); +#pragma aux shrd_word_asm = \ + "push [edi]" \ + "popf" \ + "shrd ax,dx,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [dx] [cl] \ + value [ax] \ + modify exact [ax dx cl]; + +u32 shrd_long_asm(u32 *flags,u32 d, u32 fill, u8 s); +#pragma aux shrd_long_asm = \ + "push [edi]" \ + "popf" \ + "shrd eax,edx,cl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [edx] [cl] \ + value [eax] \ + modify exact [eax edx cl]; + +u8 sbb_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux sbb_byte_asm = \ + "push [edi]" \ + "popf" \ + "sbb al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 sbb_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux sbb_word_asm = \ + "push [edi]" \ + "popf" \ + "sbb ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 sbb_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux sbb_long_asm = \ + "push [edi]" \ + "popf" \ + "sbb eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +u8 sub_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux sub_byte_asm = \ + "push [edi]" \ + "popf" \ + "sub al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 sub_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux sub_word_asm = \ + "push [edi]" \ + "popf" \ + "sub ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 sub_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux sub_long_asm = \ + "push [edi]" \ + "popf" \ + "sub eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +void test_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux test_byte_asm = \ + "push [edi]" \ + "popf" \ + "test al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + modify exact [al bl]; + +void test_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux test_word_asm = \ + "push [edi]" \ + "popf" \ + "test ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + modify exact [ax bx]; + +void test_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux test_long_asm = \ + "push [edi]" \ + "popf" \ + "test eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + modify exact [eax ebx]; + +u8 xor_byte_asm(u32 *flags,u8 d, u8 s); +#pragma aux xor_byte_asm = \ + "push [edi]" \ + "popf" \ + "xor al,bl" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [al] [bl] \ + value [al] \ + modify exact [al bl]; + +u16 xor_word_asm(u32 *flags,u16 d, u16 s); +#pragma aux xor_word_asm = \ + "push [edi]" \ + "popf" \ + "xor ax,bx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [ax] [bx] \ + value [ax] \ + modify exact [ax bx]; + +u32 xor_long_asm(u32 *flags,u32 d, u32 s); +#pragma aux xor_long_asm = \ + "push [edi]" \ + "popf" \ + "xor eax,ebx" \ + "pushf" \ + "pop [edi]" \ + parm [edi] [eax] [ebx] \ + value [eax] \ + modify exact [eax ebx]; + +void imul_byte_asm(u32 *flags,u16 *ax,u8 d,u8 s); +#pragma aux imul_byte_asm = \ + "push [edi]" \ + "popf" \ + "imul bl" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],ax" \ + parm [edi] [esi] [al] [bl] \ + modify exact [esi ax bl]; + +void imul_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 d,u16 s); +#pragma aux imul_word_asm = \ + "push [edi]" \ + "popf" \ + "imul bx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],ax" \ + "mov [ecx],dx" \ + parm [edi] [esi] [ecx] [ax] [bx]\ + modify exact [esi edi ax bx dx]; + +void imul_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 d,u32 s); +#pragma aux imul_long_asm = \ + "push [edi]" \ + "popf" \ + "imul ebx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],eax" \ + "mov [ecx],edx" \ + parm [edi] [esi] [ecx] [eax] [ebx] \ + modify exact [esi edi eax ebx edx]; + +void mul_byte_asm(u32 *flags,u16 *ax,u8 d,u8 s); +#pragma aux mul_byte_asm = \ + "push [edi]" \ + "popf" \ + "mul bl" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],ax" \ + parm [edi] [esi] [al] [bl] \ + modify exact [esi ax bl]; + +void mul_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 d,u16 s); +#pragma aux mul_word_asm = \ + "push [edi]" \ + "popf" \ + "mul bx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],ax" \ + "mov [ecx],dx" \ + parm [edi] [esi] [ecx] [ax] [bx]\ + modify exact [esi edi ax bx dx]; + +void mul_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 d,u32 s); +#pragma aux mul_long_asm = \ + "push [edi]" \ + "popf" \ + "mul ebx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],eax" \ + "mov [ecx],edx" \ + parm [edi] [esi] [ecx] [eax] [ebx] \ + modify exact [esi edi eax ebx edx]; + +void idiv_byte_asm(u32 *flags,u8 *al,u8 *ah,u16 d,u8 s); +#pragma aux idiv_byte_asm = \ + "push [edi]" \ + "popf" \ + "idiv bl" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],al" \ + "mov [ecx],ah" \ + parm [edi] [esi] [ecx] [ax] [bl]\ + modify exact [esi edi ax bl]; + +void idiv_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 dlo,u16 dhi,u16 s); +#pragma aux idiv_word_asm = \ + "push [edi]" \ + "popf" \ + "idiv bx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],ax" \ + "mov [ecx],dx" \ + parm [edi] [esi] [ecx] [ax] [dx] [bx]\ + modify exact [esi edi ax dx bx]; + +void idiv_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 dlo,u32 dhi,u32 s); +#pragma aux idiv_long_asm = \ + "push [edi]" \ + "popf" \ + "idiv ebx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],eax" \ + "mov [ecx],edx" \ + parm [edi] [esi] [ecx] [eax] [edx] [ebx]\ + modify exact [esi edi eax edx ebx]; + +void div_byte_asm(u32 *flags,u8 *al,u8 *ah,u16 d,u8 s); +#pragma aux div_byte_asm = \ + "push [edi]" \ + "popf" \ + "div bl" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],al" \ + "mov [ecx],ah" \ + parm [edi] [esi] [ecx] [ax] [bl]\ + modify exact [esi edi ax bl]; + +void div_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 dlo,u16 dhi,u16 s); +#pragma aux div_word_asm = \ + "push [edi]" \ + "popf" \ + "div bx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],ax" \ + "mov [ecx],dx" \ + parm [edi] [esi] [ecx] [ax] [dx] [bx]\ + modify exact [esi edi ax dx bx]; + +void div_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 dlo,u32 dhi,u32 s); +#pragma aux div_long_asm = \ + "push [edi]" \ + "popf" \ + "div ebx" \ + "pushf" \ + "pop [edi]" \ + "mov [esi],eax" \ + "mov [ecx],edx" \ + parm [edi] [esi] [ecx] [eax] [edx] [ebx]\ + modify exact [esi edi eax edx ebx]; + +#endif + +#endif /* __X86EMU_PRIM_ASM_H */ diff --git a/cfe/cfe/x86emu/x86emu/prim_ops.h b/cfe/cfe/x86emu/x86emu/prim_ops.h new file mode 100644 index 0000000..1633fe1 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/prim_ops.h @@ -0,0 +1,231 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for primitive operation functions. +* +****************************************************************************/ + +#ifndef __X86EMU_PRIM_OPS_H +#define __X86EMU_PRIM_OPS_H + +#include "x86emu/prim_asm.h" + +#ifdef __cplusplus +extern "C" { /* Use "C" linkage when in C++ mode */ +#endif + +u16 aaa_word (u16 d); +u16 aas_word (u16 d); +u16 aad_word (u16 d); +u16 aam_word (u8 d); +u8 adc_byte (u8 d, u8 s); +u16 adc_word (u16 d, u16 s); +u32 adc_long (u32 d, u32 s); +u8 add_byte (u8 d, u8 s); +u16 add_word (u16 d, u16 s); +u32 add_long (u32 d, u32 s); +u8 and_byte (u8 d, u8 s); +u16 and_word (u16 d, u16 s); +u32 and_long (u32 d, u32 s); +u8 cmp_byte (u8 d, u8 s); +u16 cmp_word (u16 d, u16 s); +u32 cmp_long (u32 d, u32 s); +u8 daa_byte (u8 d); +u8 das_byte (u8 d); +u8 dec_byte (u8 d); +u16 dec_word (u16 d); +u32 dec_long (u32 d); +u8 inc_byte (u8 d); +u16 inc_word (u16 d); +u32 inc_long (u32 d); +u8 or_byte (u8 d, u8 s); +u16 or_word (u16 d, u16 s); +u32 or_long (u32 d, u32 s); +u8 neg_byte (u8 s); +u16 neg_word (u16 s); +u32 neg_long (u32 s); +u8 not_byte (u8 s); +u16 not_word (u16 s); +u32 not_long (u32 s); +u8 rcl_byte (u8 d, u8 s); +u16 rcl_word (u16 d, u8 s); +u32 rcl_long (u32 d, u8 s); +u8 rcr_byte (u8 d, u8 s); +u16 rcr_word (u16 d, u8 s); +u32 rcr_long (u32 d, u8 s); +u8 rol_byte (u8 d, u8 s); +u16 rol_word (u16 d, u8 s); +u32 rol_long (u32 d, u8 s); +u8 ror_byte (u8 d, u8 s); +u16 ror_word (u16 d, u8 s); +u32 ror_long (u32 d, u8 s); +u8 shl_byte (u8 d, u8 s); +u16 shl_word (u16 d, u8 s); +u32 shl_long (u32 d, u8 s); +u8 shr_byte (u8 d, u8 s); +u16 shr_word (u16 d, u8 s); +u32 shr_long (u32 d, u8 s); +u8 sar_byte (u8 d, u8 s); +u16 sar_word (u16 d, u8 s); +u32 sar_long (u32 d, u8 s); +u16 shld_word (u16 d, u16 fill, u8 s); +u32 shld_long (u32 d, u32 fill, u8 s); +u16 shrd_word (u16 d, u16 fill, u8 s); +u32 shrd_long (u32 d, u32 fill, u8 s); +u8 sbb_byte (u8 d, u8 s); +u16 sbb_word (u16 d, u16 s); +u32 sbb_long (u32 d, u32 s); +u8 sub_byte (u8 d, u8 s); +u16 sub_word (u16 d, u16 s); +u32 sub_long (u32 d, u32 s); +void test_byte (u8 d, u8 s); +void test_word (u16 d, u16 s); +void test_long (u32 d, u32 s); +u8 xor_byte (u8 d, u8 s); +u16 xor_word (u16 d, u16 s); +u32 xor_long (u32 d, u32 s); +void imul_byte (u8 s); +void imul_word (u16 s); +void imul_long (u32 s); +void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s); +void mul_byte (u8 s); +void mul_word (u16 s); +void mul_long (u32 s); +void idiv_byte (u8 s); +void idiv_word (u16 s); +void idiv_long (u32 s); +void div_byte (u8 s); +void div_word (u16 s); +void div_long (u32 s); +void ins (int size); +void outs (int size); +u16 mem_access_word (int addr); +void push_word (u16 w); +void push_long (u32 w); +u16 pop_word (void); +u32 pop_long (void); + +#if defined(__HAVE_INLINE_ASSEMBLER__) && !defined(PRIM_OPS_NO_REDEFINE_ASM) + +#define aaa_word(d) aaa_word_asm(&M.x86.R_EFLG,d) +#define aas_word(d) aas_word_asm(&M.x86.R_EFLG,d) +#define aad_word(d) aad_word_asm(&M.x86.R_EFLG,d) +#define aam_word(d) aam_word_asm(&M.x86.R_EFLG,d) +#define adc_byte(d,s) adc_byte_asm(&M.x86.R_EFLG,d,s) +#define adc_word(d,s) adc_word_asm(&M.x86.R_EFLG,d,s) +#define adc_long(d,s) adc_long_asm(&M.x86.R_EFLG,d,s) +#define add_byte(d,s) add_byte_asm(&M.x86.R_EFLG,d,s) +#define add_word(d,s) add_word_asm(&M.x86.R_EFLG,d,s) +#define add_long(d,s) add_long_asm(&M.x86.R_EFLG,d,s) +#define and_byte(d,s) and_byte_asm(&M.x86.R_EFLG,d,s) +#define and_word(d,s) and_word_asm(&M.x86.R_EFLG,d,s) +#define and_long(d,s) and_long_asm(&M.x86.R_EFLG,d,s) +#define cmp_byte(d,s) cmp_byte_asm(&M.x86.R_EFLG,d,s) +#define cmp_word(d,s) cmp_word_asm(&M.x86.R_EFLG,d,s) +#define cmp_long(d,s) cmp_long_asm(&M.x86.R_EFLG,d,s) +#define daa_byte(d) daa_byte_asm(&M.x86.R_EFLG,d) +#define das_byte(d) das_byte_asm(&M.x86.R_EFLG,d) +#define dec_byte(d) dec_byte_asm(&M.x86.R_EFLG,d) +#define dec_word(d) dec_word_asm(&M.x86.R_EFLG,d) +#define dec_long(d) dec_long_asm(&M.x86.R_EFLG,d) +#define inc_byte(d) inc_byte_asm(&M.x86.R_EFLG,d) +#define inc_word(d) inc_word_asm(&M.x86.R_EFLG,d) +#define inc_long(d) inc_long_asm(&M.x86.R_EFLG,d) +#define or_byte(d,s) or_byte_asm(&M.x86.R_EFLG,d,s) +#define or_word(d,s) or_word_asm(&M.x86.R_EFLG,d,s) +#define or_long(d,s) or_long_asm(&M.x86.R_EFLG,d,s) +#define neg_byte(s) neg_byte_asm(&M.x86.R_EFLG,s) +#define neg_word(s) neg_word_asm(&M.x86.R_EFLG,s) +#define neg_long(s) neg_long_asm(&M.x86.R_EFLG,s) +#define not_byte(s) not_byte_asm(&M.x86.R_EFLG,s) +#define not_word(s) not_word_asm(&M.x86.R_EFLG,s) +#define not_long(s) not_long_asm(&M.x86.R_EFLG,s) +#define rcl_byte(d,s) rcl_byte_asm(&M.x86.R_EFLG,d,s) +#define rcl_word(d,s) rcl_word_asm(&M.x86.R_EFLG,d,s) +#define rcl_long(d,s) rcl_long_asm(&M.x86.R_EFLG,d,s) +#define rcr_byte(d,s) rcr_byte_asm(&M.x86.R_EFLG,d,s) +#define rcr_word(d,s) rcr_word_asm(&M.x86.R_EFLG,d,s) +#define rcr_long(d,s) rcr_long_asm(&M.x86.R_EFLG,d,s) +#define rol_byte(d,s) rol_byte_asm(&M.x86.R_EFLG,d,s) +#define rol_word(d,s) rol_word_asm(&M.x86.R_EFLG,d,s) +#define rol_long(d,s) rol_long_asm(&M.x86.R_EFLG,d,s) +#define ror_byte(d,s) ror_byte_asm(&M.x86.R_EFLG,d,s) +#define ror_word(d,s) ror_word_asm(&M.x86.R_EFLG,d,s) +#define ror_long(d,s) ror_long_asm(&M.x86.R_EFLG,d,s) +#define shl_byte(d,s) shl_byte_asm(&M.x86.R_EFLG,d,s) +#define shl_word(d,s) shl_word_asm(&M.x86.R_EFLG,d,s) +#define shl_long(d,s) shl_long_asm(&M.x86.R_EFLG,d,s) +#define shr_byte(d,s) shr_byte_asm(&M.x86.R_EFLG,d,s) +#define shr_word(d,s) shr_word_asm(&M.x86.R_EFLG,d,s) +#define shr_long(d,s) shr_long_asm(&M.x86.R_EFLG,d,s) +#define sar_byte(d,s) sar_byte_asm(&M.x86.R_EFLG,d,s) +#define sar_word(d,s) sar_word_asm(&M.x86.R_EFLG,d,s) +#define sar_long(d,s) sar_long_asm(&M.x86.R_EFLG,d,s) +#define shld_word(d,fill,s) shld_word_asm(&M.x86.R_EFLG,d,fill,s) +#define shld_long(d,fill,s) shld_long_asm(&M.x86.R_EFLG,d,fill,s) +#define shrd_word(d,fill,s) shrd_word_asm(&M.x86.R_EFLG,d,fill,s) +#define shrd_long(d,fill,s) shrd_long_asm(&M.x86.R_EFLG,d,fill,s) +#define sbb_byte(d,s) sbb_byte_asm(&M.x86.R_EFLG,d,s) +#define sbb_word(d,s) sbb_word_asm(&M.x86.R_EFLG,d,s) +#define sbb_long(d,s) sbb_long_asm(&M.x86.R_EFLG,d,s) +#define sub_byte(d,s) sub_byte_asm(&M.x86.R_EFLG,d,s) +#define sub_word(d,s) sub_word_asm(&M.x86.R_EFLG,d,s) +#define sub_long(d,s) sub_long_asm(&M.x86.R_EFLG,d,s) +#define test_byte(d,s) test_byte_asm(&M.x86.R_EFLG,d,s) +#define test_word(d,s) test_word_asm(&M.x86.R_EFLG,d,s) +#define test_long(d,s) test_long_asm(&M.x86.R_EFLG,d,s) +#define xor_byte(d,s) xor_byte_asm(&M.x86.R_EFLG,d,s) +#define xor_word(d,s) xor_word_asm(&M.x86.R_EFLG,d,s) +#define xor_long(d,s) xor_long_asm(&M.x86.R_EFLG,d,s) +#define imul_byte(s) imul_byte_asm(&M.x86.R_EFLG,&M.x86.R_AX,M.x86.R_AL,s) +#define imul_word(s) imul_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,s) +#define imul_long(s) imul_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s) +#define imul_long_direct(res_lo,res_hi,d,s) imul_long_asm(&M.x86.R_EFLG,res_lo,res_hi,d,s) +#define mul_byte(s) mul_byte_asm(&M.x86.R_EFLG,&M.x86.R_AX,M.x86.R_AL,s) +#define mul_word(s) mul_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,s) +#define mul_long(s) mul_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s) +#define idiv_byte(s) idiv_byte_asm(&M.x86.R_EFLG,&M.x86.R_AL,&M.x86.R_AH,M.x86.R_AX,s) +#define idiv_word(s) idiv_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,M.x86.R_DX,s) +#define idiv_long(s) idiv_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,M.x86.R_EDX,s) +#define div_byte(s) div_byte_asm(&M.x86.R_EFLG,&M.x86.R_AL,&M.x86.R_AH,M.x86.R_AX,s) +#define div_word(s) div_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,M.x86.R_DX,s) +#define div_long(s) div_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,M.x86.R_EDX,s) + +#endif + +#ifdef __cplusplus +} /* End of "C" linkage for C++ */ +#endif + +#endif /* __X86EMU_PRIM_OPS_H */ diff --git a/cfe/cfe/x86emu/x86emu/regs.h b/cfe/cfe/x86emu/x86emu/regs.h new file mode 100644 index 0000000..b0a6231 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/regs.h @@ -0,0 +1,351 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for x86 register definitions. +* +****************************************************************************/ + +#ifndef __X86EMU_REGS_H +#define __X86EMU_REGS_H + +#ifdef __mips +#if defined(__MIPSEB) +#define __BIG_ENDIAN__ +#elif defined(__MIPSEL) +#define __LITTLE_ENDIAN__ +#else +#error "You must define either __MIPSEB or __MIPSEL" +#endif +#endif + +/*---------------------- Macros and type definitions ----------------------*/ + +#ifndef __mips +#pragma pack(1) +#endif + +/* + * General EAX, EBX, ECX, EDX type registers. Note that for + * portability, and speed, the issue of byte swapping is not addressed + * in the registers. All registers are stored in the default format + * available on the host machine. The only critical issue is that the + * registers should line up EXACTLY in the same manner as they do in + * the 386. That is: + * + * EAX & 0xff === AL + * EAX & 0xffff == AX + * + * etc. The result is that alot of the calculations can then be + * done using the native instruction set fully. + */ + +#ifdef __BIG_ENDIAN__ + +typedef struct { + u32 e_reg; + } I32_reg_t; + +typedef struct { + u16 filler0, x_reg; + } I16_reg_t; + +typedef struct { + u8 filler0, filler1, h_reg, l_reg; + } I8_reg_t; + +#else /* !__BIG_ENDIAN__ */ + +typedef struct { + u32 e_reg; + } I32_reg_t; + +typedef struct { + u16 x_reg; + } I16_reg_t; + +typedef struct { + u8 l_reg, h_reg; + } I8_reg_t; + +#endif /* BIG_ENDIAN */ + +typedef union { + I32_reg_t I32_reg; + I16_reg_t I16_reg; + I8_reg_t I8_reg; + } i386_general_register; + +struct i386_general_regs { + i386_general_register A, B, C, D; + }; + +typedef struct i386_general_regs Gen_reg_t; + +struct i386_special_regs { + i386_general_register SP, BP, SI, DI, IP; + u32 FLAGS; + }; + +/* + * Segment registers here represent the 16 bit quantities + * CS, DS, ES, SS. + */ + +struct i386_segment_regs { + u16 CS, DS, SS, ES, FS, GS; + }; + +/* 8 bit registers */ +#define R_AH gen.A.I8_reg.h_reg +#define R_AL gen.A.I8_reg.l_reg +#define R_BH gen.B.I8_reg.h_reg +#define R_BL gen.B.I8_reg.l_reg +#define R_CH gen.C.I8_reg.h_reg +#define R_CL gen.C.I8_reg.l_reg +#define R_DH gen.D.I8_reg.h_reg +#define R_DL gen.D.I8_reg.l_reg + +/* 16 bit registers */ +#define R_AX gen.A.I16_reg.x_reg +#define R_BX gen.B.I16_reg.x_reg +#define R_CX gen.C.I16_reg.x_reg +#define R_DX gen.D.I16_reg.x_reg + +/* 32 bit extended registers */ +#define R_EAX gen.A.I32_reg.e_reg +#define R_EBX gen.B.I32_reg.e_reg +#define R_ECX gen.C.I32_reg.e_reg +#define R_EDX gen.D.I32_reg.e_reg + +/* special registers */ +#define R_SP spc.SP.I16_reg.x_reg +#define R_BP spc.BP.I16_reg.x_reg +#define R_SI spc.SI.I16_reg.x_reg +#define R_DI spc.DI.I16_reg.x_reg +#define R_IP spc.IP.I16_reg.x_reg +#define R_FLG spc.FLAGS + +/* special registers */ +#define R_SP spc.SP.I16_reg.x_reg +#define R_BP spc.BP.I16_reg.x_reg +#define R_SI spc.SI.I16_reg.x_reg +#define R_DI spc.DI.I16_reg.x_reg +#define R_IP spc.IP.I16_reg.x_reg +#define R_FLG spc.FLAGS + +/* special registers */ +#define R_ESP spc.SP.I32_reg.e_reg +#define R_EBP spc.BP.I32_reg.e_reg +#define R_ESI spc.SI.I32_reg.e_reg +#define R_EDI spc.DI.I32_reg.e_reg +#define R_EIP spc.IP.I32_reg.e_reg +#define R_EFLG spc.FLAGS + +/* segment registers */ +#define R_CS seg.CS +#define R_DS seg.DS +#define R_SS seg.SS +#define R_ES seg.ES +#define R_FS seg.FS +#define R_GS seg.GS + +/* flag conditions */ +#define FB_CF 0x0001 /* CARRY flag */ +#define FB_PF 0x0004 /* PARITY flag */ +#define FB_AF 0x0010 /* AUX flag */ +#define FB_ZF 0x0040 /* ZERO flag */ +#define FB_SF 0x0080 /* SIGN flag */ +#define FB_TF 0x0100 /* TRAP flag */ +#define FB_IF 0x0200 /* INTERRUPT ENABLE flag */ +#define FB_DF 0x0400 /* DIR flag */ +#define FB_OF 0x0800 /* OVERFLOW flag */ + +/* 80286 and above always have bit#1 set */ +#define F_ALWAYS_ON (0x0002) /* flag bits always on */ + +/* + * Define a mask for only those flag bits we will ever pass back + * (via PUSHF) + */ +#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF) + +/* following bits masked in to a 16bit quantity */ + +#define F_CF 0x0001 /* CARRY flag */ +#define F_PF 0x0004 /* PARITY flag */ +#define F_AF 0x0010 /* AUX flag */ +#define F_ZF 0x0040 /* ZERO flag */ +#define F_SF 0x0080 /* SIGN flag */ +#define F_TF 0x0100 /* TRAP flag */ +#define F_IF 0x0200 /* INTERRUPT ENABLE flag */ +#define F_DF 0x0400 /* DIR flag */ +#define F_OF 0x0800 /* OVERFLOW flag */ + +#define TOGGLE_FLAG(flag) (M.x86.R_FLG ^= (flag)) +#define SET_FLAG(flag) (M.x86.R_FLG |= (flag)) +#define CLEAR_FLAG(flag) (M.x86.R_FLG &= ~(flag)) +#define ACCESS_FLAG(flag) (M.x86.R_FLG & (flag)) +#define CLEARALL_FLAG(m) (M.x86.R_FLG = 0) + +#define CONDITIONAL_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG) + +#define F_PF_CALC 0x010000 /* PARITY flag has been calced */ +#define F_ZF_CALC 0x020000 /* ZERO flag has been calced */ +#define F_SF_CALC 0x040000 /* SIGN flag has been calced */ + +#define F_ALL_CALC 0xff0000 /* All have been calced */ + +/* + * Emulator machine state. + * Segment usage control. + */ +#define SYSMODE_SEG_DS_SS 0x00000001 +#define SYSMODE_SEGOVR_CS 0x00000002 +#define SYSMODE_SEGOVR_DS 0x00000004 +#define SYSMODE_SEGOVR_ES 0x00000008 +#define SYSMODE_SEGOVR_FS 0x00000010 +#define SYSMODE_SEGOVR_GS 0x00000020 +#define SYSMODE_SEGOVR_SS 0x00000040 +#define SYSMODE_PREFIX_REPE 0x00000080 +#define SYSMODE_PREFIX_REPNE 0x00000100 +#define SYSMODE_PREFIX_DATA 0x00000200 +#define SYSMODE_PREFIX_ADDR 0x00000400 +#define SYSMODE_INTR_PENDING 0x10000000 +#define SYSMODE_EXTRN_INTR 0x20000000 +#define SYSMODE_HALTED 0x40000000 + +#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | \ + SYSMODE_SEGOVR_CS | \ + SYSMODE_SEGOVR_DS | \ + SYSMODE_SEGOVR_ES | \ + SYSMODE_SEGOVR_FS | \ + SYSMODE_SEGOVR_GS | \ + SYSMODE_SEGOVR_SS) +#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS | \ + SYSMODE_SEGOVR_CS | \ + SYSMODE_SEGOVR_DS | \ + SYSMODE_SEGOVR_ES | \ + SYSMODE_SEGOVR_FS | \ + SYSMODE_SEGOVR_GS | \ + SYSMODE_SEGOVR_SS | \ + SYSMODE_PREFIX_DATA | \ + SYSMODE_PREFIX_ADDR) + +#define INTR_SYNCH 0x1 +#define INTR_ASYNCH 0x2 +#define INTR_HALTED 0x4 + +typedef struct { + struct i386_general_regs gen; + struct i386_special_regs spc; + struct i386_segment_regs seg; + /* + * MODE contains information on: + * REPE prefix 2 bits repe,repne + * SEGMENT overrides 5 bits normal,DS,SS,CS,ES + * Delayed flag set 3 bits (zero, signed, parity) + * reserved 6 bits + * interrupt # 8 bits instruction raised interrupt + * BIOS video segregs 4 bits + * Interrupt Pending 1 bits + * Extern interrupt 1 bits + * Halted 1 bits + */ + long mode; + u8 intno; + volatile int intr; /* mask of pending interrupts */ + int debug; +#ifdef DEBUG + int check; + u16 saved_ip; + u16 saved_cs; + int enc_pos; + int enc_str_pos; + char decode_buf[32]; /* encoded byte stream */ + char decoded_buf[256]; /* disassembled strings */ +#endif + } X86EMU_regs; + +/**************************************************************************** +REMARKS: +Structure maintaining the emulator machine state. + +MEMBERS: +x86 - X86 registers +mem_base - Base real mode memory for the emulator +mem_size - Size of the real mode memory block for the emulator +****************************************************************************/ +typedef struct { + X86EMU_regs x86; + unsigned long mem_base; + unsigned long mem_size; + void* private; + } X86EMU_sysEnv; + +#ifndef __mips +#pragma pack() +#endif + +/*----------------------------- Global Variables --------------------------*/ + +#ifdef __cplusplus +extern "C" { /* Use "C" linkage when in C++ mode */ +#endif + +/* Global emulator machine state. + * + * We keep it global to avoid pointer dereferences in the code for speed. + */ + +extern X86EMU_sysEnv _X86EMU_env; +#define M _X86EMU_env + +/*-------------------------- Function Prototypes --------------------------*/ + +/* Function to log information at runtime */ + +#ifdef _CFE_ +#include "lib_printf.h" +#define printk xprintf +#define sprintf xsprintf +#else +void printk(const char *fmt, ...); +#endif + +#ifdef __cplusplus +} /* End of "C" linkage for C++ */ +#endif + +#endif /* __X86EMU_REGS_H */ diff --git a/cfe/cfe/x86emu/x86emu/types.h b/cfe/cfe/x86emu/x86emu/types.h new file mode 100644 index 0000000..f3d3783 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/types.h @@ -0,0 +1,89 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for x86 emulator type definitions. +* +****************************************************************************/ + +/* $XFree86: xc/extras/x86emu/include/x86emu/types.h,v 1.4 2000/09/26 15:56:44 tsi Exp $ */ + +#ifndef __X86EMU_TYPES_H +#define __X86EMU_TYPES_H + +#ifndef IN_MODULE +//#include +#endif + +/* + * The following kludge is an attempt to work around typedef conflicts with + * . + */ +#define u8 x86emuu8 +#define u16 x86emuu16 +#define u32 x86emuu32 +#define u64 x86emuu64 +#define s8 x86emus8 +#define s16 x86emus16 +#define s32 x86emus32 +#define s64 x86emus64 +#define uint x86emuuint +#define sint x86emusint + +/*---------------------- Macros and type definitions ----------------------*/ + +/* Currently only for Linux/32bit */ +#if defined(__GNUC__) && !defined(NO_LONG_LONG) +#define __HAS_LONG_LONG__ +#endif + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +#ifdef __HAS_LONG_LONG__ +typedef unsigned long long u64; +#endif + +typedef char s8; +typedef short s16; +typedef int s32; +#ifdef __HAS_LONG_LONG__ +typedef long long s64; +#endif + +typedef unsigned int uint; +typedef int sint; + +typedef u16 X86EMU_pioAddr; + +#endif /* __X86EMU_TYPES_H */ diff --git a/cfe/cfe/x86emu/x86emu/x86emui.h b/cfe/cfe/x86emu/x86emu/x86emui.h new file mode 100644 index 0000000..594b344 --- /dev/null +++ b/cfe/cfe/x86emu/x86emu/x86emui.h @@ -0,0 +1,109 @@ +/**************************************************************************** +* +* Realmode X86 Emulator Library +* +* Copyright (C) 1996-1999 SciTech Software, Inc. +* Copyright (C) David Mosberger-Tang +* Copyright (C) 1999 Egbert Eich +* +* ======================================================================== +* +* Permission to use, copy, modify, distribute, and sell this software and +* its documentation for any purpose is hereby granted without fee, +* provided that the above copyright notice appear in all copies and that +* both that copyright notice and this permission notice appear in +* supporting documentation, and that the name of the authors not be used +* in advertising or publicity pertaining to distribution of the software +* without specific, written prior permission. The authors makes no +* representations about the suitability of this software for any purpose. +* It is provided "as is" without express or implied warranty. +* +* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* +* ======================================================================== +* +* Language: ANSI C +* Environment: Any +* Developer: Kendall Bennett +* +* Description: Header file for system specific functions. These functions +* are always compiled and linked in the OS depedent libraries, +* and never in a binary portable driver. +* +****************************************************************************/ + +/* $XFree86: xc/extras/x86emu/src/x86emu/x86emu/x86emui.h,v 1.3 2000/04/17 16:29:47 eich Exp $ */ + +#ifndef __X86EMU_X86EMUI_H +#define __X86EMU_X86EMUI_H + +/* If we are compiling in C++ mode, we can compile some functions as + * inline to increase performance (however the code size increases quite + * dramatically in this case). + */ + +#if defined(__cplusplus) && !defined(_NO_INLINE) +#define _INLINE inline +#else +#define _INLINE static +#endif + +/* Get rid of unused parameters in C++ compilation mode */ + +#ifdef __cplusplus +#define X86EMU_UNUSED(v) +#else +#define X86EMU_UNUSED(v) v +#endif + +#include "x86emu.h" +#include "x86emu/regs.h" +#include "x86emu/debug.h" +#include "x86emu/decode.h" +#include "x86emu/ops.h" +#include "x86emu/prim_ops.h" +#include "x86emu/fpu.h" +#include "x86emu/fpu_regs.h" + +#ifdef IN_MODULE +#include +#else +#ifdef _CFE_ +#include "lib_types.h" +#include "lib_string.h" +#else +#include +#include +#endif +#endif +/*--------------------------- Inline Functions ----------------------------*/ + +#ifdef __cplusplus +extern "C" { /* Use "C" linkage when in C++ mode */ +#endif + +extern u8 (X86APIP sys_rdb)(u32 addr); +extern u16 (X86APIP sys_rdw)(u32 addr); +extern u32 (X86APIP sys_rdl)(u32 addr); +extern void (X86APIP sys_wrb)(u32 addr,u8 val); +extern void (X86APIP sys_wrw)(u32 addr,u16 val); +extern void (X86APIP sys_wrl)(u32 addr,u32 val); + +extern u8 (X86APIP sys_inb)(X86EMU_pioAddr addr); +extern u16 (X86APIP sys_inw)(X86EMU_pioAddr addr); +extern u32 (X86APIP sys_inl)(X86EMU_pioAddr addr); +extern void (X86APIP sys_outb)(X86EMU_pioAddr addr,u8 val); +extern void (X86APIP sys_outw)(X86EMU_pioAddr addr,u16 val); +extern void (X86APIP sys_outl)(X86EMU_pioAddr addr,u32 val); + +#ifdef __cplusplus +} /* End of "C" linkage for C++ */ +#endif + +#endif /* __X86EMU_X86EMUI_H */ diff --git a/cfe/cfe/zlib/ChangeLog b/cfe/cfe/zlib/ChangeLog new file mode 100644 index 0000000..567a500 --- /dev/null +++ b/cfe/cfe/zlib/ChangeLog @@ -0,0 +1,471 @@ + + ChangeLog file for zlib + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occuring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id: ChangeLog,v 1.1 2001/11/09 01:48:01 mpl Exp $. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/cfe/cfe/zlib/FAQ b/cfe/cfe/zlib/FAQ new file mode 100644 index 0000000..0feb6d3 --- /dev/null +++ b/cfe/cfe/zlib/FAQ @@ -0,0 +1,72 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://www.cdrom.com/pub/infozip/zlib/ which may have more recent information. + + +1) I need a Windows DLL +2) I need a Visual Basic interface to zlib +3) compress() returns Z_BUF_ERROR +4) deflate or inflate returns Z_BUF_ERROR +5) Where is the zlib documentation (man pages, etc...)? +6) Why don't you use GNU autoconf, libtool, etc...? +7) There is a bug in zlib. +8) I get "undefined reference to gzputc" + + + +1) I need a Windows DLL + + The zlib sources can be compiled without change to produce a DLL. + If you want a precompiled DLL, see http://www.winimage.com/zLibDll + + +2) I need a Visual Basic interface to zlib + + See http://www.tcfb.com/dowseware/cmp-z-it.zip + http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm + and contrib/visual-basic.txt + +3) compress() returns Z_BUF_ERROR + + Make sure that before the call of compress, the length of the + compressed buffer is equal to the total size of the compressed buffer + and not zero. For Visual Basic, check that this parameter is passed + by reference ("as any"), not by value ("as long"). + + +4) deflate or inflate returns Z_BUF_ERROR + + Make sure that before the call avail_in and avail_out are not zero. + + +5) Where is the zlib documentation (man pages, etc...)? + + It's in zlib.h for the moment. Volunteers to transform this + to man pages, please contact jloup@gzip.org. Examples of zlib usage + are in the files example.c and minigzip.c. + + +6) Why don't you use GNU autoconf, libtool, etc...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + +7) There is a bug in zlib. + + Most of the time, such problems are due to an incorrect usage + of zlib. Please try to reproduce the problem with a small + program and send us the corresponding source at zlib@quest.jpl.nasa.gov + Do not send multi-megabyte data files without prior agreement. + + +8) I get "undefined reference to gzputc" + + If "make test" produces something like + example.o(.text+0x174): + check that you don't have old files libz.* in /usr/lib, /usr/local/lib + or /usr/X11R6/lib. Remove old versions then do "make install". + diff --git a/cfe/cfe/zlib/INDEX b/cfe/cfe/zlib/INDEX new file mode 100644 index 0000000..8a24576 --- /dev/null +++ b/cfe/cfe/zlib/INDEX @@ -0,0 +1,86 @@ +ChangeLog history of changes +INDEX this file +FAQ Frequently Asked Questions about zlib +Make_vms.com script for Vax/VMS +Makefile makefile for Unix (generated by configure) +Makefile.in makefile for Unix (template for configure) +Makefile.riscos makefile for RISCOS +README guess what +algorithm.txt description of the (de)compression algorithm +configure configure script for Unix +descrip.mms makefile for Vax/VMS +zlib.3 mini man page for zlib (volunteers to write full + man pages from zlib.h welcome. write to jloup@gzip.org) + +amiga/Makefile.sas makefile for Amiga SAS/C +amiga/Makefile.pup makefile for Amiga powerUP SAS/C PPC + +msdos/Makefile.w32 makefile for Microsoft Visual C++ 32-bit +msdos/Makefile.b32 makefile for Borland C++ 32-bit +msdos/Makefile.bor makefile for Borland C/C++ 16-bit +msdos/Makefile.dj2 makefile for DJGPP 2.x +msdos/Makefile.emx makefile for EMX 0.9c (32-bit DOS/OS2) +msdos/Makefile.msc makefile for Microsoft C 16-bit +msdos/Makefile.tc makefile for Turbo C +msdos/Makefile.wat makefile for Watcom C +msdos/zlib.def definition file for Windows DLL +msdos/zlib.rc definition file for Windows DLL + +nt/Makefile.nt makefile for Windows NT +nt/zlib.dnt definition file for Windows NT DLL +nt/Makefile.emx makefile for EMX 0.9c/RSXNT 1.41 (Win32 Intel) +nt/Makefile.gcc makefile for Windows NT using GCC (mingw32) + + + zlib public header files (must be kept): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +deflate.c +deflate.h +gzio.c +infblock.c +infblock.h +infcodes.c +infcodes.h +inffast.c +inffast.h +inflate.c +inftrees.c +inftrees.h +infutil.c +infutil.h +maketree.c +trees.c +uncompr.c +zutil.c +zutil.h + + source files for sample programs: +example.c +minigzip.c + + unsupported contribution by third parties + +contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + +contrib/minizip/ by Gilles Vollant + Mini zip and unzip based on zlib + See http://www.winimage.com/zLibDll/unzip.html + +contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + +contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + +contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz extractor using zlib + +contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. diff --git a/cfe/cfe/zlib/Make_vms.com b/cfe/cfe/zlib/Make_vms.com new file mode 100644 index 0000000..1c57e8f --- /dev/null +++ b/cfe/cfe/zlib/Make_vms.com @@ -0,0 +1,115 @@ +$! make libz under VMS +$! written by Martin P.J. Zinser +$! +$! Look for the compiler used +$! +$ ccopt = "" +$ if f$getsyi("HW_MODEL").ge.1024 +$ then +$ ccopt = "/prefix=all"+ccopt +$ comp = "__decc__=1" +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ else +$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs."" +$ then +$ comp = "__vaxc__=1" +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ else +$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include: +$ ccopt = "/decc/prefix=all"+ccopt +$ comp = "__decc__=1" +$ endif +$ endif +$! +$! Build the thing plain or with mms +$! +$ write sys$output "Compiling Zlib sources ..." +$ if f$search("SYS$SYSTEM:MMS.EXE").eqs."" +$ then +$ dele example.obj;*,minigzip.obj;* +$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" - + adler32.c zlib.h zconf.h +$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" - + compress.c zlib.h zconf.h +$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" - + crc32.c zlib.h zconf.h +$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" - + deflate.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" - + gzio.c zutil.h zlib.h zconf.h +$ CALL MAKE infblock.OBJ "CC ''CCOPT' infblock" - + infblock.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE infcodes.OBJ "CC ''CCOPT' infcodes" - + infcodes.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" - + inffast.c zutil.h zlib.h zconf.h inffast.h +$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" - + inflate.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" - + inftrees.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE infutil.OBJ "CC ''CCOPT' infutil" - + infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h +$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" - + trees.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" - + uncompr.c zlib.h zconf.h +$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" - + zutil.c zutil.h zlib.h zconf.h +$ write sys$output "Building Zlib ..." +$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ +$ write sys$output "Building example..." +$ CALL MAKE example.OBJ "CC ''CCOPT' example" - + example.c zlib.h zconf.h +$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb +$ write sys$output "Building minigzip..." +$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" - + minigzip.c zlib.h zconf.h +$ call make minigzip.exe - + "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" - + minigzip.obj libz.olb +$ else +$ mms/macro=('comp') +$ endif +$ write sys$output "Zlib build completed" +$ exit +$! +$! +$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES +$ V = 'F$Verify(0) +$! P1 = What we are trying to make +$! P2 = Command to make it +$! P3 - P8 What it depends on +$ +$ If F$Search(P1) .Eqs. "" Then Goto Makeit +$ Time = F$CvTime(F$File(P1,"RDT")) +$arg=3 +$Loop: +$ Argument = P'arg +$ If Argument .Eqs. "" Then Goto Exit +$ El=0 +$Loop2: +$ File = F$Element(El," ",Argument) +$ If File .Eqs. " " Then Goto Endl +$ AFile = "" +$Loop3: +$ OFile = AFile +$ AFile = F$Search(File) +$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl +$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit +$ Goto Loop3 +$NextEL: +$ El = El + 1 +$ Goto Loop2 +$EndL: +$ arg=arg+1 +$ If arg .Le. 8 Then Goto Loop +$ Goto Exit +$ +$Makeit: +$ VV=F$VERIFY(0) +$ write sys$output P2 +$ 'P2 +$ VV='F$Verify(VV) +$Exit: +$ If V Then Set Verify +$ENDSUBROUTINE diff --git a/cfe/cfe/zlib/Makefile b/cfe/cfe/zlib/Makefile new file mode 100644 index 0000000..e9224bb --- /dev/null +++ b/cfe/cfe/zlib/Makefile @@ -0,0 +1,28 @@ + +#ALLOBJS += adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ +# zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +#ALLOBJS += adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ +# zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +ALLOBJS += adler32.o uncompr.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o zutil.o +CFLAGS += -DCFG_ZLIB=1 -DMY_ZCALLOC -DNO_MEMCPY + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h +infcodes.o: zutil.h zlib.h zconf.h +infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h +inffast.o: infblock.h infcodes.h infutil.h inffast.h +inflate.o: zutil.h zlib.h zconf.h infblock.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/cfe/cfe/zlib/Makefile.in b/cfe/cfe/zlib/Makefile.in new file mode 100644 index 0000000..3a3b116 --- /dev/null +++ b/cfe/cfe/zlib/Makefile.in @@ -0,0 +1,174 @@ +# Makefile for zlib +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=-L. -lz +LDSHARED=$(CC) +CPP=$(CC) -E + +VER=1.1.3 +LIBS=libz.a +SHAREDLIB=libz.so + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +DISTFILES = README FAQ INDEX ChangeLog configure Make*[a-z0-9] *.[ch] *.mms \ + algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \ + nt/Make*[a-z0-9] nt/zlib.dnt amiga/Make*.??? os2/M*.os2 os2/zlib.def \ + contrib/RE*.contrib contrib/*.txt contrib/asm386/*.asm contrib/asm386/*.c \ + contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/asm[56]86/*.?86 \ + contrib/asm[56]86/*.S contrib/iostream/*.cpp \ + contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \ + contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 \ + contrib/minizip/[CM]*[pe] contrib/minizip/*.[ch] contrib/minizip/*.[td]?? \ + contrib/delphi*/*.??? + +all: example minigzip + +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIB).$(VER): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIB).1 + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIB).1 + +example: example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip: minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(includedir) ]; then mkdir $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir $(libdir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIB).$(VER); then \ + rm -f $(SHAREDLIB) $(SHAREDLIB).1; \ + ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB); \ + ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB).1; \ + (ldconfig || true) >/dev/null 2>&1; \ + fi +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + v=$(VER); \ + if test -f zlib.h; then \ + v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`; \ + rm -f zlib.h zconf.h; \ + fi; \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIB).$$v; then \ + rm -f $(SHAREDLIB).$$v $(SHAREDLIB) $(SHAREDLIB).1; \ + fi + +clean: + rm -f *.o *~ example minigzip libz.a libz.so* foo.gz so_locations \ + _match.s maketree + +distclean: clean + +zip: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c contrib/minizip/test.zip + v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + zip -ul9 zlib$$v $(DISTFILES) + mv Makefile~ Makefile + +dist: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c contrib/minizip/test.zip + d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + rm -f $$d.tar.gz; \ + if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \ + files=""; \ + for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \ + cd ..; \ + GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \ + if test ! -d $$d; then rm -f $$d; fi + mv Makefile~ Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h +infcodes.o: zutil.h zlib.h zconf.h +infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h +inffast.o: infblock.h infcodes.h infutil.h inffast.h +inflate.o: zutil.h zlib.h zconf.h infblock.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/cfe/cfe/zlib/Makefile.orig b/cfe/cfe/zlib/Makefile.orig new file mode 100644 index 0000000..3a3b116 --- /dev/null +++ b/cfe/cfe/zlib/Makefile.orig @@ -0,0 +1,174 @@ +# Makefile for zlib +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=-L. -lz +LDSHARED=$(CC) +CPP=$(CC) -E + +VER=1.1.3 +LIBS=libz.a +SHAREDLIB=libz.so + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +DISTFILES = README FAQ INDEX ChangeLog configure Make*[a-z0-9] *.[ch] *.mms \ + algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \ + nt/Make*[a-z0-9] nt/zlib.dnt amiga/Make*.??? os2/M*.os2 os2/zlib.def \ + contrib/RE*.contrib contrib/*.txt contrib/asm386/*.asm contrib/asm386/*.c \ + contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/asm[56]86/*.?86 \ + contrib/asm[56]86/*.S contrib/iostream/*.cpp \ + contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \ + contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 \ + contrib/minizip/[CM]*[pe] contrib/minizip/*.[ch] contrib/minizip/*.[td]?? \ + contrib/delphi*/*.??? + +all: example minigzip + +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIB).$(VER): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIB).1 + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIB).1 + +example: example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip: minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(includedir) ]; then mkdir $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir $(libdir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIB).$(VER); then \ + rm -f $(SHAREDLIB) $(SHAREDLIB).1; \ + ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB); \ + ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB).1; \ + (ldconfig || true) >/dev/null 2>&1; \ + fi +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + v=$(VER); \ + if test -f zlib.h; then \ + v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`; \ + rm -f zlib.h zconf.h; \ + fi; \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIB).$$v; then \ + rm -f $(SHAREDLIB).$$v $(SHAREDLIB) $(SHAREDLIB).1; \ + fi + +clean: + rm -f *.o *~ example minigzip libz.a libz.so* foo.gz so_locations \ + _match.s maketree + +distclean: clean + +zip: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c contrib/minizip/test.zip + v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + zip -ul9 zlib$$v $(DISTFILES) + mv Makefile~ Makefile + +dist: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c contrib/minizip/test.zip + d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + rm -f $$d.tar.gz; \ + if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \ + files=""; \ + for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \ + cd ..; \ + GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \ + if test ! -d $$d; then rm -f $$d; fi + mv Makefile~ Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h +infcodes.o: zutil.h zlib.h zconf.h +infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h +inffast.o: infblock.h infcodes.h infutil.h inffast.h +inflate.o: zutil.h zlib.h zconf.h infblock.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/cfe/cfe/zlib/Makefile.riscos b/cfe/cfe/zlib/Makefile.riscos new file mode 100644 index 0000000..d97f449 --- /dev/null +++ b/cfe/cfe/zlib/Makefile.riscos @@ -0,0 +1,151 @@ +# Project: zlib_1_03 +# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430 +# test works out-of-the-box, installs `somewhere' on demand + +# Toolflags: +CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fah +C++flags = -c -depend !Depend -IC: -throwback +Linkflags = -aif -c++ -o $@ +ObjAsmflags = -throwback -NoCache -depend !Depend +CMHGflags = +LibFileflags = -c -l -o $@ +Squeezeflags = -o $@ + +# change the line below to where _you_ want the library installed. +libdest = lib:zlib + +# Final targets: +@.lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \ + @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \ + @.o.uncompr @.o.zutil + LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \ + @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \ + @.o.trees @.o.uncompr @.o.zutil +test: @.minigzip @.example @.lib + @copy @.lib @.libc A~C~DF~L~N~P~Q~RS~TV + @echo running tests: hang on. + @/@.minigzip -f -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -f -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -1 libc + @/@.minigzip -d libc-gz + @diff @.lib @.libc + @echo that should have reported '@.lib and @.libc identical' if you have diff. + @/@.example @.fred @.fred + @echo that will have given lots of hello!'s. + +@.minigzip: @.o.minigzip @.lib C:o.Stubs + Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs +@.example: @.o.example @.lib C:o.Stubs + Link $(Linkflags) @.o.example @.lib C:o.Stubs + +install: @.lib + cdir $(libdest) + cdir $(libdest).h + @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV + @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV + @copy @.lib $(libdest).lib A~C~DF~L~N~P~Q~RS~TV + @echo okay, installed zlib in $(libdest) + +clean:; remove @.minigzip + remove @.example + remove @.libc + -wipe @.o.* F~r~cV + remove @.fred + +# User-editable dependencies: +.c.o: + cc $(ccflags) -o $@ $< + +# Static dependencies: + +# Dynamic dependencies: +o.example: c.example +o.example: h.zlib +o.example: h.zconf +o.minigzip: c.minigzip +o.minigzip: h.zlib +o.minigzip: h.zconf +o.adler32: c.adler32 +o.adler32: h.zlib +o.adler32: h.zconf +o.compress: c.compress +o.compress: h.zlib +o.compress: h.zconf +o.crc32: c.crc32 +o.crc32: h.zlib +o.crc32: h.zconf +o.deflate: c.deflate +o.deflate: h.deflate +o.deflate: h.zutil +o.deflate: h.zlib +o.deflate: h.zconf +o.gzio: c.gzio +o.gzio: h.zutil +o.gzio: h.zlib +o.gzio: h.zconf +o.infblock: c.infblock +o.infblock: h.zutil +o.infblock: h.zlib +o.infblock: h.zconf +o.infblock: h.infblock +o.infblock: h.inftrees +o.infblock: h.infcodes +o.infblock: h.infutil +o.infcodes: c.infcodes +o.infcodes: h.zutil +o.infcodes: h.zlib +o.infcodes: h.zconf +o.infcodes: h.inftrees +o.infcodes: h.infblock +o.infcodes: h.infcodes +o.infcodes: h.infutil +o.infcodes: h.inffast +o.inffast: c.inffast +o.inffast: h.zutil +o.inffast: h.zlib +o.inffast: h.zconf +o.inffast: h.inftrees +o.inffast: h.infblock +o.inffast: h.infcodes +o.inffast: h.infutil +o.inffast: h.inffast +o.inflate: c.inflate +o.inflate: h.zutil +o.inflate: h.zlib +o.inflate: h.zconf +o.inflate: h.infblock +o.inftrees: c.inftrees +o.inftrees: h.zutil +o.inftrees: h.zlib +o.inftrees: h.zconf +o.inftrees: h.inftrees +o.inftrees: h.inffixed +o.infutil: c.infutil +o.infutil: h.zutil +o.infutil: h.zlib +o.infutil: h.zconf +o.infutil: h.infblock +o.infutil: h.inftrees +o.infutil: h.infcodes +o.infutil: h.infutil +o.trees: c.trees +o.trees: h.deflate +o.trees: h.zutil +o.trees: h.zlib +o.trees: h.zconf +o.trees: h.trees +o.uncompr: c.uncompr +o.uncompr: h.zlib +o.uncompr: h.zconf +o.zutil: c.zutil +o.zutil: h.zutil +o.zutil: h.zlib +o.zutil: h.zconf diff --git a/cfe/cfe/zlib/README b/cfe/cfe/zlib/README new file mode 100644 index 0000000..8ff4587 --- /dev/null +++ b/cfe/cfe/zlib/README @@ -0,0 +1,148 @@ +zlib 1.1.3 is a general purpose data compression library. All the code +is thread safe. The data format used by the zlib library +is described by RFCs (Request for Comments) 1950 to 1952 in the files +ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate +format) and rfc1952.txt (gzip format). These documents are also available in +other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact jloup@gzip.org). A usage +example of the library is given in the file example.c which also tests that +the library is working correctly. Another example is given in the file +minigzip.c. The compression library itself is composed of all source files +except example.c and minigzip.c. + +To compile all files and run the test program, follow the instructions +given at the top of Makefile. In short "make test; make install" +should work for most machines. For Unix: "configure; make test; make install" +For MSDOS, use one of the special makefiles such as Makefile.msc. +For VMS, use Make_vms.com or descrip.mms. + +Questions about zlib should be sent to , or to +Gilles Vollant for the Windows DLL version. +The zlib home page is http://www.cdrom.com/pub/infozip/zlib/ +The official zlib ftp site is ftp://ftp.cdrom.com/pub/infozip/zlib/ +Before reporting a problem, please check those sites to verify that +you have the latest version of zlib; otherwise get the latest version and +check whether the problem still exists or not. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.1.3 are documented in the file ChangeLog. +The main changes since 1.1.2 are: + +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +plus many changes for portability. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit 1.1 +http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html +See the zlib home page http://www.cdrom.com/pub/infozip/zlib/ for details. + +A Perl interface to zlib written by Paul Marquess +is in the CPAN (Comprehensive Perl Archive Network) sites, such as: +ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib* + +A Python interface to zlib written by A.M. Kuchling +is available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries +is availlable at http://www.westend.com/~kupries/doc/trf/man/man.html + +An experimental package to read and write files in .zip format, +written on top of zlib by Gilles Vollant , is +available at http://www.winimage.com/zLibDll/unzip.html +and also in the contrib/minizip directory of zlib. + + +Notes for some targets: + +- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc + and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL + The zlib DLL support was initially done by Alessandro Iacopetti and is + now maintained by Gilles Vollant . Check the zlib DLL + home page at http://www.winimage.com/zLibDll + + From Visual Basic, you can call the DLL functions which do not take + a structure as argument: compress, uncompress and all gz* functions. + See contrib/visual-basic.txt for more information, or get + http://www.tcfb.com/dowseware/cmp-z-it.zip + +- For 64-bit Irix, deflate.c must be compiled without any optimization. + With -O, one libpng test fails. The test works in 32 bit mode (with + the -n32 compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 + it works when compiled with cc. + +- on Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 + is necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works + with other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For Turbo C the small model is supported only with reduced performance to + avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 + +- For PalmOs, see http://www.cs.uit.no/~perm/PASTA/pilot/software.html + Per Harald Myrvang + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-1998 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. diff --git a/cfe/cfe/zlib/adler32.c b/cfe/cfe/zlib/adler32.c new file mode 100644 index 0000000..70d368e --- /dev/null +++ b/cfe/cfe/zlib/adler32.c @@ -0,0 +1,48 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2001/11/09 01:48:01 mpl Exp $ */ + +#include "zlib.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/cfe/cfe/zlib/algorithm.txt b/cfe/cfe/zlib/algorithm.txt new file mode 100644 index 0000000..cdc830b --- /dev/null +++ b/cfe/cfe/zlib/algorithm.txt @@ -0,0 +1,213 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The real question is, given a Huffman tree, how to decode fast. The most +important realization is that shorter codes are much more common than +longer codes, so pay attention to decoding the short codes fast, and let +the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and set it +for the maximum speed. + +inflate() sends new trees relatively often, so it is possibly set for a +smaller first level table than an application that has only one tree for +all the data. For inflate, which has 286 possible codes for the +literal/length tree, the size of the first table is nine bits. Also the +distance trees have 30 possible values, and the size of the first table is +six bits. Note that for each of those cases, the table ended up one bit +longer than the ``average'' code length, i.e. the code length of an +approximately flat code which would be a little more than eight bits for +286 symbols and a little less than five bits for 30 symbols. It would be +interesting to see if optimizing the first level table for other +applications gave values within a bit or two of the flat code size. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend two much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode to and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +ftp://ds.internic.net/rfc/rfc1951.txt diff --git a/cfe/cfe/zlib/compress.c b/cfe/cfe/zlib/compress.c new file mode 100644 index 0000000..4000959 --- /dev/null +++ b/cfe/cfe/zlib/compress.c @@ -0,0 +1,68 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2001/11/09 01:48:01 mpl Exp $ */ + +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} diff --git a/cfe/cfe/zlib/configure b/cfe/cfe/zlib/configure new file mode 100755 index 0000000..e894235 --- /dev/null +++ b/cfe/cfe/zlib/configure @@ -0,0 +1,212 @@ +#!/bin/sh +# configure script for zlib. This script is needed only if +# you wish to build a shared library and your system supports them, +# of if you need special compiler, flags or install directory. +# Otherwise, you can just use directly "make test; make install" +# +# To create a shared library, use "configure --shared"; by default a static +# library is created. If the primitive shared library support provided here +# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) +# LDSHARED is the command to be used to create a shared library + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +LIBS=libz.a +SHAREDLIB=libz.so +VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h` +AR=${AR-"ar rc"} +RANLIB=${RANLIB-"ranlib"} +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +libdir=${libdir-'${exec_prefix}/lib'} +includedir=${includedir-'${prefix}/include'} +shared_ext='.so' +shared=0 +gcc=0 +old_cc="$CC" +old_cflags="$CFLAGS" + +while test $# -ge 1 +do +case "$1" in + -h* | --h*) + echo 'usage:' + echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]' + echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]' + exit 0;; + -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;; + -p* | --p*) prefix="$2"; shift; shift;; + -e* | --e*) exec_prefix="$2"; shift; shift;; + -l* | --l*) libdir="$2"; shift; shift;; + -i* | --i*) includedir="$2"; shift; shift;; + -s* | --s*) shared=1; shift;; + esac +done + +test=ztest$$ +cat > $test.c </dev/null; then + CC="$cc" + SFLAGS=${CFLAGS-"-fPIC -O3"} + CFLAGS="$cflags" + case `(uname -s || echo unknown) 2>/dev/null` in + Linux | linux) LDSHARED=${LDSHARED-"gcc -shared -Wl,-soname,libz.so.1"};; + *) LDSHARED=${LDSHARED-"gcc -shared"};; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + case `(uname -sr || echo unknown) 2>/dev/null` in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} +# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"} + LDSHARED=${LDSHARED-"ld -b"} + shared_ext='.sl' + SHAREDLIB='libz.sl';; + IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."} + CFLAGS=${CFLAGS-"-ansi -O2"} + LDSHARED=${LDSHARED-"cc -shared"};; + OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,$SHAREDLIB -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};; + OSF1*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared"};; + QNX*) SFLAGS=${CFLAGS-"-4 -O"} + CFLAGS=${CFLAGS-"-4 -O"} + LDSHARED=${LDSHARED-"cc"} + RANLIB=${RANLIB-"true"} + AR="cc -A";; + SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "} + CFLAGS=${CFLAGS-"-O3"} + LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};; + SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."} + CFLAGS=${CFLAGS-"-fast -xcg89"} + LDSHARED=${LDSHARED-"cc -G"};; + SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"} + CFLAGS=${CFLAGS-"-O2"} + LDSHARED=${LDSHARED-"ld"};; + UNIX_System_V\ 4.2.0) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + UNIX_SV\ 4.2MP) + SFLAGS=${CFLAGS-"-Kconform_pic -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + # send working options for other systems to support@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -shared"};; + esac +fi + +if test $shared -eq 1; then + echo Checking for shared library support... + # we must test in two steps (cc then ld), required at least on SunOS 4.x + if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" && + test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then + CFLAGS="$SFLAGS" + LIBS="$SHAREDLIB.$VER" + echo Building shared library $SHAREDLIB.$VER with $CC. + elif test -z "$old_cc" -a -z "$old_cflags"; then + echo No shared library suppport. + shared=0; + else + echo 'No shared library suppport; try without defining CC and CFLAGS' + shared=0; + fi +fi +if test $shared -eq 0; then + LDSHARED="$CC" + echo Building static library $LIBS version $VER with $CC. +fi + +cat > $test.c < +int main() { return 0; } +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DHAVE_UNISTD_H" + echo "Checking for unistd.h... Yes." +else + echo "Checking for unistd.h... No." +fi + +cat > $test.c < +int main() { return 0; } +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for errno.h... Yes." +else + echo "Checking for errno.h... No." + CFLAGS="$CFLAGS -DNO_ERRNO_H" +fi + +cat > $test.c < +#include +#include +caddr_t hello() { + return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0); +} +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DUSE_MMAP" + echo Checking for mmap support... Yes. +else + echo Checking for mmap support... No. +fi + +CPP=${CPP-"$CC -E"} +case $CFLAGS in + *ASMV*) + if test "`nm $test.o | grep _hello`" = ""; then + CPP="$CPP -DNO_UNDERLINE" + echo Checking for underline in external names... No. + else + echo Checking for underline in external names... Yes. + fi;; +esac + +rm -f $test.[co] $test$shared_ext + +# udpate Makefile +sed < Makefile.in " +/^CC *=/s%=.*%=$CC% +/^CFLAGS *=/s%=.*%=$CFLAGS% +/^CPP *=/s%=.*%=$CPP% +/^LDSHARED *=/s%=.*%=$LDSHARED% +/^LIBS *=/s%=.*%=$LIBS% +/^SHAREDLIB *=/s%=.*%=$SHAREDLIB% +/^AR *=/s%=.*%=$AR% +/^RANLIB *=/s%=.*%=$RANLIB% +/^VER *=/s%=.*%=$VER% +/^prefix *=/s%=.*%=$prefix% +/^exec_prefix *=/s%=.*%=$exec_prefix% +/^libdir *=/s%=.*%=$libdir% +/^includedir *=/s%=.*%=$includedir% +" > Makefile diff --git a/cfe/cfe/zlib/crc32.c b/cfe/cfe/zlib/crc32.c new file mode 100644 index 0000000..0402f67 --- /dev/null +++ b/cfe/cfe/zlib/crc32.c @@ -0,0 +1,162 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: crc32.c,v 1.1 2001/11/09 01:48:01 mpl Exp $ */ + +#include "zlib.h" + +#define local static + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local uLongf crc_table[256]; +local void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +local void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +local const uLongf crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLongf * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLongf *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong ZEXPORT crc32(crc, buf, len) + uLong crc; + const Bytef *buf; + uInt len; +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} diff --git a/cfe/cfe/zlib/deflate.c b/cfe/cfe/zlib/deflate.c new file mode 100644 index 0000000..be87d40 --- /dev/null +++ b/cfe/cfe/zlib/deflate.c @@ -0,0 +1,1350 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.1.3 Copyright 1995-1998 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_slow OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int noheader = 0; + static const char* my_version = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == Z_NULL) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == Z_NULL) strm->zfree = zcfree; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#ifdef FASTEST + level = 1; +#endif + + if (windowBits < 0) { /* undocumented feature: suppress zlib header */ + noheader = 1; + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->noheader = noheader; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->status != INIT_STATE) return Z_STREAM_ERROR; + + s = strm->state; + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->noheader < 0) { + s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + } + s->status = s->noheader ? BUSY_STATE : INIT_STATE; + strm->adler = 1; + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + + if (level == Z_DEFAULT_COMPRESSION) { + level = 6; + } + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the zlib header */ + if (s->status == INIT_STATE) { + + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags = (s->level-1) >> 1; + + if (level_flags > 3) level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = 1L; + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUFF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->noheader) return Z_STREAM_END; + + /* Write the zlib trailer (adler32) */ + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + s->noheader = -1; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((Bytef *) ds->prev, (const Bytef *) ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((Bytef *) ds->head, (const Bytef *) ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (!strm->state->noheader) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +#ifndef FASTEST +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} + +#else /* FASTEST */ +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return len <= s->lookahead ? len : s->lookahead; +} +#endif /* FASTEST */ +#endif /* ASMV */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + } else if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in hash table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} diff --git a/cfe/cfe/zlib/deflate.h b/cfe/cfe/zlib/deflate.h new file mode 100644 index 0000000..e91a4f2 --- /dev/null +++ b/cfe/cfe/zlib/deflate.h @@ -0,0 +1,318 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-1998 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +#include "zutil.h" + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif diff --git a/cfe/cfe/zlib/descrip.mms b/cfe/cfe/zlib/descrip.mms new file mode 100644 index 0000000..9d36459 --- /dev/null +++ b/cfe/cfe/zlib/descrip.mms @@ -0,0 +1,48 @@ +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser + +cc_defs = +c_deb = + +.ifdef __DECC__ +pref = /prefix=all +.endif + +OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\ + inftrees.obj, infcodes.obj, infutil.obj, inffast.obj + +CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF) + +all : example.exe minigzip.exe + @ write sys$output " Example applications available" +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib + +clean : + delete *.obj;*,libz.olb;* + + +# Other dependencies. +adler32.obj : zutil.h zlib.h zconf.h +compress.obj : zlib.h zconf.h +crc32.obj : zutil.h zlib.h zconf.h +deflate.obj : deflate.h zutil.h zlib.h zconf.h +example.obj : zlib.h zconf.h +gzio.obj : zutil.h zlib.h zconf.h +infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h +inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h +inflate.obj : zutil.h zlib.h zconf.h infblock.h +inftrees.obj : zutil.h zlib.h zconf.h inftrees.h +infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h +minigzip.obj : zlib.h zconf.h +trees.obj : deflate.h zutil.h zlib.h zconf.h +uncompr.obj : zlib.h zconf.h +zutil.obj : zutil.h zlib.h zconf.h diff --git a/cfe/cfe/zlib/example.c b/cfe/cfe/zlib/example.c new file mode 100644 index 0000000..63a1b1e --- /dev/null +++ b/cfe/cfe/zlib/example.c @@ -0,0 +1,556 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: example.c,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#else + extern void exit OF((int)); +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *out, const char *in, + Byte *uncompr, int uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(out, in, uncompr, uncomprLen) + const char *out; /* compressed output file */ + const char *in; /* compressed input file */ + Byte *uncompr; + int uncomprLen; +{ + int err; + int len = strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(out, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(in, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + } + strcpy((char*)uncompr, "garbage"); + + uncomprLen = gzread(file, uncompr, (unsigned)uncomprLen); + if (uncomprLen != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char *)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, uncomprLen); + uncomprLen = strlen((char*)uncompr); + if (uncomprLen != 6) { /* "hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello+7)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char *)uncompr); + } + + gzclose(file); +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + int len = strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != (uLong)len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + int len = strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + (argc > 2 ? argv[2] : TESTFILE), + uncompr, (int)uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + exit(0); + return 0; /* to avoid warning */ +} diff --git a/cfe/cfe/zlib/gzio.c b/cfe/cfe/zlib/gzio.c new file mode 100644 index 0000000..6dfd489 --- /dev/null +++ b/cfe/cfe/zlib/gzio.c @@ -0,0 +1,875 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_DEFLATE to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#include + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + long startpos; /* start of compressed data in file (header skipped) */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open return NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->startpos = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * startpos anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->startpos = (ftell(s->file) - s->stream.avail_in); + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + c = get_byte(s); + if (c != gz_magic[len]) { + if (len != 0) s->stream.avail_in++, s->stream.next_in--; + if (c != EOF) { + s->stream.avail_in++, s->stream.next_in--; + s->transparent = 1; + } + s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; + return; + } + } + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_DEFLATE + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->stream.total_in += (uLong)len; + s->stream.total_out += (uLong)len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may + * be different from s->stream.total_out) in case of + * concatenated .gz files. Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + uLong total_in = s->stream.total_in; + uLong total_out = s->stream.total_out; + + inflateReset(&(s->stream)); + s->stream.total_in = total_in; + s->stream.total_out = total_out; + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_DEFLATE +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + const voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + va_start(va, format); +#ifdef HAS_vsnprintf + (void)vsnprintf(buf, sizeof(buf), format, va); +#else + (void)vsprintf(buf, format, va); +#endif + va_end(va); + len = strlen(buf); /* some *sprintf don't return the nb of bytes written */ + if (len <= 0) return 0; + + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + +#ifdef HAS_snprintf + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +#else + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +#endif + len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */ + if (len <= 0) return 0; + + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->z_err = deflate(&(s->stream), flush); + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_DEFLATE */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->stream.total_in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return (z_off_t)s->stream.total_in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->stream.total_out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->stream.total_in = s->stream.total_out = (uLong)offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if ((uLong)offset >= s->stream.total_out) { + offset -= s->stream.total_out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return (z_off_t)s->stream.total_out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + + if (s->startpos == 0) { /* not a compressed file */ + rewind(s->file); + return 0; + } + + (void) inflateReset(&s->stream); + return fseek(s->file, s->startpos, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + return (s == NULL || s->mode != 'r') ? 0 : s->z_eof; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, s->stream.total_in); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char* ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} diff --git a/cfe/cfe/zlib/infblock.c b/cfe/cfe/zlib/infblock.c new file mode 100644 index 0000000..f4920fa --- /dev/null +++ b/cfe/cfe/zlib/infblock.c @@ -0,0 +1,398 @@ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); + Tracev((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_streamp z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(s, z) +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(s, d, n) +inflate_blocks_statef *s; +const Bytef *d; +uInt n; +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(s) +inflate_blocks_statef *s; +{ + return s->mode == LENS; +} diff --git a/cfe/cfe/zlib/infblock.h b/cfe/cfe/zlib/infblock.h new file mode 100644 index 0000000..bd25c80 --- /dev/null +++ b/cfe/cfe/zlib/infblock.h @@ -0,0 +1,39 @@ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); diff --git a/cfe/cfe/zlib/infcodes.c b/cfe/cfe/zlib/infcodes.c new file mode 100644 index 0000000..d4e5ee9 --- /dev/null +++ b/cfe/cfe/zlib/infcodes.c @@ -0,0 +1,257 @@ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +z_streamp z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_streamp z; +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} diff --git a/cfe/cfe/zlib/infcodes.h b/cfe/cfe/zlib/infcodes.h new file mode 100644 index 0000000..6c750d8 --- /dev/null +++ b/cfe/cfe/zlib/infcodes.h @@ -0,0 +1,27 @@ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + diff --git a/cfe/cfe/zlib/inffast.c b/cfe/cfe/zlib/inffast.c new file mode 100644 index 0000000..61a78ee --- /dev/null +++ b/cfe/cfe/zlib/inffast.c @@ -0,0 +1,170 @@ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} diff --git a/cfe/cfe/zlib/inffast.h b/cfe/cfe/zlib/inffast.h new file mode 100644 index 0000000..8facec5 --- /dev/null +++ b/cfe/cfe/zlib/inffast.h @@ -0,0 +1,17 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); diff --git a/cfe/cfe/zlib/inffixed.h b/cfe/cfe/zlib/inffixed.h new file mode 100644 index 0000000..77f7e76 --- /dev/null +++ b/cfe/cfe/zlib/inffixed.h @@ -0,0 +1,151 @@ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local uInt fixed_bl = 9; +local uInt fixed_bd = 5; +local inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; diff --git a/cfe/cfe/zlib/inflate.c b/cfe/cfe/zlib/inflate.c new file mode 100644 index 0000000..32e9b8d --- /dev/null +++ b/cfe/cfe/zlib/inflate.c @@ -0,0 +1,366 @@ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" + +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ + +typedef enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int ZEXPORT inflateReset(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int ZEXPORT inflateEnd(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + + +int ZEXPORT inflateInit2_(z, w, version, stream_size) +z_streamp z; +int w; +const char *version; +int stream_size; +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int ZEXPORT inflateInit_(z, version, stream_size) +z_streamp z; +const char *version; +int stream_size; +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int ZEXPORT inflate(z, f) +z_streamp z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) +z_streamp z; +const Bytef *dictionary; +uInt dictLength; +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + + +int ZEXPORT inflateSync(z) +z_streamp z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} diff --git a/cfe/cfe/zlib/inftrees.c b/cfe/cfe/zlib/inftrees.c new file mode 100644 index 0000000..ef1e0b6 --- /dev/null +++ b/cfe/cfe/zlib/inftrees.c @@ -0,0 +1,455 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#if !defined(BUILDFIXED) && !defined(STDC) +# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ +#endif + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ +struct internal_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uIntf * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +local int huft_build(b, n, s, d, e, t, m, hp, hn, v) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= 288) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +const uIntf *d; /* list of base values for non-simple codes */ +const uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +inflate_huft *hp; /* space for trees */ +uInt *hn; /* hufts used in space */ +uIntf *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(c, bb, tb, hp, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +#ifdef BUILDFIXED +local int fixed_built = 0; +#define FIXEDH 544 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; +#else +#include "inffixed.h" +#endif + + +int inflate_trees_fixed(bl, bd, tl, td, z) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for memory allocation */ +{ +#ifdef BUILDFIXED + /* build fixed tables if not already */ + if (!fixed_built) + { + int k; /* temporary variable */ + uInt f = 0; /* number of hufts used in fixed_mem */ + uIntf *c; /* length list for huft_build */ + uIntf *v; /* work area for huft_build */ + + /* allocate memory */ + if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + { + ZFREE(z, c); + return Z_MEM_ERROR; + } + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 9; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, + fixed_mem, &f, v); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, + fixed_mem, &f, v); + + /* done */ + ZFREE(z, v); + ZFREE(z, c); + fixed_built = 1; + } +#endif + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} diff --git a/cfe/cfe/zlib/inftrees.h b/cfe/cfe/zlib/inftrees.h new file mode 100644 index 0000000..85853e0 --- /dev/null +++ b/cfe/cfe/zlib/inftrees.h @@ -0,0 +1,58 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp)); /* for memory allocation */ diff --git a/cfe/cfe/zlib/infutil.c b/cfe/cfe/zlib/infutil.c new file mode 100644 index 0000000..824dab5 --- /dev/null +++ b/cfe/cfe/zlib/infutil.c @@ -0,0 +1,87 @@ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} diff --git a/cfe/cfe/zlib/infutil.h b/cfe/cfe/zlib/infutil.h new file mode 100644 index 0000000..99d1135 --- /dev/null +++ b/cfe/cfe/zlib/infutil.h @@ -0,0 +1,98 @@ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#endif diff --git a/cfe/cfe/zlib/maketree.c b/cfe/cfe/zlib/maketree.c new file mode 100644 index 0000000..949d786 --- /dev/null +++ b/cfe/cfe/zlib/maketree.c @@ -0,0 +1,85 @@ +/* maketree.c -- make inffixed.h table for decoding fixed codes + * Copyright (C) 1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* This program is included in the distribution for completeness. + You do not need to compile or run this program since inffixed.h + is already included in the distribution. To use this program + you need to compile zlib with BUILDFIXED defined and then compile + and link this program with the zlib library. Then the output of + this program can be piped to inffixed.h. */ + +#include +#include +#include "zutil.h" +#include "inftrees.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* generate initialization table for an inflate_huft structure array */ +void maketree(uInt b, inflate_huft *t) +{ + int i, e; + + i = 0; + while (1) + { + e = t[i].exop; + if (e && (e & (16+64)) == 0) /* table pointer */ + { + fprintf(stderr, "maketree: cannot initialize sub-tables!\n"); + exit(1); + } + if (i % 4 == 0) + printf("\n "); + printf(" {{{%u,%u}},%u}", t[i].exop, t[i].bits, t[i].base); + if (++i == (1< +#include "zlib.h" + +#ifdef STDC +# include +# include +#else + extern void exit OF((int)); +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + int len = strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [-f] [-h] [-1 to -9] [files...] + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + char outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + argc--, argv++; + + while (argc > 0) { + if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv, outmode); + } + } while (argv++, --argc); + } + exit(0); + return 0; /* to avoid warning */ +} diff --git a/cfe/cfe/zlib/trees.c b/cfe/cfe/zlib/trees.c new file mode 100644 index 0000000..b37335b --- /dev/null +++ b/cfe/cfe/zlib/trees.c @@ -0,0 +1,1214 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-1998 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +#define MAX(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/cfe/cfe/zlib/trees.h b/cfe/cfe/zlib/trees.h new file mode 100644 index 0000000..72facf9 --- /dev/null +++ b/cfe/cfe/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/cfe/cfe/zlib/uncompr.c b/cfe/cfe/zlib/uncompr.c new file mode 100644 index 0000000..eab3f5b --- /dev/null +++ b/cfe/cfe/zlib/uncompr.c @@ -0,0 +1,58 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/cfe/cfe/zlib/zconf.h b/cfe/cfe/zlib/zconf.h new file mode 100644 index 0000000..23a52b3 --- /dev/null +++ b/cfe/cfe/zlib/zconf.h @@ -0,0 +1,279 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Old Borland C incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# if defined(STDC) || defined(_CFE_) +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR _far +# endif +#endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include +# define ZEXPORT __declspec(dllexport) WINAPI +# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT _export +# define ZEXPORTVA _export +# endif +# endif +# endif +#endif + +#if defined (__BEOS__) +# if defined (ZLIB_DLL) +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +#endif + +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(MACOS) && !defined(TARGET_OS_MAC) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") +#endif + +#endif /* _ZCONF_H */ diff --git a/cfe/cfe/zlib/zlib.3 b/cfe/cfe/zlib/zlib.3 new file mode 100644 index 0000000..25c8495 --- /dev/null +++ b/cfe/cfe/zlib/zlib.3 @@ -0,0 +1,107 @@ +.TH ZLIB 3 "9 July 1998" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms will be added later and will have the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +(for example if an input file is mmap'ed), +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.I gzip +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. The decoder checks +the consistency of the compressed data, so the library should never +crash even in case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h. +The distribution source includes examples of use of the library +the files +.I example.c +and +.IR minigzip.c . +.LP +A Java implementation of +.IR zlib +is available in the Java Development Kit 1.1 +.IP +http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmarquess@bfsec.bt.co.uk) +is available at CPAN (Comprehensive Perl Archive Network) sites, +such as: +.IP +ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib* +.LP +A Python interface to +.IR zlib +written by A.M. Kuchling +is available from the Python Software Association sites, such as: +.IP +ftp://ftp.python.org/pub/python/contrib/Encoding/zlib*.tar.gz +.SH "SEE ALSO" +Questions about zlib should be sent to: +.IP +zlib@quest.jpl.nasa.gov +or, if this fails, to the author addresses given below. +The zlib home page is: +.IP +http://www.cdrom.com/pub/infozip/zlib/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +ftp://ds.internic.net/rfc/rfc1950.txt (zlib format) +.br +rfc1951.txt (deflate format) +.br +rfc1952.txt (gzip format) +.LP +These documents are also available in other formats from: +.IP +ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html +.SH AUTHORS +Version 1.1.3 +Copyright (C) 1995-1998 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/cfe/cfe/zlib/zlib.h b/cfe/cfe/zlib/zlib.h new file mode 100644 index 0000000..49f56b4 --- /dev/null +++ b/cfe/cfe/zlib/zlib.h @@ -0,0 +1,893 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */ diff --git a/cfe/cfe/zlib/zutil.c b/cfe/cfe/zlib/zutil.c new file mode 100644 index 0000000..52a8197 --- /dev/null +++ b/cfe/cfe/zlib/zutil.c @@ -0,0 +1,225 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/cfe/cfe/zlib/zutil.h b/cfe/cfe/zlib/zutil.h new file mode 100644 index 0000000..6dc18e1 --- /dev/null +++ b/cfe/cfe/zlib/zutil.h @@ -0,0 +1,220 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2001/11/09 01:48:02 mpl Exp $ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# define fdopen(fd,type) _fdopen(fd,type) +#endif + + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, + uInt len)); +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ diff --git a/cfe/docs/cfe.pdf b/cfe/docs/cfe.pdf new file mode 100755 index 0000000..ae668a1 Binary files /dev/null and b/cfe/docs/cfe.pdf differ -- cgit v1.2.3